CnC_Remastered_Collection

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

ANIM.CPP (60712B)


      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: /CounterStrike/ANIM.CPP 1     3/03/97 10:24a 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 : Dune                                                         *
     22  *                                                                                             *
     23  *                    File Name : ANIM.CPP                                                     *
     24  *                                                                                             *
     25  *                   Programmer : Joe L. Bostic                                                *
     26  *                                                                                             *
     27  *                   Start Date : June 3, 1991                                                 *
     28  *                                                                                             *
     29  *---------------------------------------------------------------------------------------------*
     30  * Functions:                                                                                  *
     31  *   AnimClass::AI -- This is the low level anim processor.                                    *
     32  *   AnimClass::AnimClass -- The constructor for animation objects.                            *
     33  *   AnimClass::Attach_To -- Attaches animation to object specified.                           *
     34  *   AnimClass::Sort_Above -- Sorts the animation above the target specified.                  *
     35  *   AnimClass::Center_Coord -- Determine center of animation.                                 *
     36  *   AnimClass::Detach -- Remove animation if attached to target.                              *
     37  *   AnimClass::Do_Atom_Damage -- Do atom bomb damage centered around the cell specified.      *
     38  *   AnimClass::Draw_It -- Draws the animation at the location specified.                      *
     39  *   AnimClass::In_Which_Layer -- Determines what render layer the anim should be in.          *
     40  *   AnimClass::Init -- Performs pre-scenario initialization.                                  *
     41  *   AnimClass::Mark -- Signals to map that redrawing is necessary.                            *
     42  *   AnimClass::Middle -- Processes any middle events.                                         *
     43  *   AnimClass::Occupy_List -- Determines the occupy list for the animation.                   *
     44  *   AnimClass::Overlap_List -- Determines the overlap list for the animation.                 *
     45  *   AnimClass::Render -- Draws an animation object.                                           *
     46  *   AnimClass::Sort_Y -- Returns with the sorting coordinate for the animation.               *
     47  *   AnimClass::Start -- Processes initial animation side effects.                             *
     48  *   AnimClass::delete -- Returns an anim object back to the free pool.                        *
     49  *   AnimClass::new -- Allocates an anim object from the pool.                                 *
     50  *   AnimClass::~AnimClass -- Destructor for anim objects.                                     *
     51  *   Anim_From_Name -- Given a name, this finds the corresponding anim type.                   *
     52  *   Shorten_Attached_Anims -- Reduces attached animation durations.                           *
     53  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     54 
     55 #include	"function.h"
     56 #define   VIC   1
     57 
     58 /***********************************************************************************************
     59  * Anim_From_Name -- Given a name, this finds the corresponding anim type.                     *
     60  *                                                                                             *
     61  *    This routine will convert the supplied ASCII name into the animation type that it        *
     62  *    represents.                                                                              *
     63  *                                                                                             *
     64  * INPUT:   name  -- Pointer to the ASCII name to convert.                                     *
     65  *                                                                                             *
     66  * OUTPUT:  Returns with the animation type that matches the name specified. If no match could *
     67  *          be found, then ANIM_NONE is returned.                                              *
     68  *                                                                                             *
     69  * WARNINGS:   none                                                                            *
     70  *                                                                                             *
     71  * HISTORY:                                                                                    *
     72  *   07/06/1996 JLB : Created.                                                                 *
     73  *=============================================================================================*/
     74 AnimType Anim_From_Name(char const * name)
     75 {
     76   #ifdef VIC
     77 	if (name == NULL) return(ANIM_NONE);
     78 
     79 	for (int anim = ANIM_FIRST; anim < ANIM_COUNT; anim++) {
     80 		if (stricmp(AnimTypeClass::As_Reference((AnimType)anim).IniName, name) == 0) {
     81 			return((AnimType)anim);
     82 		}
     83 	}
     84 #endif
     85 	return(ANIM_NONE);
     86 }
     87 
     88 
     89 /***********************************************************************************************
     90  * Shorten_Attached_Anims -- Reduces attached animation durations.                             *
     91  *                                                                                             *
     92  *    This routine is used to reduce the amount of time any attached animations will process.  *
     93  *    Typical use of this is when an object is on fire and the object should now be destroyed  *
     94  *    but the attached animations are to run until completion before destruction can follow.   *
     95  *    This routine will make the animation appear to run its course, but in as short of time   *
     96  *    as possible. The shortening effect is achieved by reducing the number of times the       *
     97  *    animation will loop.                                                                     *
     98  *                                                                                             *
     99  * INPUT:   obj   -- Pointer to the object that all attached animations will be processed.     *
    100  *                                                                                             *
    101  * OUTPUT:  none                                                                               *
    102  *                                                                                             *
    103  * WARNINGS:   none                                                                            *
    104  *                                                                                             *
    105  * HISTORY:                                                                                    *
    106  *   12/11/1994 JLB : Created.                                                                 *
    107  *=============================================================================================*/
    108 void Shorten_Attached_Anims(ObjectClass * obj)
    109 {
    110 	if (obj != NULL) {
    111 		for (int index = 0; index < Anims.Count(); index++) {
    112 			AnimClass & anim = * Anims.Ptr(index);
    113 
    114 			if (As_Object(anim.xObject) == obj) {
    115 				anim.Loops = 0;
    116 			}
    117 		}
    118 	}
    119 }
    120 
    121 
    122 /***********************************************************************************************
    123  * AnimClass::Sort_Y -- Returns with the sorting coordinate for the animation.                 *
    124  *                                                                                             *
    125  *    This routine is used by the sorting system. Animations that are located in the ground    *
    126  *    layer will be sorted by this the value returned from this function.                      *
    127  *                                                                                             *
    128  * INPUT:   none                                                                               *
    129  *                                                                                             *
    130  * OUTPUT:  Returns with the sort coordinate to use for this animation.                        *
    131  *                                                                                             *
    132  * WARNINGS:   none                                                                            *
    133  *                                                                                             *
    134  * HISTORY:                                                                                    *
    135  *   10/17/1994 JLB : Created.                                                                 *
    136  *   12/15/1994 JLB : Handles flat anims (infantry decay anims).                               *
    137  *=============================================================================================*/
    138 COORDINATE AnimClass::Sort_Y(void) const
    139 {
    140 #ifdef VIC
    141 	assert(Anims.ID(this) == ID);
    142 	assert(IsActive);
    143 
    144 	if (xObject != TARGET_NONE) {
    145 		return(Coord_Add(As_Object(xObject)->Sort_Y(), 0x00010000L));
    146 	}
    147 	if (Target_Legal(SortTarget)) {
    148 		ObjectClass * obj = As_Object(SortTarget);
    149 		if (obj && obj->IsActive) {
    150 			return(Coord_Add(obj->Sort_Y(), 0x00010000L));
    151 		}
    152 	}
    153 	if (*this == ANIM_MOVE_FLASH) {
    154 		return(Coord_Add(Center_Coord(), XYP_COORD(0, -24)));
    155 	}
    156 	if (Class->IsGroundLayer || *this == ANIM_LZ_SMOKE) {
    157 		return(Coord_Add(Center_Coord(), XYP_COORD(0, 14)));
    158 	}
    159 #endif
    160 	return(Coord);
    161 }
    162 
    163 
    164 /***********************************************************************************************
    165  * AnimClass::Center_Coord -- Determine center of animation.                                   *
    166  *                                                                                             *
    167  *    This support function will return the "center" of the animation. The actual coordinate   *
    168  *    of the animation may be dependant on if the the animation is attached to an object.      *
    169  *    In such a case, it must factor in the object's location.                                 *
    170  *                                                                                             *
    171  * INPUT:   none                                                                               *
    172  *                                                                                             *
    173  * OUTPUT:  Returns the coordinate of the center of the animation. The coordinate is in real   *
    174  *          game coordinates -- taking into consideration if the animation is attached.        *
    175  *                                                                                             *
    176  * WARNINGS:   none                                                                            *
    177  *                                                                                             *
    178  * HISTORY:                                                                                    *
    179  *   09/19/1994 JLB : Created.                                                                 *
    180  *   02/02/1996 JLB : Coordinate based on visual center of object.                             *
    181  *=============================================================================================*/
    182 COORDINATE AnimClass::Center_Coord(void) const
    183 {
    184 #ifdef VIC
    185 	assert(Anims.ID(this) == ID);
    186 	assert(IsActive);
    187 
    188 	if (xObject != TARGET_NONE) {
    189 		return(Coord_Add(Coord, As_Object(xObject)->Target_Coord()));
    190 	}
    191 #endif
    192 	return(Coord);
    193 }
    194 
    195 
    196 /***********************************************************************************************
    197  * AnimClass::Render -- Draws an animation object.                                             *
    198  *                                                                                             *
    199  *    This is the working routine that renders the animation shape. It gets called once        *
    200  *    per animation per frame. It needs to be fast.                                            *
    201  *                                                                                             *
    202  * INPUT:   bool; Should the animation be rendered in spite of render flag?                    *
    203  *                                                                                             *
    204  * OUTPUT:  bool; Was the animation rendered?                                                  *
    205  *                                                                                             *
    206  * WARNINGS:   none                                                                            *
    207  *                                                                                             *
    208  * HISTORY:                                                                                    *
    209  *   05/31/1994 JLB : Created.                                                                 *
    210  *=============================================================================================*/
    211 bool AnimClass::Render(bool forced) const
    212 {
    213 #ifdef VIC
    214 	assert(Anims.ID(this) == ID);
    215 	assert(IsActive);
    216 
    217 	if (Delay) return(false);
    218 	if (Map[Center_Coord()].IsVisible) {
    219 		const_cast<AnimClass*>(this)->IsToDisplay = true;	// const_cast. ST - 5/8/2019
    220 	}
    221 #endif
    222 	return(ObjectClass::Render(forced));
    223 }
    224 
    225 
    226 /***********************************************************************************************
    227  * AnimClass::Draw_It -- Draws the animation at the location specified.                        *
    228  *                                                                                             *
    229  *    This routine is used to render the animation object at the location specified. This is   *
    230  *    how the map imagery gets updated.                                                        *
    231  *                                                                                             *
    232  * INPUT:   x,y      -- The pixel coordinates to draw the animation at.                        *
    233  *                                                                                             *
    234  *          window   -- The to base the draw coordinates upon.                                 *
    235  *                                                                                             *
    236  * OUTPUT:  none                                                                               *
    237  *                                                                                             *
    238  * WARNINGS:   none                                                                            *
    239  *                                                                                             *
    240  * HISTORY:                                                                                    *
    241  *   09/24/1994 JLB : Created.                                                                 *
    242  *   05/19/1995 JLB : Added white translucent effect.                                          *
    243  *=============================================================================================*/
    244 void AnimClass::Draw_It(int x, int y, WindowNumberType window) const
    245 {
    246 #ifdef VIC
    247 	assert(Anims.ID(this) == ID);
    248 	assert(IsActive);
    249 
    250 	bool render_legacy = !IsInvisible && (Class->VirtualAnim == ANIM_NONE || window != WINDOW_VIRTUAL);
    251 	bool render_virtual = Target_Legal(VirtualAnimTarget) && window == WINDOW_VIRTUAL;
    252 
    253 	if (render_legacy) {
    254 		BStart(BENCH_ANIMS);
    255 
    256 		IsTheaterShape = Class->IsTheater;
    257 
    258 		void const * shapefile = Get_Image_Data();
    259 		if (shapefile != NULL) {
    260 			void const * transtable = NULL;
    261 			int shapenum = Class->Start + Fetch_Stage();
    262 			void const * remap = NULL;
    263 			ShapeFlags_Type flags = SHAPE_CENTER|SHAPE_WIN_REL;
    264 			bool alt = false;
    265 			int width = 0;
    266 			int height = 0;
    267 
    268 			/*
    269 			**	Some animations require special fixups.
    270 			*/
    271 			switch (Class->Type) {
    272 				case ANIM_ATOM_BLAST:
    273 					transtable = Map.UnitShadow;
    274 					break;
    275 
    276 				case ANIM_FLAG:
    277 					x += (ICON_PIXEL_W / 2) - 2;
    278 					y += (3 * ICON_PIXEL_H / 4) - Get_Build_Frame_Height(shapefile);
    279 					transtable = Map.UnitShadow;
    280 					alt = true;
    281 					break;
    282 
    283 				case ANIM_BEACON_VIRTUAL:
    284 					width = 29;
    285 					height = 39;
    286 					flags = flags | SHAPE_BOTTOM | SHAPE_COMPACT;
    287 					break;
    288 			}
    289 
    290 			/*
    291 			**	If the translucent table hasn't been determined yet, then check to see if it
    292 			**	should use the white or normal translucent tables.
    293 			*/
    294 			if (transtable == NULL && Class->IsWhiteTrans) transtable = DisplayClass::WhiteTranslucentTable;
    295 			if (transtable == NULL && Class->IsTranslucent) transtable = DisplayClass::TranslucentTable;
    296 
    297 			/*
    298 			**	Set the shape flags to properly take into account any fading or ghosting
    299 			**	table necessary.
    300 			*/
    301 			if (alt) {
    302 				flags = flags | SHAPE_FADING;
    303 				if (OwnerHouse != HOUSE_NONE) {
    304 					remap = HouseClass::As_Pointer(OwnerHouse)->Remap_Table(false);
    305 				} else {
    306 					remap = ColorRemaps[PCOLOR_GOLD].RemapTable;
    307 				}
    308 			}
    309 			if (transtable != NULL) flags = flags | SHAPE_GHOST;
    310 
    311 			/*
    312 			**	Draw the animation shape, but ignore legacy if beyond normal stage count.
    313 			*/
    314 			if ((window == WINDOW_VIRTUAL) || (Fetch_Stage() < Class->Stages)) {
    315 				// Add 'this' parameter to call new shape draw intercept. ST - 5/22/2019
    316 				CC_Draw_Shape(this, shapefile, shapenum, x, y, window, flags, remap, transtable, DIR_N, Class->VirtualScale, width, height);
    317 			}
    318 		}
    319 		IsTheaterShape = false;
    320 		BEnd(BENCH_ANIMS);
    321 	}
    322 	if (render_virtual) {
    323 		AnimClass* virtual_anim = As_Animation(VirtualAnimTarget);
    324 		virtual_anim->Make_Visible();
    325 		virtual_anim->Draw_It(x, y, window);
    326 		virtual_anim->Make_Invisible();
    327 	}
    328 #endif
    329 }
    330 
    331 
    332 /***********************************************************************************************
    333  * AnimClass::Mark -- Signals to map that redrawing is necessary.                              *
    334  *                                                                                             *
    335  *    This routine is used by the animation logic system to inform the map that the cells      *
    336  *    under the animation must be rerendered.                                                  *
    337  *                                                                                             *
    338  * INPUT:                                                                                      *
    339  *                                                                                             *
    340  * OUTPUT:  none                                                                               *
    341  *                                                                                             *
    342  * WARNINGS:   none                                                                            *
    343  *                                                                                             *
    344  * HISTORY:                                                                                    *
    345  *   05/31/1994 JLB : Created.                                                                 *
    346  *=============================================================================================*/
    347 bool AnimClass::Mark(MarkType mark)
    348 {
    349 #ifdef VIC
    350 	assert(Anims.ID(this) == ID);
    351 	assert(IsActive);
    352 
    353 	if (ObjectClass::Mark(mark)) {
    354 		Map.Refresh_Cells(Coord_Cell(Center_Coord()), Overlap_List());
    355 //		ObjectClass::Mark(mark);
    356 		return(true);
    357 	}
    358 #endif
    359 	return(false);
    360 }
    361 
    362 
    363 /***********************************************************************************************
    364  * AnimClass::Overlap_List -- Determines the overlap list for the animation.                   *
    365  *                                                                                             *
    366  *    Use this routine to fetch the overlap list for the animation. This overlap list is the   *
    367  *    cells that this animation spills over.                                                   *
    368  *                                                                                             *
    369  * INPUT:   none                                                                               *
    370  *                                                                                             *
    371  * OUTPUT:  Returns a pointer to the overlap list for this particular instance of the          *
    372  *          animation.                                                                         *
    373  *                                                                                             *
    374  * WARNINGS:   none                                                                            *
    375  *                                                                                             *
    376  * HISTORY:                                                                                    *
    377  *   03/19/1995 JLB : Created.                                                                 *
    378  *=============================================================================================*/
    379 short const * AnimClass::Overlap_List(void) const
    380 {
    381 #ifdef VIC
    382 	assert(Anims.ID(this) == ID);
    383 	assert(IsActive);
    384 	static short const OverlapAtom[] = {
    385 		(-MAP_CELL_W * 2) - 1, (-MAP_CELL_W * 2), (-MAP_CELL_W * 2) + 1,
    386 		(-MAP_CELL_W * 1) - 1, (-MAP_CELL_W * 1), (-MAP_CELL_W * 1) + 1,
    387 		(-MAP_CELL_W * 0) - 1, (-MAP_CELL_W * 0), (-MAP_CELL_W * 0) + 1,
    388 		( MAP_CELL_W * 1) - 1, ( MAP_CELL_W * 1), ( MAP_CELL_W * 1) + 1,
    389 		( MAP_CELL_W * 2) - 1, ( MAP_CELL_W * 2), ( MAP_CELL_W * 2) + 1,
    390  		REFRESH_EOL
    391 	};
    392 	static short const OverlapFlag[] = { 0, 1, -MAP_CELL_W, -(MAP_CELL_W-1), MAP_CELL_W, MAP_CELL_W+1, REFRESH_EOL };
    393 
    394 	if (IsToDelete) {
    395 		static short const _list[] = {REFRESH_EOL};
    396 		return(_list);
    397 	}
    398 
    399 	if (Class->Type == ANIM_ATOM_BLAST) {
    400 		return(OverlapAtom);
    401 	}
    402 
    403 	if (Class->Type == ANIM_FLAG) {
    404 		return(OverlapFlag);
    405 	}
    406 
    407 #ifdef PARTIAL
    408 IsTheaterShape = Class->IsTheater;
    409 	if (Class->Get_Image_Data() != NULL) {
    410 		int shapenum = Class->Start + Fetch_Stage();
    411 		int count = Get_Build_Frame_Count(Class->Get_Image_Data());
    412 		shapenum = min(shapenum, count-1);
    413 
    414 		if (Class->DimensionData == NULL) {
    415 			Class->DimensionData = new Rect [count];
    416 		}
    417 		if (Class->DimensionData != NULL && !Class->DimensionData[shapenum].Is_Valid()) {
    418 			Class->DimensionData[shapenum] = Shape_Dimensions(Class->Get_Image_Data(), shapenum);
    419 IsTheaterShape = false;
    420 			return(Coord_Spillage_List(Center_Coord(), Class->DimensionData[shapenum]));
    421 		}
    422 	}
    423 IsTheaterShape = false;
    424 #endif
    425 #endif
    426 	return(Coord_Spillage_List(Center_Coord(), Class->Size));
    427 }
    428 
    429 
    430 /***********************************************************************************************
    431  * AnimClass::Occupy_List -- Determines the occupy list for the animation.                     *
    432  *                                                                                             *
    433  *    Animations always occupy only the cell that their center is located over. As such, this  *
    434  *    routine always returns a simple (center cell) occupation list.                           *
    435  *                                                                                             *
    436  * INPUT:   none                                                                               *
    437  *                                                                                             *
    438  * OUTPUT:  Returns with the occupation list for the animation.                                *
    439  *                                                                                             *
    440  * WARNINGS:   none                                                                            *
    441  *                                                                                             *
    442  * HISTORY:                                                                                    *
    443  *   03/19/1995 JLB : Created.                                                                 *
    444  *=============================================================================================*/
    445 short const * AnimClass::Occupy_List(bool) const
    446 {
    447 #ifdef VIC
    448 	assert(Anims.ID(this) == ID);
    449 	assert(IsActive);
    450 
    451 	static short _simple[] = {REFRESH_EOL};
    452 
    453 #endif
    454 	return(_simple);
    455 }
    456 
    457 
    458 /***********************************************************************************************
    459  * AnimClass::Init -- Performs pre-scenario initialization.                                    *
    460  *                                                                                             *
    461  *    This routine is used to initialize the animation system prior to a scenario being loaded *
    462  *    or reloaded. It effectively removes all animations from the system.                      *
    463  *                                                                                             *
    464  * INPUT:   none                                                                               *
    465  *                                                                                             *
    466  * OUTPUT:  none                                                                               *
    467  *                                                                                             *
    468  * WARNINGS:   none                                                                            *
    469  *                                                                                             *
    470  * HISTORY:                                                                                    *
    471  *   05/31/1994 JLB : Created.                                                                 *
    472  *=============================================================================================*/
    473 void AnimClass::Init(void)
    474 {
    475 	Anims.Free_All();
    476 }
    477 
    478 
    479 /***********************************************************************************************
    480  * AnimClass::new -- Allocates an anim object from the pool.                                   *
    481  *                                                                                             *
    482  *    This routine is used to allocate a free anim class object from the preallocated pool     *
    483  *    in the near heap. If there are no free animation objects, then null is returned.         *
    484  *                                                                                             *
    485  * INPUT:   none                                                                               *
    486  *                                                                                             *
    487  * OUTPUT:  Returns with a pointer to a free anim object.                                      *
    488  *                                                                                             *
    489  * WARNINGS:   none                                                                            *
    490  *                                                                                             *
    491  * HISTORY:                                                                                    *
    492  *   05/31/1994 JLB : Created.                                                                 *
    493  *=============================================================================================*/
    494 void * AnimClass::operator new(size_t)
    495 {
    496 	void * ptr = Anims.Allocate();
    497 	if (ptr != NULL) {
    498 		((AnimClass *)ptr)->Set_Active();
    499 	} else {
    500 		GlyphX_Debug_Print("AnimClass::operator new FAILED");
    501 	}
    502 	return(ptr);
    503 }
    504 
    505 
    506 /***********************************************************************************************
    507  * AnimClass::delete -- Returns an anim object back to the free pool.                          *
    508  *                                                                                             *
    509  *    This routine is used to return an anim object back to the pool of free anim objects.     *
    510  *    Anim objects so returned are available to be reallocated for the next animation.         *
    511  *                                                                                             *
    512  * INPUT:   ptr   -- Pointer to the anim object to return to the pool.                         *
    513  *                                                                                             *
    514  * OUTPUT:  none                                                                               *
    515  *                                                                                             *
    516  * WARNINGS:   none                                                                            *
    517  *                                                                                             *
    518  * HISTORY:                                                                                    *
    519  *   05/31/1994 JLB : Created.                                                                 *
    520  *=============================================================================================*/
    521 void AnimClass::operator delete(void * ptr)
    522 {
    523 	if (ptr != NULL) {
    524 		((AnimClass *)ptr)->IsActive = false;
    525 	}
    526 	Anims.Free((AnimClass *)ptr);
    527 }
    528 
    529 
    530 /***********************************************************************************************
    531  * AnimClass::AnimClass -- The constructor for animation objects.                              *
    532  *                                                                                             *
    533  *    This routine is used as the constructor of animation objects. It initializes and adds    *
    534  *    the animation object to the display and logic systems.                                   *
    535  *                                                                                             *
    536  * INPUT:   animnum  -- The animation number to start.                                         *
    537  *                                                                                             *
    538  *          coord    -- The location of the animation.                                         *
    539  *                                                                                             *
    540  *          timedelay-- The delay before the animation starts.                                 *
    541  *                                                                                             *
    542  *          loop     -- The number of times to loop this animation.                            *
    543  *                                                                                             *
    544  * OUTPUT:  none                                                                               *
    545  *                                                                                             *
    546  * WARNINGS:   none                                                                            *
    547  *                                                                                             *
    548  * HISTORY:                                                                                    *
    549  *   05/31/1994 JLB : Created.                                                                 *
    550  *   08/03/1994 JLB : Added a delayed affect parameter.                                        *
    551  *=============================================================================================*/
    552 AnimClass::AnimClass(AnimType animnum, COORDINATE coord, unsigned char timedelay, char loop) :
    553 	ObjectClass(RTTI_ANIM, Anims.ID(this)),
    554 	Class(AnimTypes.Ptr((int)animnum)),
    555 	xObject(TARGET_NONE),
    556 	SortTarget(TARGET_NONE),
    557 	OwnerHouse(HOUSE_NONE),
    558 	Loops(1),
    559 	IsToDelete(false),
    560 	IsBrandNew(true),
    561 	IsInvisible(false),
    562 	Delay(timedelay),
    563 	Accum(0),
    564 	AttachLayer(LAYER_NONE),
    565 	KillTime(0ULL)
    566 {
    567 #ifdef VIC
    568 	if (Class->Stages == -1) {
    569 IsTheaterShape = Class->IsTheater;
    570 		((int&)Class->Stages) = Get_Build_Frame_Count(Class->Get_Image_Data());
    571 IsTheaterShape = false;
    572 
    573 	}
    574 	if (Class->LoopEnd == -1) {
    575 		((int&)Class->LoopEnd) = Class->Stages;
    576 	}
    577 	if (Class->IsNormalized) {
    578 		Set_Rate(Options.Normalize_Delay(Class->Delay));
    579 	} else {
    580 		Set_Rate(Class->Delay);
    581 	}
    582 	Set_Stage(0);
    583 
    584 	if (Class->IsGroundLayer) {
    585 		Height = FLIGHT_LEVEL;
    586 	}
    587 
    588 	AnimClass::Unlimbo(coord);
    589 
    590 	VisibleFlags = static_cast<unsigned int>(-1);
    591 
    592 	/*
    593 	**	Drop zone smoke always reveals the map around itself.
    594 	*/
    595 	if (*this == ANIM_LZ_SMOKE) {
    596 		// Added PlayerPtr here as Sight_From now needs to know who to perform the action for. This should be OK as long as it's not used in MP. ST - 8/2/2019 2:34PM
    597 		Map.Sight_From(Coord_Cell(coord), Rule.DropZoneRadius / CELL_LEPTON_W, PlayerPtr, false);
    598 	}
    599 
    600 	if (Class->Loops >= 0) {
    601 		Loops = (char)(max(loop, 1) * Class->Loops);
    602 		Loops = (char)max(Loops, 1);
    603 	} else {
    604 		Loops = Class->Loops;
    605 	}
    606 
    607 	/*
    608 	**	If the animation starts immediately, then play the associated sound effect now.
    609 	*/
    610 	if (!Delay) {
    611 		Start();
    612 	}
    613 
    614 	/*
    615 	**	Check for a virtual animation
    616 	*/
    617 	if (Class->VirtualAnim != ANIM_NONE) {
    618 		AnimClass* virtual_anim = new AnimClass(Class->VirtualAnim, Coord, timedelay, loop);
    619 		if (virtual_anim != NULL) {
    620 			virtual_anim->Make_Invisible();
    621 			VirtualAnimTarget = virtual_anim->As_Target();
    622 		} else {
    623 			VirtualAnimTarget = TARGET_NONE;
    624 		}
    625 	} else {
    626 		VirtualAnimTarget = TARGET_NONE;
    627 	}
    628 #endif
    629 }
    630 
    631 
    632 /***********************************************************************************************
    633  * AnimClass::~AnimClass -- Destructor for anim objects.                                       *
    634  *                                                                                             *
    635  *    This destructor handles removing the animation object from the system. It might require  *
    636  *    informing any object this animation is attached to that it is no longer attached.        *
    637  *                                                                                             *
    638  * INPUT:   none                                                                               *
    639  *                                                                                             *
    640  * OUTPUT:  none                                                                               *
    641  *                                                                                             *
    642  * WARNINGS:   none                                                                            *
    643  *                                                                                             *
    644  * HISTORY:                                                                                    *
    645  *   11/29/1994 JLB : Created.                                                                 *
    646  *=============================================================================================*/
    647 AnimClass::~AnimClass(void)
    648 {
    649 #ifdef VIC
    650 	assert(Anims.ID(this) == ID);
    651 	assert(IsActive);
    652 	if (GameActive) {
    653 
    654 		/*
    655 		**	If this anim is attached to another object
    656 		**	then check to see if this is the last anim attached to it. If this
    657 		**	is the case, then inform the object that it is no longer attached to
    658 		**	an animation.
    659 		*/
    660 		if (Target_Legal(xObject) && As_Object(xObject) != NULL) {
    661 			ObjectClass * to = As_Object(xObject);
    662 
    663 			/*
    664 			**	Remove the object from the appropriate display list.
    665 			*/
    666 			Map.Remove(this, In_Which_Layer());
    667 
    668 			/*
    669 			**	Scan for any other animations that are attached to the object that
    670 			**	this animation is attached to. If there are no others, then inform the
    671 			**	attached object of this fact.
    672 			*/
    673 			int index;
    674 			for (index = 0; index < Anims.Count(); index++) {
    675 				if (Anims.Ptr(index) != this && Anims.Ptr(index)->xObject == xObject) break;
    676 			}
    677 
    678 			/*
    679 			**	Tell the object that it is no longer being damaged.
    680 			*/
    681 			if (index == Anims.Count()) {
    682 				to->Fire_Out();
    683 				if (to->In_Which_Layer() == LAYER_GROUND) to->Mark(MARK_OVERLAP_UP);
    684 				to->IsAnimAttached = false;
    685 				if (to->In_Which_Layer() == LAYER_GROUND) to->Mark(MARK_OVERLAP_DOWN);
    686 			}
    687 			Coord = Coord_Add(to->Center_Coord(), Coord);
    688 			xObject = TARGET_NONE;
    689 		}
    690 
    691 		Limbo();
    692 	}
    693 
    694 	xObject = TARGET_NONE;
    695 	Class = 0;
    696 	ID = -1;
    697 
    698 #endif
    699 }
    700 
    701 
    702 /***********************************************************************************************
    703  * AnimClass::AI -- This is the low level anim processor.                                      *
    704  *                                                                                             *
    705  *    This routine is called once per frame per animation. It handles transition between       *
    706  *    animation frames and marks the map for redraw as necessary.                              *
    707  *                                                                                             *
    708  * INPUT:   none                                                                               *
    709  *                                                                                             *
    710  * OUTPUT:  none                                                                               *
    711  *                                                                                             *
    712  * WARNINGS:   Speed is of upmost importance.                                                  *
    713  *                                                                                             *
    714  * HISTORY:                                                                                    *
    715  *   05/31/1994 JLB : Created.                                                                 *
    716  *=============================================================================================*/
    717 void AnimClass::AI(void)
    718 {
    719 #ifdef VIC
    720 	assert(Anims.ID(this) == ID);
    721 	assert(IsActive);
    722 
    723 	/*
    724 	**	For ground level based animations (ones that can run slowly as well as
    725 	**	occur behind other ground objects) always cause the cell to be redrawn.
    726 	*/
    727 #ifdef PARTIAL
    728 	if (!Delay && Class->IsGroundLayer) {
    729 		Map.Refresh_Cells(Coord_Cell(Center_Coord()), Overlap_List());
    730 	}
    731 #else
    732 	Map.Refresh_Cells(Coord_Cell(Center_Coord()), Overlap_List());
    733 #endif
    734 
    735 	/*
    736 	**	Special case check to make sure that building on top of a smoke marker
    737 	**	causes the smoke marker to vanish.
    738 	*/
    739 	if (Class->Type == ANIM_LZ_SMOKE && Map[Center_Coord()].Cell_Building()) {
    740 		IsToDelete = true;
    741 	}
    742 
    743 	/*
    744 	**	Don't allow corpses on rocks, rivers, and water (looks really weird).
    745 	*/
    746 	if (Class->Type >= ANIM_CORPSE1 && Class->Type <= ANIM_CORPSE3) {
    747 		LandType land = Map[Center_Coord()].Land_Type();
    748 		if (land == LAND_ROCK || land == LAND_WATER || land == LAND_RIVER) {
    749 			IsToDelete = true;
    750 		}
    751 	}
    752 
    753 	/*
    754 	**	Check the kill time.
    755 	*/
    756 	if (KillTime > 0ULL) {
    757 		FILETIME ft;
    758 		GetSystemTimeAsFileTime(&ft);
    759 
    760 		unsigned long long now = (unsigned long long)ft.dwLowDateTime + ((unsigned long long)ft.dwHighDateTime << 32ULL);
    761 		if (now >= KillTime) {
    762 			IsToDelete = true;
    763 		}
    764 	}
    765 
    766 	/*
    767 	**	Delete this animation and bail early if the animation is flagged to be deleted
    768 	**	immediately.
    769 	*/
    770 	if (IsToDelete) {
    771 		delete this;
    772 		return;
    773 	}
    774 
    775 	/*
    776 	**	If this is a brand new animation, then don't process it the first logic pass
    777 	**	since it might end up skipping the first animation frame before it has had a
    778 	**	chance to draw it.
    779 	*/
    780 	if (IsBrandNew) {
    781 		IsBrandNew = false;
    782 		return;
    783 	}
    784 
    785 #ifdef FIXIT_MULTI_SAVE
    786 	if (Class->Stages == -1) {
    787 		IsTheaterShape = Class->IsTheater;
    788 		((int&)Class->Stages) = Get_Build_Frame_Count(Class->Get_Image_Data());
    789 		IsTheaterShape = false;
    790 	}
    791 	if (Class->LoopEnd == -1) {
    792 		((int&)Class->LoopEnd) = Class->Stages;
    793 	}
    794 #endif
    795 
    796 	if (Delay) {
    797 		Delay--;
    798 		if (!Delay) {
    799 			Start();
    800 		}
    801 	} else {
    802 
    803 #ifdef FIXIT_MULTI_SAVE
    804 		if (Class->Stages == -1) {
    805 			IsTheaterShape = Class->IsTheater;
    806 			((int&)Class->Stages) = Get_Build_Frame_Count(Class->Get_Image_Data());
    807 			IsTheaterShape = false;
    808 		}
    809 		if (Class->LoopEnd == -1) {
    810 			((int&)Class->LoopEnd) = Class->Stages;
    811 		}
    812 #endif
    813 
    814 		/*
    815 		**	This is necessary because there is no recording of animations on the map
    816 		**	and thus the animation cannot be intelligently flagged for redraw. Most
    817 		**	animations move fast enough that they would need to be redrawn every
    818 		**	game frame anyway so this isn't TOO bad.
    819 		*/
    820 		Mark(MARK_CHANGE);
    821 
    822 		if (StageClass::Graphic_Logic()) {
    823 			int stage = Fetch_Stage();
    824 
    825 			/*
    826 			**	If this animation is attached to another object and it is a
    827 			**	damaging kind of animation, then do the damage to the other
    828 			**	object.
    829 			*/
    830 			if (xObject != TARGET_NONE && Class->Damage > 0 && stage < Class->Stages) {
    831 				Accum += Class->Damage;
    832 
    833 				if (Accum >= 1) {
    834 
    835 					/*
    836 					**	Administer the damage. If the object was destroyed by this anim,
    837 					**	then the attached damaging anim is also destroyed.
    838 					*/
    839 					int damage = Accum;
    840 					Accum -= damage;
    841 					if (As_Object(xObject)->Take_Damage(damage, 0, WARHEAD_FIRE) == RESULT_DESTROYED) {
    842 						if (Target_Legal(VirtualAnimTarget)) {
    843 							delete As_Animation(VirtualAnimTarget);
    844 						}
    845 						delete this;
    846 						return;
    847 					}
    848 				}
    849 			}
    850 
    851 			/*
    852 			**	During the biggest stage (covers the most ground), perform any ground altering
    853 			**	action required. This masks craters and scorch marks, so that they appear
    854 			**	naturally rather than "popping" into existence while in plain sight.
    855 			*/
    856 			if (Class->Biggest && Class->Start+stage == Class->Biggest) {
    857 				Middle();
    858 			}
    859 
    860 			/*
    861 			**	Check to see if the last frame has been displayed. If so, then the
    862 			**	animation either ends or loops.
    863 			*/
    864 			if ((Loops <= 1 && stage >= Class->Stages) || (Loops > 1 && stage >= Class->LoopEnd-Class->Start)) {
    865 
    866 				/*
    867 				**	Determine if this animation should loop another time. If so, then start the loop
    868 				**	but if not, then proceed into the animation termination handler.
    869 				*/
    870 				if (Loops > 0) Loops--;
    871 				if (Loops != 0) {
    872 					Set_Stage(Class->LoopStart);
    873 				} else {
    874 
    875 					if (Class->VirtualAnim != ANIM_NONE) {
    876 						Make_Invisible();
    877 						if (!Target_Legal(VirtualAnimTarget)) {
    878 							if (Class->ChainTo != ANIM_NONE) {
    879 								Chain();
    880 							}
    881 							else {
    882 								delete this;
    883 							}
    884 						}
    885 					}
    886 					else {
    887 						if ((Class->VirtualStages < 0) || (stage >= Class->VirtualStages)) {
    888 							if (Class->ChainTo != ANIM_NONE) {
    889 								Chain();
    890 							}
    891 							else {
    892 								delete this;
    893 							}
    894 						}
    895 					}
    896 				}
    897 			}
    898 		}
    899 	}
    900 #endif
    901 }
    902 
    903 
    904 /***********************************************************************************************
    905  * AnimClass::Attach_To -- Attaches animation to object specified.                             *
    906  *                                                                                             *
    907  *    An animation can be "attached" to an object. In such cases, the animation is rendered    *
    908  *    as an offset from the center of the object it is attached to. This allows affects such   *
    909  *    as fire or smoke to be consistently placed on the vehicle it is associated with.         *
    910  *                                                                                             *
    911  * INPUT:   obj   -- Pointer to the object to attach the animation to.                         *
    912  *                                                                                             *
    913  * OUTPUT:  none                                                                               *
    914  *                                                                                             *
    915  * WARNINGS:   none                                                                            *
    916  *                                                                                             *
    917  * HISTORY:                                                                                    *
    918  *   09/19/1994 JLB : Created.                                                                 *
    919  *=============================================================================================*/
    920 void AnimClass::Attach_To(ObjectClass * obj)
    921 {
    922 #ifdef VIC
    923 	assert(Anims.ID(this) == ID);
    924 	assert(IsActive);
    925 
    926 	if (obj == NULL) return;
    927 	assert(obj->IsActive);
    928 
    929 	if (obj->In_Which_Layer() == LAYER_GROUND) obj->Mark(MARK_OVERLAP_UP);
    930 	obj->IsAnimAttached = true;
    931 	if (obj->In_Which_Layer() == LAYER_GROUND) obj->Mark(MARK_OVERLAP_DOWN);
    932 	Limbo();
    933 	xObject = obj->As_Target();
    934 	Unlimbo(Coord);
    935 	AttachLayer = In_Which_Layer();
    936 	Height = (AttachLayer == LAYER_GROUND) ? FLIGHT_LEVEL : 0;
    937 	Coord = Coord_Sub(Coord, obj->Target_Coord());
    938 #endif
    939 }
    940 
    941 
    942 /***********************************************************************************************
    943  * AnimClass::Sort_Above -- Sorts the animation right above the specified target.              *
    944  *                                                                                             *
    945  *    Allows an animation to always be sorted above a particular target. Typically used        *
    946  *    for explosions and other effects that look weird beneath those objects.                  *
    947  *                                                                                             *
    948  * INPUT:   target   -- Target to sort above.                                                  *
    949  *                                                                                             *
    950  * OUTPUT:  none                                                                               *
    951  *                                                                                             *
    952  * WARNINGS:   none                                                                            *
    953  *                                                                                             *
    954  * HISTORY:                                                                                    *
    955  *   08/14/2019 SKY : Created.                                                                 *
    956  *=============================================================================================*/
    957 void AnimClass::Sort_Above(TARGET target)
    958 {
    959 #ifdef VIC
    960 	SortTarget = target;
    961 #endif
    962 }
    963 
    964 
    965 /***********************************************************************************************
    966  * AnimClass::In_Which_Layer -- Determines what render layer the anim should be in.            *
    967  *                                                                                             *
    968  *    Use this routine to find out which display layer (ground or air) that the animation      *
    969  *    should be in. This information is used to place the animation into the correct display   *
    970  *    list.                                                                                    *
    971  *                                                                                             *
    972  * INPUT:   none                                                                               *
    973  *                                                                                             *
    974  * OUTPUT:  Returns with the layer that the animation should exist in.                         *
    975  *                                                                                             *
    976  * WARNINGS:   none                                                                            *
    977  *                                                                                             *
    978  * HISTORY:                                                                                    *
    979  *   12/25/1994 JLB : Created.                                                                 *
    980  *=============================================================================================*/
    981 LayerType AnimClass::In_Which_Layer(void) const
    982 {
    983 #ifdef VIC
    984 	assert(Anims.ID(this) == ID);
    985 	assert(IsActive);
    986 
    987 	if (AttachLayer != LAYER_NONE) {
    988 		return AttachLayer;
    989 	}
    990 
    991 	if (Class->Type >= ANIM_CORPSE1 && Class->Type <= ANIM_CORPSE3) {
    992 		return(LAYER_SURFACE);
    993 	}
    994 
    995 	if (Target_Legal(xObject)) {
    996 		return As_Object(xObject)->In_Which_Layer();
    997 	}
    998 
    999 	if (Class->IsGroundLayer) {
   1000 		return(LAYER_GROUND);
   1001 	}
   1002 #endif
   1003 	return(LAYER_AIR);
   1004 }
   1005 
   1006 
   1007 /***********************************************************************************************
   1008  * AnimClass::Start -- Processes initial animation side effects.                               *
   1009  *                                                                                             *
   1010  *    This routine is called when the animation first starts. Sometimes there are side effects *
   1011  *    associated with this animation that must occur immediately. Typically, this is the       *
   1012  *    sound effect assigned to this animation. If this animation is supposed to attach itself  *
   1013  *    to any object at its location, then do so at this time as well.                          *
   1014  *                                                                                             *
   1015  * INPUT:   none                                                                               *
   1016  *                                                                                             *
   1017  * OUTPUT:  none                                                                               *
   1018  *                                                                                             *
   1019  * WARNINGS:   none                                                                            *
   1020  *                                                                                             *
   1021  * HISTORY:                                                                                    *
   1022  *   06/30/1995 JLB : Created.                                                                 *
   1023  *=============================================================================================*/
   1024 void AnimClass::Start(void)
   1025 {
   1026 #ifdef VIC
   1027 	assert(Anims.ID(this) == ID);
   1028 	assert(IsActive);
   1029 
   1030 	Mark();
   1031 
   1032 	/*
   1033 	**	Play the sound effect for this animation.
   1034 	*/
   1035 	Sound_Effect(Class->Sound, Coord);
   1036 
   1037 	/*
   1038 	**	If the stage where collateral effects occur is the first stage of the animation, then
   1039 	**	perform this action now. Subsequent checks against this stage value starts with the
   1040 	**	second frame of the animation.
   1041 	*/
   1042 	if (!Class->Biggest) {
   1043 		Middle();
   1044 	}
   1045 #endif
   1046 }
   1047 
   1048 
   1049 /***********************************************************************************************
   1050  * AnimClass::Middle -- Processes any middle events.                                           *
   1051  *                                                                                             *
   1052  *    This routine is called when the animation as reached its largest stage. Typically, this  *
   1053  *    routine is used to cause scorches or craters to appear at a cosmetically pleasing        *
   1054  *    moment.                                                                                  *
   1055  *                                                                                             *
   1056  * INPUT:   none                                                                               *
   1057  *                                                                                             *
   1058  * OUTPUT:  none                                                                               *
   1059  *                                                                                             *
   1060  * WARNINGS:   none                                                                            *
   1061  *                                                                                             *
   1062  * HISTORY:                                                                                    *
   1063  *   06/30/1995 JLB : Created.                                                                 *
   1064  *   10/17/1995 JLB : Ion camera added.                                                        *
   1065  *=============================================================================================*/
   1066 void AnimClass::Middle(void)
   1067 {
   1068 #ifdef VIC
   1069 	assert(Anims.ID(this) == ID);
   1070 	assert(IsActive);
   1071 
   1072 	CELL cell = Coord_Cell(Center_Coord());
   1073 	CellClass * cellptr = &Map[cell];
   1074 
   1075 	if (Class->Type == ANIM_ATOM_BLAST) {
   1076 		Do_Atom_Damage(OwnerHouse, cell);
   1077 	}
   1078 
   1079 	/*
   1080 	**	If this animation leaves scorch marks (e.g., napalm), then do so at this time.
   1081 	*/
   1082 	if (Class->IsScorcher) {
   1083 		new SmudgeClass(Random_Pick(SMUDGE_SCORCH1, SMUDGE_SCORCH6), Center_Coord());
   1084 	}
   1085 
   1086 	/*
   1087 	**	Some animations leave a crater when they occur. Artillery is a good example.
   1088 	**	Craters always remove the Tiberium where they occur.
   1089 	*/
   1090 	if (Class->IsCraterForming) {
   1091 
   1092 		/*
   1093 		**	Craters reduce the level of Tiberium in the cell.
   1094 		*/
   1095 		cellptr->Reduce_Tiberium(6);
   1096 
   1097 		/*
   1098 		**	If there already is a crater in the cell, then just expand the
   1099 		**	crater.
   1100 		*/
   1101 		new SmudgeClass(SMUDGE_CRATER1, Center_Coord());
   1102 	}
   1103 
   1104 	AnimClass * newanim;
   1105 
   1106 	/*
   1107 	**	If this animation spawns side effects during its lifetime, then
   1108 	**	do so now. Usually, these side effects are in the form of other
   1109 	**	animations.
   1110 	*/
   1111 	switch (Class->Type) {
   1112 		case ANIM_NAPALM1:
   1113 		case ANIM_NAPALM2:
   1114 		case ANIM_NAPALM3:
   1115 			new AnimClass(ANIM_FIRE_SMALL, Map.Closest_Free_Spot(Coord_Scatter(Center_Coord(), 0x0040), true), 0, Random_Pick(1, 2));
   1116 			if (Percent_Chance(50)) {
   1117 				new AnimClass(ANIM_FIRE_SMALL, Map.Closest_Free_Spot(Coord_Scatter(Center_Coord(), 0x00A0), true), 0, Random_Pick(1, 2));
   1118 			}
   1119 			if (Percent_Chance(50)) {
   1120 				new AnimClass(ANIM_FIRE_MED, Map.Closest_Free_Spot(Coord_Scatter(Center_Coord(), 0x0070), true), 0, Random_Pick(1, 2));
   1121 			}
   1122 			break;
   1123 
   1124 		case ANIM_FIRE_MED:
   1125 		case ANIM_FIRE_MED2:
   1126 			newanim = new AnimClass(ANIM_FIRE_SMALL, Center_Coord(), 0, Random_Pick(1, 2));
   1127 			if (newanim != NULL && xObject != TARGET_NONE) {
   1128 				newanim->Attach_To(As_Object(xObject));
   1129 			}
   1130 			break;
   1131 
   1132 		default:
   1133 			break;
   1134 	}
   1135 #endif
   1136 }
   1137 
   1138 
   1139 void AnimClass::Chain(void)
   1140 {
   1141 	/*
   1142 	**	The animation should end now, but first check to see if
   1143 	**	it needs to chain into another animation. If so, then the
   1144 	**	animation isn't technically over. It metamorphoses into the
   1145 	**	new form.
   1146 	*/
   1147 	if (Class->ChainTo != ANIM_NONE) {
   1148 
   1149 		Class = (AnimTypeClass *)&AnimTypeClass::As_Reference(Class->ChainTo);
   1150 
   1151 		if (Class->Stages == -1) {
   1152 			IsTheaterShape = Class->IsTheater;
   1153 			((int&)Class->Stages) = Get_Build_Frame_Count(Class->Get_Image_Data());
   1154 			IsTheaterShape = false;
   1155 		}
   1156 		if (Class->LoopEnd == -1) {
   1157 			((int&)Class->LoopEnd) = Class->Stages;
   1158 		}
   1159 
   1160 		IsToDelete = false;
   1161 		Loops = Class->Loops;
   1162 		Accum = 0;
   1163 		if (Class->IsNormalized) {
   1164 			Set_Rate(Options.Normalize_Delay(Class->Delay));
   1165 		} else {
   1166 			Set_Rate(Class->Delay);
   1167 		}
   1168 		Set_Stage(Class->Start);
   1169 		Start();
   1170 	}
   1171 }
   1172 
   1173 
   1174 /***********************************************************************************************
   1175  * AnimClass::Detach -- Remove animation if attached to target.                                *
   1176  *                                                                                             *
   1177  *    This routine is called when the specified target is being removed from the game. If this *
   1178  *    animation happens to be attached to this object, then the animation must be remove as    *
   1179  *    well.                                                                                    *
   1180  *                                                                                             *
   1181  * INPUT:   target   -- The target that is about to be destroyed.                              *
   1182  *                                                                                             *
   1183  *          all      -- Is the target being destroyed RIGHT NOW? If not, then it will be       *
   1184  *                      destroyed soon. In that case, the animation should continue to remain  *
   1185  *                      attached for cosmetic reasons.                                         *
   1186  *                                                                                             *
   1187  * OUTPUT:  none                                                                               *
   1188  *                                                                                             *
   1189  * WARNINGS:   none                                                                            *
   1190  *                                                                                             *
   1191  * HISTORY:                                                                                    *
   1192  *   06/30/1995 JLB : Created.                                                                 *
   1193  *   07/02/1995 JLB : Detach is a precursor to animation destruction.                          *
   1194  *=============================================================================================*/
   1195 void AnimClass::Detach(TARGET target, bool all)
   1196 {
   1197 #ifdef VIC
   1198 	assert(Anims.ID(this) == ID);
   1199 	assert(IsActive);
   1200 
   1201 	if (all) {
   1202 		if (Target_Legal(VirtualAnimTarget) && VirtualAnimTarget == target) {
   1203 			VirtualAnimTarget = TARGET_NONE;
   1204 			if (IsInvisible) {
   1205 				IsToDelete = true;
   1206 				Mark(MARK_UP);
   1207 			}
   1208 		}
   1209 		if (xObject == target) {
   1210 			Map.Remove(this, In_Which_Layer());
   1211 			xObject = TARGET_NONE;
   1212 			AttachLayer = LAYER_NONE;
   1213 			IsToDelete = true;
   1214 			Mark(MARK_UP);
   1215 		}
   1216 	}
   1217 #endif
   1218 }
   1219 
   1220 
   1221 /***********************************************************************************************
   1222  * AnimClass::Do_Atom_Damage -- Do atom bomb damage centered around the cell specified.        *
   1223  *                                                                                             *
   1224  *    This routine will apply damage around the ground-zero cell specified.                    *
   1225  *                                                                                             *
   1226  * INPUT:   ownerhouse  -- The owner of this atom bomb.                                        *
   1227  *                                                                                             *
   1228  *          cell        -- The ground zero location to apply the atom bomb damage.             *
   1229  *                                                                                             *
   1230  * OUTPUT:  none                                                                               *
   1231  *                                                                                             *
   1232  * WARNINGS:   none                                                                            *
   1233  *                                                                                             *
   1234  * HISTORY:                                                                                    *
   1235  *   07/06/1996 JLB : Created.                                                                 *
   1236  *=============================================================================================*/
   1237 void AnimClass::Do_Atom_Damage(HousesType ownerhouse, CELL cell)
   1238 {
   1239 #ifdef VIC
   1240 	/*
   1241 	**	Find someone to blame the explosion on. This is necessary in
   1242 	**	order to properly enact retribution and record the kill for
   1243 	**	score purposes.
   1244 	*/
   1245 	BuildingClass * building = NULL;
   1246 	TechnoClass * backup = NULL;
   1247 	if (ownerhouse != HOUSE_NONE) {
   1248 		for (int index = 0; index < Logic.Count(); index++) {
   1249 			ObjectClass * obj = Logic[index];
   1250 
   1251 			if (obj != NULL && obj->Is_Techno() && obj->Owner() == ownerhouse) {
   1252 				backup = (TechnoClass *)obj;
   1253 				if (obj->What_Am_I() == RTTI_BUILDING && *((BuildingClass *)obj) == STRUCT_MSLO) {
   1254 					building = (BuildingClass *)obj;
   1255 					break;
   1256 				}
   1257 			}
   1258 		}
   1259 
   1260 		if (building == NULL) building = (BuildingClass *)backup;
   1261 	}
   1262 
   1263 	int radius;
   1264 	int rawdamage;
   1265 	if (Session.Type == GAME_NORMAL) {
   1266 		radius = 4;
   1267 		rawdamage = Rule.AtomDamage;
   1268 		//WhitePalette.Set(FADE_PALETTE_SLOW, Call_Back);		//TO_FIX. ST 5/8/2019
   1269 	} else {
   1270 		radius = 3;
   1271 		rawdamage = Rule.AtomDamage/5;
   1272 	}
   1273 
   1274 	Wide_Area_Damage(Cell_Coord(cell), radius * CELL_LEPTON_W, rawdamage, building, WARHEAD_FIRE);
   1275 	Shake_The_Screen(3);
   1276 	if (Session.Type == GAME_NORMAL) {
   1277 		//GamePalette.Set(FADE_PALETTE_SLOW, Call_Back);	//TO_FIX. ST 5/8/2019
   1278 	}
   1279 #endif
   1280 }
   1281 
   1282 void AnimClass::Set_Owner(HousesType owner)
   1283 {
   1284 	OwnerHouse = owner;
   1285 	if (Target_Legal(VirtualAnimTarget)) {
   1286 		As_Animation(VirtualAnimTarget)->Set_Owner(owner);
   1287 	}
   1288 }
   1289 
   1290 void AnimClass::Set_Visible_Flags(unsigned flags)
   1291 {
   1292 	VisibleFlags = flags;
   1293 	if (Target_Legal(VirtualAnimTarget)) {
   1294 		As_Animation(VirtualAnimTarget)->Set_Visible_Flags(flags);
   1295 	}
   1296 }