CnC_Remastered_Collection

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

VORTEX.CPP (51596B)


      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 /*************************************************************************************
     17  **   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                  **
     18  *************************************************************************************
     19  *                                                                                   *
     20  *                 Project Name : Command & Conquer - Red Alert                      *
     21  *                                                                                   *
     22  *                    File Name : VORTEX.CPP                                         *
     23  *                                                                                   *
     24  *                   Programmer : Steve Tall                                         *
     25  *                                                                                   *
     26  *                   Start Date : August 12th, 1996                                  *
     27  *                                                                                   *
     28  *                  Last Update : September 6th, 1996 [ST]                           *
     29  *                                                                                   *
     30  *-----------------------------------------------------------------------------------*
     31  * Overview:                                                                         *
     32  *                                                                                   *
     33  *  Circley vortexy swirly type thing. (Really just a pixel & color remap).          *
     34  *                                                                                   *
     35  *-----------------------------------------------------------------------------------*
     36  * Functions:                                                                        *
     37  *                                                                                   *
     38  * CVC::ChronalVortexClass -- vortex class constructor                               *
     39  * CVC::~ChronalVortexClass -- vortex class destructor                               *
     40  * CVC::Appear -- Makes a chronal vortex appear at the given coordinate.             *
     41  * CVC::Disappear -- Makes the chronal vortex go away.                               *
     42  * CVC::Hide -- Makes the vortex hide. It might come back later.                     *
     43  * CVC::Show -- Makes a hidden vortex visible again.                                 *
     44  * CVC::Stop -- Stops the vortex without going through the hide animation            *
     45  * CVC::Load -- Loads the chronal vortex from a savegame file.                       *
     46  * CVC::Save -- Saves the vortex class data to a savegame file                       *
     47  * CVC::AI -- AI for the vortex. Includes movement and firing.                       *
     48  * CVC::Movement -- Movement AI for the vortex.                                      *
     49  * CVC::Set_Target -- Make the vortex zap a particular object.                       *
     50  * CVC::Attack -- look for objects to attack                                         *
     51  * CVC::Zap_Target -- If the vortex has a target object then zap it with lightning.  *
     52  * CVC::Coordinate_Remap -- Draws the vortex                                         *
     53  * CVC::Render -- Renders the vortex at its current position.                        *
     54  * CVC::Set_Redraw -- Flags the cells under to vortex to redraw.                     *
     55  * CVC::Setup_Remap_Tables -- Initialises the color remap tables based on theater.   *
     56  * CVC::Build_Fading_Table -- Builds a fading color lookup table.                    *
     57  *                                                                                   *
     58  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     59 
     60 #include "function.h"
     61 #include "vortex.h"
     62 
     63 
     64 /*
     65 ** Instance of chronal vortex class. This must be the only instance.
     66 */
     67 ChronalVortexClass	ChronalVortex;
     68 
     69 
     70 
     71 /***********************************************************************************************
     72  * CVC::ChronalVortexClass -- vortex class constructor                                         *
     73  *                                                                                             *
     74  *                                                                                             *
     75  *                                                                                             *
     76  * INPUT:    Nothing                                                                           *
     77  *                                                                                             *
     78  * OUTPUT:   Nothing                                                                           *
     79  *                                                                                             *
     80  * WARNINGS: None                                                                              *
     81  *                                                                                             *
     82  * HISTORY:                                                                                    *
     83  *    8/29/96 4:25PM ST : Created                                                              *
     84  *=============================================================================================*/
     85 ChronalVortexClass::ChronalVortexClass (void)
     86 {
     87 	Active 	= 0;
     88 	Theater 	= THEATER_NONE;
     89 	Speed		= 10;
     90 	Range		= 10;
     91 	Damage	= 200;
     92 	RenderBuffer = NULL;		//We havn't allocated it yet. It will be allocated as needed.
     93 }
     94 
     95 
     96 
     97 /***********************************************************************************************
     98  * CVC::~ChronalVortexClass -- vortex class destructor                                         *
     99  *                                                                                             *
    100  *                                                                                             *
    101  *                                                                                             *
    102  * INPUT:    Nothing                                                                           *
    103  *                                                                                             *
    104  * OUTPUT:   Nothing                                                                           *
    105  *                                                                                             *
    106  * WARNINGS: None                                                                              *
    107  *                                                                                             *
    108  * HISTORY:                                                                                    *
    109  *    8/29/96 4:25PM ST : Created                                                              *
    110  *=============================================================================================*/
    111 ChronalVortexClass::~ChronalVortexClass (void)
    112 {
    113 	if (RenderBuffer) delete RenderBuffer;
    114 	Active = 0;
    115 }
    116 
    117 
    118 
    119 /***********************************************************************************************
    120  * CVC::Appear -- Makes a chronal vortex appear at the given coordinate.                       *
    121  *                                                                                             *
    122  *                                                                                             *
    123  *                                                                                             *
    124  * INPUT:    Coordinate that vortex should appear at.                                          *
    125  *                                                                                             *
    126  * OUTPUT:   Nothing                                                                           *
    127  *                                                                                             *
    128  * WARNINGS: This member does nothing if the vortex is already active                          *
    129  *                                                                                             *
    130  * HISTORY:                                                                                    *
    131  *    8/29/96 4:27PM ST : Created                                                              *
    132  *=============================================================================================*/
    133 void ChronalVortexClass::Appear (COORDINATE coordinate)
    134 {
    135 	if (Active) return;
    136 
    137 	/*
    138 	** Adjust the given coordinate so the vortex appears in a central position
    139 	*/
    140 	int x = Lepton_To_Pixel(Coord_X(coordinate));
    141 	int y = Lepton_To_Pixel(Coord_Y(coordinate));
    142 
    143 	x -= 32;
    144 	y -= 32;
    145 
    146 	LEPTON lx = Pixel_To_Lepton (x);
    147 	LEPTON ly = Pixel_To_Lepton (y);
    148 
    149 	Position = XY_Coord (lx, ly);
    150 
    151 	/*
    152 	** Initialise the vortex variables.
    153 	*/
    154 	AnimateDir 		= 1;
    155 	AnimateFrame 	= 0;
    156 	State				= STATE_GROW;
    157 	Active			= true;
    158 	Animate			= 0;
    159 	StartShutdown	= false;
    160 	LastAttackFrame= Frame;
    161 	TargetObject	= TARGET_NONE;
    162 	ZapFrame			= 0;
    163 	Hidden			= false;
    164 	StartHiding		= false;
    165 	XDir				= 0;
    166 	YDir				= 0;
    167 
    168 	/*
    169 	** Vortex starts off in a random direction.
    170 	*/
    171 	DesiredXDir		= Random_Pick (-Speed, Speed);
    172 	DesiredYDir		= Random_Pick (-Speed, Speed);
    173 
    174 }
    175 
    176 
    177 /***********************************************************************************************
    178  * CVC::Disappear -- Makes the chronal vortex go away.                                         *
    179  *                                                                                             *
    180  *                                                                                             *
    181  *                                                                                             *
    182  * INPUT:    Nothing                                                                           *
    183  *                                                                                             *
    184  * OUTPUT:   Nothing                                                                           *
    185  *                                                                                             *
    186  * WARNINGS: None                                                                              *
    187  *                                                                                             *
    188  * HISTORY:                                                                                    *
    189  *    8/29/96 4:30PM ST : Created                                                              *
    190  *=============================================================================================*/
    191 void ChronalVortexClass::Disappear (void)
    192 {
    193 	if (Hidden) {
    194 		Active = false;
    195 	} else {
    196 		StartShutdown = true;
    197 	}
    198 }
    199 
    200 
    201 
    202 /***********************************************************************************************
    203  * CVC::Hide -- Makes the vortex hide. It might come back later.                               *
    204  *                                                                                             *
    205  *                                                                                             *
    206  *                                                                                             *
    207  * INPUT:    Nothing                                                                           *
    208  *                                                                                             *
    209  * OUTPUT:   Nothing                                                                           *
    210  *                                                                                             *
    211  * WARNINGS: This doesnt deactivate the vortex. Use Disappear to get rid of it permanently.    *
    212  *                                                                                             *
    213  * HISTORY:                                                                                    *
    214  *    8/29/96 4:30PM ST : Created                                                              *
    215  *=============================================================================================*/
    216 void ChronalVortexClass::Hide (void)
    217 {
    218 	if (!StartShutdown) {
    219 		StartHiding = true;
    220 	}
    221 }
    222 
    223 
    224 /***********************************************************************************************
    225  * CVC::Show -- Makes a hidden vortex visible again.                                           *
    226  *                                                                                             *
    227  *                                                                                             *
    228  *                                                                                             *
    229  * INPUT:    Nothing                                                                           *
    230  *                                                                                             *
    231  * OUTPUT:   Nothing                                                                           *
    232  *                                                                                             *
    233  * WARNINGS: None                                                                              *
    234  *                                                                                             *
    235  * HISTORY:                                                                                    *
    236  *    8/29/96 4:31PM ST : Created                                                              *
    237  *=============================================================================================*/
    238 void ChronalVortexClass::Show (void)
    239 {
    240 	/*
    241 	** Dont do anything if vortx is dying.
    242 	*/
    243 	if (!StartShutdown) {
    244 
    245 		/*
    246 		** If the vortex is hidden then show it again.
    247 		*/
    248 		if (Hidden) {
    249 			Hidden = false;
    250 			StartHiding = false;
    251 			AnimateFrame = 0;
    252 			State = STATE_GROW;
    253 			XDir = 0;
    254 			YDir = 0;
    255 		} else {
    256 			/*
    257 			** If the vortex is in the process of hiding then reverse it.
    258 			*/
    259 			StartHiding = false;
    260 			if (State == STATE_SHRINK) {
    261 				State = STATE_GROW;
    262 				AnimateFrame = VORTEX_FRAMES - AnimateFrame;
    263 			}
    264 		}
    265 	}
    266 }
    267 
    268 
    269 
    270 /***********************************************************************************************
    271  * CVC::Stop -- Stops the vortex without going through the hide animation                      *
    272  *                                                                                             *
    273  *                                                                                             *
    274  *                                                                                             *
    275  * INPUT:    Nothing                                                                           *
    276  *                                                                                             *
    277  * OUTPUT:   Nothing                                                                           *
    278  *                                                                                             *
    279  * WARNINGS: None                                                                              *
    280  *                                                                                             *
    281  * HISTORY:                                                                                    *
    282  *    8/29/96 4:32PM ST : Created                                                              *
    283  *=============================================================================================*/
    284 void ChronalVortexClass::Stop(void)
    285 {
    286 	if (Active) Active = false;
    287 }
    288 
    289 
    290 
    291 
    292 /***********************************************************************************************
    293  * CVC::Load -- Loads the chronal vortex from a savegame file.                                 *
    294  *                                                                                             *
    295  *                                                                                             *
    296  *                                                                                             *
    297  * INPUT:    ptr to file                                                                       *
    298  *                                                                                             *
    299  * OUTPUT:   Nothing                                                                           *
    300  *                                                                                             *
    301  * WARNINGS: None                                                                              *
    302  *                                                                                             *
    303  * HISTORY:                                                                                    *
    304  *    8/29/96 4:32PM ST : Created                                                              *
    305  *=============================================================================================*/
    306 void ChronalVortexClass::Load(Straw &file)
    307 {
    308 	/*
    309 	** Delete the render buffer as we are going to lose the pointer anyway.
    310 	** It will be re-allocated when needed.
    311 	*/
    312 	if (RenderBuffer) delete RenderBuffer;
    313 
    314 	file.Get (this, sizeof (ChronalVortexClass));
    315 }
    316 
    317 
    318 
    319 /***********************************************************************************************
    320  * CVC::Save -- Saves the vortex class data to a savegame file                                 *
    321  *                                                                                             *
    322  *                                                                                             *
    323  *                                                                                             *
    324  * INPUT:    file                                                                              *
    325  *                                                                                             *
    326  * OUTPUT:   Nothing                                                                           *
    327  *                                                                                             *
    328  * WARNINGS: None                                                                              *
    329  *                                                                                             *
    330  * HISTORY:                                                                                    *
    331  *    8/29/96 4:33PM ST : Created                                                              *
    332  *=============================================================================================*/
    333 void ChronalVortexClass::Save(Pipe &file)
    334 {
    335 	GraphicBufferClass *save_ptr = NULL;
    336 
    337 	if (RenderBuffer){
    338 		/*
    339 		** Save the ptr to the render buffer so we can null it for the save
    340 		*/
    341 		save_ptr = RenderBuffer;
    342 		RenderBuffer = NULL;
    343 	}
    344 
    345 	file.Put (this, sizeof (ChronalVortexClass));
    346 
    347 	/*
    348 	** Restore the render buffer ptr
    349 	*/
    350 	if (save_ptr){
    351 		RenderBuffer = save_ptr;
    352 	}
    353 }
    354 
    355 
    356 
    357 /***********************************************************************************************
    358  * CVC::AI -- AI for the vortex. Includes movement and firing.                                 *
    359  *                                                                                             *
    360  *                                                                                             *
    361  *                                                                                             *
    362  * INPUT:    Nothing                                                                           *
    363  *                                                                                             *
    364  * OUTPUT:   Nothing                                                                           *
    365  *                                                                                             *
    366  * WARNINGS: None                                                                              *
    367  *                                                                                             *
    368  * HISTORY:                                                                                    *
    369  *    8/29/96 4:34PM ST : Created                                                              *
    370  *=============================================================================================*/
    371 void ChronalVortexClass::AI(void)
    372 {
    373 
    374 	int chance;
    375 
    376 	/*
    377 	** No AI if vortex isnt active
    378 	*/
    379 	if (Active) {
    380 
    381 		/*
    382 		** Do the movement AI
    383 		*/
    384 		Movement();
    385 
    386 		/*
    387 		** Do the attack AI
    388 		*/
    389 		Zap_Target();
    390 
    391 
    392 		if (Hidden && (Frame - HiddenFrame > 50) ) {
    393 			/*
    394 			** Vortex is hidden. Chance of it showing itself increases the longer its stays hidden.
    395 			*/
    396 			chance = Random_Pick(0,2000);
    397 			if (chance <= Frame - HiddenFrame) {
    398 				Show();
    399 			}
    400 		} else {
    401 
    402 			if (Animate == 0) {
    403 
    404 				/*
    405 				** Its time to animate the vortex.
    406 				*/
    407 				AnimateFrame += AnimateDir;
    408 
    409 				if (AnimateFrame > VORTEX_FRAMES) {
    410 					/*
    411 					** State changes can only occur on final animation frames.
    412 					*/
    413 					AnimateFrame = 1;
    414 
    415 					if (StartShutdown) {
    416 
    417 						/*
    418 						** Vortex is in the process of dying.
    419 						*/
    420 						if (State == STATE_SHRINK) {
    421 							Set_Redraw();
    422 							Active = false;
    423 							AnimateFrame = 0;
    424 						} else {
    425 							Attack();
    426 							State = STATE_SHRINK;
    427 						}
    428 					} else {
    429 
    430 						if (StartHiding) {
    431 							/*
    432 							** Vortex wants to hide.
    433 							*/
    434 							if (State == STATE_SHRINK) {
    435 								/*
    436 								** Hide the vortex now.
    437 								*/
    438 								Set_Redraw();
    439 								StartHiding = false;
    440 								Hidden = true;
    441 								HiddenFrame = Frame;
    442 								if (Random_Pick(0,4) == 4) {
    443 									Disappear();
    444 								}
    445 							} else {
    446 								/*
    447 								** Start hiding the vortex.
    448 								*/
    449 								Attack();
    450 								State = STATE_SHRINK;
    451 							}
    452 						} else {
    453 
    454 							Attack();
    455 							if (State == STATE_GROW) {
    456 								State = STATE_ROTATE;
    457 							} else {
    458 								//Attack();
    459 							}
    460 						}
    461 					}
    462 				} else {
    463 					if (AnimateFrame == VORTEX_FRAMES / 2) Attack();
    464 				}
    465 			}
    466 			Animate++;
    467 			Animate &= 1;
    468 		}
    469 	}
    470 }
    471 
    472 
    473 
    474 
    475 
    476 /***********************************************************************************************
    477  * CVC::Movement -- Movement AI for the vortex.                                                *
    478  *                                                                                             *
    479  *                                                                                             *
    480  *                                                                                             *
    481  * INPUT:    Nothing                                                                           *
    482  *                                                                                             *
    483  * OUTPUT:   Nothing                                                                           *
    484  *                                                                                             *
    485  * WARNINGS: None                                                                              *
    486  *                                                                                             *
    487  * HISTORY:                                                                                    *
    488  *    8/29/96 4:39PM ST : Created                                                              *
    489  *=============================================================================================*/
    490 void ChronalVortexClass::Movement (void)
    491 {
    492 	bool newpick = true;
    493 
    494 	/*
    495 	** Update the vortex position by applying the x and y direction variables
    496 	*/
    497 	LEPTON x = Coord_X(Position);
    498 	LEPTON y = Coord_Y(Position);
    499 
    500 	x += XDir;
    501 	y += YDir;
    502 
    503 	Position = XY_Coord (x,y);
    504 
    505 	/*
    506 	** Reverse the direction of the vortex if its drifting off the map.
    507 	*/
    508 	if (x > CELL_LEPTON_W *(Map.MapCellX + Map.MapCellWidth -4)) {
    509 		newpick = false;
    510 		if (DesiredXDir >0 ) DesiredXDir = -DesiredXDir;
    511 	}
    512 
    513 	if (y > CELL_LEPTON_H *(Map.MapCellY + Map.MapCellHeight -4)) {
    514 		newpick = false;
    515 		if (DesiredYDir >0 ) DesiredYDir = -DesiredYDir;
    516 	}
    517 
    518 	if (x < CELL_LEPTON_W *Map.MapCellX + 2*CELL_LEPTON_W) {
    519 		newpick = false;
    520 		if (DesiredXDir <0 ) DesiredXDir = -DesiredXDir;
    521 	}
    522 
    523 	if (y < CELL_LEPTON_H *Map.MapCellY + 2*CELL_LEPTON_W) {
    524 		newpick = false;
    525 		if (DesiredYDir <0 ) DesiredYDir = -DesiredYDir;
    526 	}
    527 
    528 	/*
    529 	** Vortex direction tends towards the desired direction unless the vortex is shutting down or
    530 	**	appearing in which case the direction tends towards 0.
    531 	*/
    532 	if (State == STATE_ROTATE || Hidden) {
    533 		if (XDir < DesiredXDir) XDir ++;
    534 		if (XDir > DesiredXDir) XDir --;
    535 		if (YDir < DesiredYDir) YDir ++;
    536 		if (YDir > DesiredYDir) YDir --;
    537 	} else {
    538 		if (XDir > 0) XDir -= Speed/8;
    539 		if (XDir < 0) XDir += Speed/8;
    540 		if (YDir > 0) YDir -= Speed/8;
    541 		if (YDir < 0) YDir += Speed/8;
    542 	}
    543 
    544 	/*
    545 	** Occasionally change the direction of the vortex.
    546 	*/
    547 	if (newpick && Random_Pick (0, 100) == 100) {
    548 		DesiredXDir		= Random_Pick (-Speed, Speed);
    549 		DesiredYDir		= Random_Pick (-Speed, Speed);
    550 	}
    551 }
    552 
    553 
    554 
    555 /***********************************************************************************************
    556  * CVC::Set_Target -- Make the vortex zap a particular object.                                 *
    557  *                                                                                             *
    558  *                                                                                             *
    559  *                                                                                             *
    560  * INPUT:    ptr to object to zap                                                              *
    561  *                                                                                             *
    562  * OUTPUT:   Nothing                                                                           *
    563  *                                                                                             *
    564  * WARNINGS: None                                                                              *
    565  *                                                                                             *
    566  * HISTORY:                                                                                    *
    567  *    8/29/96 4:42PM ST : Created                                                              *
    568  *=============================================================================================*/
    569 void ChronalVortexClass::Set_Target (ObjectClass *target)
    570 {
    571 	if (Active){
    572 		ZapFrame = 0;
    573 		TargetObject = TARGET_NONE;
    574 		if (target != NULL) TargetObject = target->As_Target();
    575 		LastAttackFrame = Frame;
    576 		TargetDistance = (target != NULL) ? Distance (target->Center_Coord(), Position) : 0;
    577 	}
    578 }
    579 
    580 
    581 /***********************************************************************************************
    582  * CVC::Attack -- look for objects to attack                                                   *
    583  *                                                                                             *
    584  *                                                                                             *
    585  *                                                                                             *
    586  * INPUT:    Nothing                                                                           *
    587  *                                                                                             *
    588  * OUTPUT:   Nothing                                                                           *
    589  *                                                                                             *
    590  * WARNINGS: None                                                                              *
    591  *                                                                                             *
    592  * HISTORY:                                                                                    *
    593  *    8/29/96 4:42PM ST : Created                                                              *
    594  *=============================================================================================*/
    595 void ChronalVortexClass::Attack(void)
    596 {
    597 	int distance;
    598 // if(TargetObject) return;
    599 // if(!TargetObject) return;
    600 	/*
    601 	** Calculate the position of the center of the vortex.
    602 	*/
    603 	int x = Lepton_To_Pixel(Coord_X(Position));
    604 	int y = Lepton_To_Pixel(Coord_Y(Position));
    605 
    606 	x += 32;
    607 	y += 12;
    608 
    609 	LEPTON lx = Pixel_To_Lepton (x);
    610 	LEPTON ly = Pixel_To_Lepton (y);
    611 
    612 	COORDINATE here = XY_Coord (lx, ly);
    613 
    614 	/*
    615 	** Scan through the ground layer objects and see who we should attack
    616 	*/
    617 
    618 	/*
    619 	** First scan - find any object directly above the vortex.
    620 	*/
    621 	for (int i= 0; i < Map.Layer[LAYER_GROUND].Count(); i++) {
    622 		ObjectClass * obj = Map.Layer[LAYER_GROUND][i];
    623 
    624 		if ( obj->Is_Techno() && obj->Strength > 0 ) {
    625 
    626 			distance = Distance (obj->Center_Coord(), here);
    627 
    628 			if (distance <= CELL_LEPTON_W*2) {
    629 				Set_Target (obj);
    630 				break;
    631 			}
    632 		}
    633 	}
    634 
    635 	/*
    636 	** If we found something to attack then just return
    637 	*/
    638 	if (!Target_Legal(TargetObject)) return;
    639 
    640 
    641 	/*
    642 	** Scan through all ground level objects.
    643 	**
    644 	** Objects within range have a chance of being selected based on their distance from the vortex.
    645 	*/
    646 
    647 	int chance = Random_Pick (0, 1000);
    648 	if (chance > Frame - LastAttackFrame) return;
    649 
    650 	for (int i= 0; i < Map.Layer[LAYER_GROUND].Count(); i++) {
    651 		ObjectClass * obj = Map.Layer[LAYER_GROUND][i];
    652 
    653 		if ( obj && obj->Is_Techno() ) {
    654 
    655 			distance = Distance (obj->Center_Coord(), Position);
    656 
    657 			if (distance < CELL_LEPTON_W * Range) {
    658 				chance = Random_Pick (0, distance);
    659 				if (chance < CELL_LEPTON_W) {
    660 					Set_Target (obj);
    661 					break;
    662 				}
    663 			}
    664 		}
    665 	}
    666 }
    667 
    668 
    669 
    670 
    671 /***********************************************************************************************
    672  * CVC::Zap_Target -- If the vortex has a target object then zap it with lightning.            *
    673  *                                                                                             *
    674  *                                                                                             *
    675  *                                                                                             *
    676  * INPUT:    Nothing                                                                           *
    677  *                                                                                             *
    678  * OUTPUT:   Nothing                                                                           *
    679  *                                                                                             *
    680  * WARNINGS: None                                                                              *
    681  *                                                                                             *
    682  * HISTORY:                                                                                    *
    683  *    8/29/96 4:45PM ST : Created                                                              *
    684  *=============================================================================================*/
    685 #define	ZAP_COUNT	1
    686 void ChronalVortexClass::Zap_Target (void)
    687 {
    688 	if (!Hidden && Target_Legal(TargetObject) && ZapFrame < ZAP_COUNT) {
    689 
    690 		/*
    691 		** Get the center of the vortex.
    692 		*/
    693 		int x = Lepton_To_Pixel(Coord_X(Position));
    694 		int y = Lepton_To_Pixel(Coord_Y(Position));
    695 
    696 		x += 32;
    697 		y += 12;
    698 
    699 		LEPTON lx = Pixel_To_Lepton (x);
    700 		LEPTON ly = Pixel_To_Lepton (y);
    701 
    702 		COORDINATE here = XY_Coord (lx, ly);
    703 
    704 		/*
    705 		** Create a temporary techno object se we can access the lightning ability of the tesla.
    706 		*/
    707 		TechnoClass *temptech = new BuildingClass (STRUCT_TESLA, HOUSE_GOOD);
    708 		if (temptech != NULL) {
    709 			temptech->Coord = here;
    710 			ObjectClass * obj = As_Object(TargetObject);
    711 			TARGET target = As_Target (obj->Center_Coord());
    712 			Sound_Effect(VOC_TESLA_ZAP, obj->Center_Coord());
    713 			temptech->Electric_Zap (target, 0, WINDOW_TACTICAL, here, LightningRemap);
    714 			delete temptech;
    715 
    716 			/*
    717 			** Flag the whole map to redraw to cover the lightning.
    718 			*/
    719 			Map.Flag_To_Redraw(true);
    720 
    721 			/*
    722 			** Zap the target 3 times but only do damage on the last frame.
    723 			*/
    724 			ZapFrame++;
    725 
    726 			if (ZapFrame == ZAP_COUNT) {
    727 				ZapFrame = 0;
    728 				int damage = Damage;
    729 				obj->Take_Damage(damage, TargetDistance, WARHEAD_TESLA, NULL, 1);
    730 				TargetObject = TARGET_NONE;
    731 			}
    732 		}
    733 
    734 		/*
    735 		** Vortex might pretend to go away after zapping the target.
    736 		*/
    737 		if (Random_Pick (0,2) == 2) Hide();
    738 	}
    739 }
    740 
    741 
    742 
    743 
    744 
    745 /***********************************************************************************************
    746  * CVC::Coordinate_Remap -- Draws the vortex                                                   *
    747  *                                                                                             *
    748  *                                                                                             *
    749  *                                                                                             *
    750  * INPUT:    ptr to view port to draw the vortex into                                          *
    751  *           x offset                                                                          *
    752  *           y offset                                                                          *
    753  *           width of vortex                                                                   *
    754  *           height of vortex                                                                  *
    755  *           ptr to shading remap tables                                                       *
    756  *                                                                                             *
    757  * OUTPUT:   Nothing                                                                           *
    758  *                                                                                             *
    759  * WARNINGS: None                                                                              *
    760  *                                                                                             *
    761  * HISTORY:                                                                                    *
    762  *    8/29/96 4:48PM ST : Created                                                              *
    763  *=============================================================================================*/
    764 void ChronalVortexClass::Coordinate_Remap ( GraphicViewPortClass *inbuffer, int x, int y, int width, int height, unsigned char *remap_table)
    765 {
    766 	unsigned char	getx,gety, remap_color, pixel_color;
    767 
    768 
    769 	BufferClass destbuf (width * height);
    770 
    771 	unsigned char *destptr = (unsigned char*) destbuf.Get_Buffer();
    772 
    773 	int destx = x;
    774 	int desty = y;
    775 
    776 	int dest_width = width;
    777 	int dest_height = height;
    778 
    779 	if (inbuffer->Lock()) {
    780 
    781 		/*
    782 		** Get a pointer to the section of buffer we are going to work on.
    783 		*/
    784 		unsigned char *bufptr = (unsigned char *) inbuffer->Get_Offset()
    785 															 + destx
    786 #ifdef WIN32
    787 															 + desty* (inbuffer->Get_Width() + inbuffer->Get_XAdd() + inbuffer->Get_Pitch());
    788 #else
    789 															 + desty* (inbuffer->Get_Width() + inbuffer->Get_XAdd());
    790 #endif
    791 
    792 
    793 #ifdef WIN32
    794 		int modulo = inbuffer->Get_Pitch() + inbuffer->Get_XAdd() + inbuffer->Get_Width();
    795 #else
    796 		int modulo = inbuffer->Get_XAdd() + inbuffer->Get_Width();
    797 #endif
    798 
    799 
    800 		for (int yy = desty ; yy < desty+dest_height ; yy++) {
    801 			for (int xx = destx ; xx < destx+dest_width ; xx++) {
    802 				/*
    803 				** Get the coordinates of the pixel to draw
    804 				*/
    805 				getx = *(remap_table++);
    806 				gety = *(remap_table++);
    807 				remap_color = *(remap_table++);
    808 
    809 				pixel_color = * (bufptr + getx + (gety * modulo) );
    810 
    811 				*(destptr++) = VortexRemapTables [remap_color] [pixel_color];
    812 			}
    813 
    814 			remap_table += 3*(width - dest_width);
    815 			destptr += width - dest_width;
    816 
    817 		}
    818 
    819 		destbuf.To_Page(destx, desty, dest_width, dest_height, *inbuffer);
    820 
    821 
    822 		inbuffer->Unlock();
    823 	}
    824 }
    825 
    826 
    827 
    828 /***********************************************************************************************
    829  * CVC::Render -- Renders the vortex at its current position.                                  *
    830  *                                                                                             *
    831  *                                                                                             *
    832  *                                                                                             *
    833  * INPUT:    Nothing                                                                           *
    834  *                                                                                             *
    835  * OUTPUT:   Nothing                                                                           *
    836  *                                                                                             *
    837  * WARNINGS: None                                                                              *
    838  *                                                                                             *
    839  * HISTORY:                                                                                    *
    840  *    8/29/96 4:49PM ST : Created                                                              *
    841  *=============================================================================================*/
    842 void ChronalVortexClass::Render (void)
    843 {
    844 	if (Active && !Hidden) {
    845 		char fname [80];
    846 
    847 		int frame;
    848 
    849 		/*
    850 		** Calculate which coordinate lookup table we should be using for this frame.
    851 		*/
    852 		switch (State) {
    853 			case STATE_GROW:
    854 				frame = 0;
    855 				break;
    856 
    857 			case STATE_ROTATE:
    858 				frame = VORTEX_FRAMES;
    859 				break;
    860 
    861 			case STATE_SHRINK:
    862 				frame = VORTEX_FRAMES*2;
    863 				break;
    864 		}
    865 
    866 		frame += AnimateFrame;
    867 
    868 		sprintf (fname, "HOLE%04d.lut", frame);
    869 
    870 		void const *lut_ptr = MFCD::Retrieve(fname);
    871 		if (lut_ptr) {
    872 
    873 			/*
    874 			** Build a representation of the area of the screen where the vortex will be
    875 			** in an off-screen buffer.
    876 			** This is necessary for clipping as we cant remap pixels from off screen if we build
    877 			** the image from the hidpage.
    878 			*/
    879 			if (!RenderBuffer) {
    880 				RenderBuffer = new GraphicBufferClass(CELL_PIXEL_W * 4, CELL_PIXEL_H * 4, (void*)NULL);
    881 			}
    882 			CELL xc = Coord_XCell (Position);
    883 			CELL yc = Coord_YCell (Position);
    884 			CellClass *cellptr;
    885 			CELL cell;
    886 			TemplateTypeClass const * ttype = 0;
    887 			int	icon;		// The icon number to use from the template set.
    888 
    889 
    890 #ifdef WIN32
    891 			GraphicViewPortClass * oldpage = Set_Logic_Page(RenderBuffer);
    892 #else
    893 			GraphicBufferClass * oldpage = Set_Logic_Page(RenderBuffer);
    894 #endif
    895 
    896 			/*
    897 			** Temporarily modify the tactical window so it works with our offscreen buffer
    898 			*/
    899 			int wx = WindowList[WINDOW_TACTICAL][WINDOWX];
    900 			int wy = WindowList[WINDOW_TACTICAL][WINDOWY];
    901 			int ww = WindowList[WINDOW_TACTICAL][WINDOWWIDTH];
    902 			int wh = WindowList[WINDOW_TACTICAL][WINDOWHEIGHT];
    903 
    904 			WindowList[WINDOW_TACTICAL][WINDOWX] = 0;
    905 			WindowList[WINDOW_TACTICAL][WINDOWY] = 0;
    906 			WindowList[WINDOW_TACTICAL][WINDOWWIDTH] = RenderBuffer->Get_Width();
    907 			WindowList[WINDOW_TACTICAL][WINDOWHEIGHT] = RenderBuffer->Get_Height();
    908 
    909 
    910 			/*
    911 			** Loop through all the cells that the vortex overlaps and render the template, smudge
    912 			** and overlay for each cell.
    913 			*/
    914 			for (int y = 0 ; y<4 ; y++) {
    915 				for (int x = 0 ; x<4 ; x++) {
    916 
    917 					cell = XY_Cell (xc+x,yc+y);
    918 					if (cell != -1) {
    919 
    920 						//cellptr = &Map[ Coord_Whole (Cell_Coord(cell)) ];
    921 						cellptr = &Map [cell];
    922 
    923 						/*
    924 						**	Fetch a pointer to the template type associated with this cell.
    925 						*/
    926 						if (cellptr->TType != TEMPLATE_NONE && cellptr->TType != TEMPLATE_CLEAR1 && cellptr->TType != 255) {
    927 							ttype = &TemplateTypeClass::As_Reference(cellptr->TType);
    928 							icon = cellptr->TIcon;
    929 						} else {
    930 							ttype = &TemplateTypeClass::As_Reference(TEMPLATE_CLEAR1);
    931 							icon = cellptr->Clear_Icon();
    932 						}
    933 
    934 						/*
    935 						** Draw the template
    936 						*/
    937 						if (ttype->Get_Image_Data()) {
    938 							RenderBuffer->Draw_Stamp(ttype->Get_Image_Data(), icon, x*CELL_PIXEL_W, y*CELL_PIXEL_H, NULL, WINDOW_MAIN);
    939 						}
    940 
    941 						/*
    942 						**	Draw any smudge.
    943 						*/
    944 						if (cellptr->Smudge != SMUDGE_NONE) {
    945 							SmudgeTypeClass::As_Reference(cellptr->Smudge).Draw_It(x*CELL_PIXEL_W, y*CELL_PIXEL_H, cellptr->SmudgeData);
    946 						}
    947 
    948 						/*
    949 						**	Draw the overlay object.
    950 						*/
    951 						if (cellptr->Overlay != OVERLAY_NONE) {
    952 							OverlayTypeClass const & otype = OverlayTypeClass::As_Reference(cellptr->Overlay);
    953 							IsTheaterShape = (bool)otype.IsTheater;	//Tell Build_Frame if this overlay is theater specific
    954 							CC_Draw_Shape(otype.Get_Image_Data(),
    955 												cellptr->OverlayData,
    956 												x*CELL_PIXEL_W + (CELL_PIXEL_W >> 1),
    957 												y*CELL_PIXEL_H + (CELL_PIXEL_H >> 1),
    958 												WINDOW_TACTICAL,
    959 												SHAPE_CENTER|SHAPE_WIN_REL|SHAPE_GHOST,
    960 												NULL,
    961 												DisplayClass::UnitShadow);
    962 
    963 							IsTheaterShape = false;
    964 						}
    965 
    966 						/*
    967 						**	Draw the flag if there is one located at this cell.
    968 						*/
    969 						if (cellptr->IsFlagged) {
    970 							void const * flag_remap = HouseClass::As_Pointer(cellptr->Owner)->Remap_Table(false, REMAP_NORMAL);
    971 							CC_Draw_Shape(MFCD::Retrieve("FLAGFLY.SHP"), Frame % 14, x+(ICON_PIXEL_W/2), y+(ICON_PIXEL_H/2), WINDOW_TACTICAL, SHAPE_CENTER|SHAPE_GHOST|SHAPE_FADING, flag_remap, DisplayClass::UnitShadow);
    972 						}
    973 					}
    974 				}
    975 			}
    976 
    977 
    978 			Set_Logic_Page(oldpage);
    979 
    980 			/*
    981 			** Restore the tactical window to its correct value
    982 			*/
    983 			WindowList[WINDOW_TACTICAL][WINDOWX] = wx;
    984 			WindowList[WINDOW_TACTICAL][WINDOWY] = wy;
    985 			WindowList[WINDOW_TACTICAL][WINDOWWIDTH] = ww;
    986 			WindowList[WINDOW_TACTICAL][WINDOWHEIGHT] = wh;
    987 
    988 			/*
    989 			** Render the vortex over the cells we just rendered to our buffer
    990 			*/
    991 			Coordinate_Remap (RenderBuffer, Lepton_To_Pixel(Coord_X(Coord_Fraction(Position))),
    992 											Lepton_To_Pixel(Coord_Y(Coord_Fraction(Position))),
    993 											64,
    994 											64,
    995 											(unsigned char*) lut_ptr);
    996 
    997 
    998 			/*
    999 			** Calculate the pixel position of our fresh block of cells on the tactical map so
   1000 			**	we can blit it to the hid page.
   1001 			*/
   1002 			COORDINATE render_pos = XY_Coord(xc * CELL_LEPTON_W, yc * CELL_LEPTON_H);	//Coord_Whole(Position);
   1003 
   1004 			int x, y;
   1005 			Map.Coord_To_Pixel(render_pos, x, y);
   1006 
   1007 			/*
   1008 			** Create a view port to blit to
   1009 			*/
   1010 			GraphicViewPortClass target (LogicPage->Get_Graphic_Buffer(),
   1011 													0,
   1012 													LogicPage->Get_YPos(),
   1013 													Lepton_To_Pixel (Map.TacLeptonWidth),
   1014 													Lepton_To_Pixel (Map.TacLeptonHeight));
   1015 
   1016 
   1017 			/*
   1018 			** Do some clipping since the library clipping gets it wrong.
   1019 			*/
   1020 			int diff;
   1021 
   1022 			int source_x = 0;
   1023 			int source_y = 0;
   1024 			int source_width = CELL_PIXEL_W*4;
   1025 			int source_height = CELL_PIXEL_H*4;
   1026 
   1027 			int dest_x = x;
   1028 			int dest_y = y;
   1029 			int dest_width = source_width;
   1030 			int dest_height = source_height;
   1031 
   1032 			if (dest_x < 0) {
   1033 				source_width += dest_x;
   1034 				dest_width += dest_x;
   1035 				source_x -= dest_x;
   1036 				dest_x = 0;
   1037 			}
   1038 
   1039 			if (dest_y <0) {
   1040 				source_height += dest_y;
   1041 				dest_height += dest_y;
   1042 				source_y -= dest_y;
   1043 				dest_y = 0;
   1044 			}
   1045 
   1046 			if (dest_x + dest_width > target.Get_Width() ) {
   1047 				diff = dest_x + dest_width - target.Get_Width();
   1048 				dest_width -= diff;
   1049 				source_width -= diff;
   1050 			}
   1051 
   1052 			if (dest_y + dest_height > target.Get_Height() ) {
   1053 				diff = dest_y + dest_height - target.Get_Height();
   1054 				dest_height -= diff;
   1055 				source_height -= diff;
   1056 			}
   1057 
   1058 
   1059 			/*
   1060 			** Blit our freshly draw cells and vortex into their correct position on the hidpage
   1061 			*/
   1062 			if (dest_width > 0 && dest_height > 0) {
   1063 				RenderBuffer->Blit (target, source_x, source_y, dest_x, dest_y, dest_width, dest_height, false);
   1064 			}
   1065 
   1066 		}
   1067 	}
   1068 }
   1069 
   1070 
   1071 
   1072 /***********************************************************************************************
   1073  * CVC::Set_Redraw -- Flags the cells under to vortex to redraw.                               *
   1074  *                                                                                             *
   1075  *                                                                                             *
   1076  *                                                                                             *
   1077  * INPUT:    Nothing                                                                           *
   1078  *                                                                                             *
   1079  * OUTPUT:   Nothing                                                                           *
   1080  *                                                                                             *
   1081  * WARNINGS: None                                                                              *
   1082  *                                                                                             *
   1083  * HISTORY:                                                                                    *
   1084  *    8/29/96 4:50PM ST : Created                                                              *
   1085  *=============================================================================================*/
   1086 void ChronalVortexClass::Set_Redraw(void)
   1087 {
   1088 
   1089 	if (Active) {
   1090 
   1091 		CELL xc = Coord_XCell (Position);
   1092 		CELL yc = Coord_YCell (Position);
   1093 
   1094 		CELL cell;
   1095 
   1096 		for (int y = MAX(0,yc - 1) ; y< yc+4 ; y++) {
   1097 			for (int x = MAX(0, xc-1) ; x< xc + 4 ; x++) {
   1098 				cell = XY_Cell (x,y);
   1099 				if (cell != -1) {
   1100 					Map[cell].Redraw_Objects();
   1101 				}
   1102 			}
   1103 		}
   1104 	}
   1105 }
   1106 
   1107 
   1108 
   1109 
   1110 /***********************************************************************************************
   1111  * CVC::Setup_Remap_Tables -- Initialises the color remap tables based on theater.             *
   1112  *                                                                                             *
   1113  *                                                                                             *
   1114  *                                                                                             *
   1115  * INPUT:    Theater                                                                           *
   1116  *                                                                                             *
   1117  * OUTPUT:   Nothing                                                                           *
   1118  *                                                                                             *
   1119  * WARNINGS: None                                                                              *
   1120  *                                                                                             *
   1121  * HISTORY:                                                                                    *
   1122  *    8/29/96 4:51PM ST : Created                                                              *
   1123  *=============================================================================================*/
   1124 void ChronalVortexClass::Setup_Remap_Tables (TheaterType theater)
   1125 {
   1126 	/*
   1127 	** The names of the remap files for each theater
   1128 	*/
   1129 	static char _remaps[3][13] ={
   1130 		"TEMP_VTX.PAL",
   1131 		"SNOW_VTX.PAL",
   1132 		"INTR_VTX.PAL"
   1133 	};
   1134 
   1135 	int i;
   1136 
   1137 	/*
   1138 	** If the theater has changed then load the remap tables from disk if they exist or create
   1139 	** them if they dont.
   1140 	*/
   1141 	if (theater != Theater) {
   1142 
   1143 		Theater = theater;
   1144 
   1145 		CCFileClass file (_remaps[(int)Theater]);
   1146 
   1147 		if (file.Is_Available()) {
   1148 			file.Read (VortexRemapTables, MAX_REMAP_SHADES*256);
   1149 		} else {
   1150 
   1151 			for (i=0 ; i<MAX_REMAP_SHADES ; i++) {
   1152 				Build_Fading_Table ( GamePalette, &VortexRemapTables[i][0], 0, 240- ((i*256)/MAX_REMAP_SHADES) );
   1153 			}
   1154 
   1155 			file.Write (VortexRemapTables, MAX_REMAP_SHADES*256);
   1156 		}
   1157 	}
   1158 
   1159 	/*
   1160 	** Set up the remap table for the lightning
   1161 	*/
   1162 	for (i=0 ; i<256 ; i++) {
   1163 		LightningRemap[i] = i;
   1164 	}
   1165 	LightningRemap[192] = 208;
   1166 	LightningRemap[193] = 209;
   1167 	LightningRemap[194] = 210;
   1168 	LightningRemap[195] = 211;
   1169 	LightningRemap[196] = 212;
   1170 	LightningRemap[197] = 213;
   1171 	LightningRemap[198] = 214;
   1172 	LightningRemap[199] = 215;
   1173 }
   1174 
   1175 
   1176 
   1177 
   1178 /***********************************************************************************************
   1179  * CVC::Build_Fading_Table -- Builds a fading color lookup table.                              *
   1180  *                                                                                             *
   1181  *                                                                                             *
   1182  *                                                                                             *
   1183  * INPUT:    ptr to palette to base tables on                                                  *
   1184  *           ptr to buffer to put clut in.                                                     *
   1185  *           color to bias colors to                                                           *
   1186  *           percentage of bias                                                                *
   1187  *                                                                                             *
   1188  * OUTPUT:   Nothing                                                                           *
   1189  *                                                                                             *
   1190  * WARNINGS: Based on Conquer_Build_Fading_Table                                               *
   1191  *                                                                                             *
   1192  * HISTORY:                                                                                    *
   1193  *    8/29/96 4:53PM ST : Created                                                              *
   1194  *=============================================================================================*/
   1195 void ChronalVortexClass::Build_Fading_Table(PaletteClass const & palette, void * dest, int color, int frac)
   1196 {
   1197 	if (dest) {
   1198 		unsigned char * ptr = (unsigned char *)dest;
   1199 
   1200 		/*
   1201 		**	Find an appropriate remap color index for every color in the palette.
   1202 		**	There are certain exceptions to this, but they are trapped within the
   1203 		**	loop.
   1204 		*/
   1205 		for (int index = 0; index < PaletteClass::COLOR_COUNT; index++) {
   1206 
   1207 			/*
   1208 			**	If this color should not be remapped, then it will be stored as a remap
   1209 			**	to itself. This is effectively no remap.
   1210 			*/
   1211 			if (index == 0 ||
   1212 				 (index >= CYCLE_COLOR_START && index < (CYCLE_COLOR_START + CYCLE_COLOR_COUNT)) ||
   1213 				 index == CC_PULSE_COLOR ||
   1214 				 index == CC_EMBER_COLOR) {
   1215 				*ptr++ = index;
   1216 			} else {
   1217 
   1218 				/*
   1219 				**	Find the color that, ideally, the working color should be remapped
   1220 				**	to in the special remap range.
   1221 				*/
   1222 				RGBClass trycolor = palette[index];
   1223 				trycolor.Adjust(frac, palette[color]);			// Try to match this color.
   1224 
   1225 				/*
   1226 				**	Search through the remap range to find the color that should be remapped
   1227 				**	to.
   1228 				*/
   1229 				int best = -1;
   1230 				int bvalue = 0;
   1231 				for (int id = 0; id < PaletteClass::COLOR_COUNT; id++) {
   1232 
   1233 					if (id != 0 &&
   1234 						(id < CYCLE_COLOR_START || id >= (CYCLE_COLOR_START + CYCLE_COLOR_COUNT)) &&
   1235 						 id != CC_PULSE_COLOR &&
   1236 						 id != CC_EMBER_COLOR) {
   1237 
   1238 						int diff = palette[id].Difference(trycolor);
   1239 						if (best == -1 || diff < bvalue) {
   1240 							best = id;
   1241 							bvalue = diff;
   1242 						}
   1243 					}
   1244 				}
   1245 				*ptr++ = best;
   1246 			}
   1247 		}
   1248 	}
   1249 }
   1250 
   1251 
   1252 void ChronalVortexClass::Detach(TARGET target)
   1253 {
   1254 	if (Target_Legal(target) && target == TargetObject) {
   1255 		Set_Target(NULL);
   1256 	}
   1257 }