CnC_Remastered_Collection

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

ANIM.CPP (62589B)


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