| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258 |
- /*
- ** Command & Conquer Red Alert(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /*************************************************************************************
- ** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S **
- *************************************************************************************
- * *
- * Project Name : Command & Conquer - Red Alert *
- * *
- * File Name : VORTEX.CPP *
- * *
- * Programmer : Steve Tall *
- * *
- * Start Date : August 12th, 1996 *
- * *
- * Last Update : September 6th, 1996 [ST] *
- * *
- *-----------------------------------------------------------------------------------*
- * Overview: *
- * *
- * Circley vortexy swirly type thing. (Really just a pixel & color remap). *
- * *
- *-----------------------------------------------------------------------------------*
- * Functions: *
- * *
- * CVC::ChronalVortexClass -- vortex class constructor *
- * CVC::~ChronalVortexClass -- vortex class destructor *
- * CVC::Appear -- Makes a chronal vortex appear at the given coordinate. *
- * CVC::Disappear -- Makes the chronal vortex go away. *
- * CVC::Hide -- Makes the vortex hide. It might come back later. *
- * CVC::Show -- Makes a hidden vortex visible again. *
- * CVC::Stop -- Stops the vortex without going through the hide animation *
- * CVC::Load -- Loads the chronal vortex from a savegame file. *
- * CVC::Save -- Saves the vortex class data to a savegame file *
- * CVC::AI -- AI for the vortex. Includes movement and firing. *
- * CVC::Movement -- Movement AI for the vortex. *
- * CVC::Set_Target -- Make the vortex zap a particular object. *
- * CVC::Attack -- look for objects to attack *
- * CVC::Zap_Target -- If the vortex has a target object then zap it with lightning. *
- * CVC::Coordinate_Remap -- Draws the vortex *
- * CVC::Render -- Renders the vortex at its current position. *
- * CVC::Set_Redraw -- Flags the cells under to vortex to redraw. *
- * CVC::Setup_Remap_Tables -- Initialises the color remap tables based on theater. *
- * CVC::Build_Fading_Table -- Builds a fading color lookup table. *
- * *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "function.h"
- #include "vortex.h"
- /*
- ** Instance of chronal vortex class. This must be the only instance.
- */
- ChronalVortexClass ChronalVortex;
- /***********************************************************************************************
- * CVC::ChronalVortexClass -- vortex class constructor *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/29/96 4:25PM ST : Created *
- *=============================================================================================*/
- ChronalVortexClass::ChronalVortexClass (void)
- {
- Active = 0;
- Theater = THEATER_NONE;
- Speed = 10;
- Range = 10;
- Damage = 200;
- RenderBuffer = NULL; //We havn't allocated it yet. It will be allocated as needed.
- }
- /***********************************************************************************************
- * CVC::~ChronalVortexClass -- vortex class destructor *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/29/96 4:25PM ST : Created *
- *=============================================================================================*/
- ChronalVortexClass::~ChronalVortexClass (void)
- {
- if (RenderBuffer) delete RenderBuffer;
- Active = 0;
- }
- /***********************************************************************************************
- * CVC::Appear -- Makes a chronal vortex appear at the given coordinate. *
- * *
- * *
- * *
- * INPUT: Coordinate that vortex should appear at. *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: This member does nothing if the vortex is already active *
- * *
- * HISTORY: *
- * 8/29/96 4:27PM ST : Created *
- *=============================================================================================*/
- void ChronalVortexClass::Appear (COORDINATE coordinate)
- {
- if (Active) return;
- /*
- ** Adjust the given coordinate so the vortex appears in a central position
- */
- int x = Lepton_To_Pixel(Coord_X(coordinate));
- int y = Lepton_To_Pixel(Coord_Y(coordinate));
- x -= 32;
- y -= 32;
- LEPTON lx = Pixel_To_Lepton (x);
- LEPTON ly = Pixel_To_Lepton (y);
- Position = XY_Coord (lx, ly);
- /*
- ** Initialise the vortex variables.
- */
- AnimateDir = 1;
- AnimateFrame = 0;
- State = STATE_GROW;
- Active = true;
- Animate = 0;
- StartShutdown = false;
- LastAttackFrame= Frame;
- TargetObject = TARGET_NONE;
- ZapFrame = 0;
- Hidden = false;
- StartHiding = false;
- XDir = 0;
- YDir = 0;
- /*
- ** Vortex starts off in a random direction.
- */
- DesiredXDir = Random_Pick (-Speed, Speed);
- DesiredYDir = Random_Pick (-Speed, Speed);
- }
- /***********************************************************************************************
- * CVC::Disappear -- Makes the chronal vortex go away. *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/29/96 4:30PM ST : Created *
- *=============================================================================================*/
- void ChronalVortexClass::Disappear (void)
- {
- if (Hidden) {
- Active = false;
- } else {
- StartShutdown = true;
- }
- }
- /***********************************************************************************************
- * CVC::Hide -- Makes the vortex hide. It might come back later. *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: This doesnt deactivate the vortex. Use Disappear to get rid of it permanently. *
- * *
- * HISTORY: *
- * 8/29/96 4:30PM ST : Created *
- *=============================================================================================*/
- void ChronalVortexClass::Hide (void)
- {
- if (!StartShutdown) {
- StartHiding = true;
- }
- }
- /***********************************************************************************************
- * CVC::Show -- Makes a hidden vortex visible again. *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/29/96 4:31PM ST : Created *
- *=============================================================================================*/
- void ChronalVortexClass::Show (void)
- {
- /*
- ** Dont do anything if vortx is dying.
- */
- if (!StartShutdown) {
- /*
- ** If the vortex is hidden then show it again.
- */
- if (Hidden) {
- Hidden = false;
- StartHiding = false;
- AnimateFrame = 0;
- State = STATE_GROW;
- XDir = 0;
- YDir = 0;
- } else {
- /*
- ** If the vortex is in the process of hiding then reverse it.
- */
- StartHiding = false;
- if (State == STATE_SHRINK) {
- State = STATE_GROW;
- AnimateFrame = VORTEX_FRAMES - AnimateFrame;
- }
- }
- }
- }
- /***********************************************************************************************
- * CVC::Stop -- Stops the vortex without going through the hide animation *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/29/96 4:32PM ST : Created *
- *=============================================================================================*/
- void ChronalVortexClass::Stop(void)
- {
- if (Active) Active = false;
- }
- /***********************************************************************************************
- * CVC::Load -- Loads the chronal vortex from a savegame file. *
- * *
- * *
- * *
- * INPUT: ptr to file *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/29/96 4:32PM ST : Created *
- *=============================================================================================*/
- void ChronalVortexClass::Load(Straw &file)
- {
- /*
- ** Delete the render buffer as we are going to lose the pointer anyway.
- ** It will be re-allocated when needed.
- */
- if (RenderBuffer) delete RenderBuffer;
- file.Get (this, sizeof (ChronalVortexClass));
- }
- /***********************************************************************************************
- * CVC::Save -- Saves the vortex class data to a savegame file *
- * *
- * *
- * *
- * INPUT: file *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/29/96 4:33PM ST : Created *
- *=============================================================================================*/
- void ChronalVortexClass::Save(Pipe &file)
- {
- GraphicBufferClass *save_ptr = NULL;
- if (RenderBuffer){
- /*
- ** Save the ptr to the render buffer so we can null it for the save
- */
- save_ptr = RenderBuffer;
- RenderBuffer = NULL;
- }
- file.Put (this, sizeof (ChronalVortexClass));
- /*
- ** Restore the render buffer ptr
- */
- if (save_ptr){
- RenderBuffer = save_ptr;
- }
- }
- /***********************************************************************************************
- * CVC::AI -- AI for the vortex. Includes movement and firing. *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/29/96 4:34PM ST : Created *
- *=============================================================================================*/
- void ChronalVortexClass::AI(void)
- {
- int chance;
- /*
- ** No AI if vortex isnt active
- */
- if (Active) {
- /*
- ** Do the movement AI
- */
- Movement();
- /*
- ** Do the attack AI
- */
- Zap_Target();
- if (Hidden && (Frame - HiddenFrame > 50) ) {
- /*
- ** Vortex is hidden. Chance of it showing itself increases the longer its stays hidden.
- */
- chance = Random_Pick(0,2000);
- if (chance <= Frame - HiddenFrame) {
- Show();
- }
- } else {
- if (Animate == 0) {
- /*
- ** Its time to animate the vortex.
- */
- AnimateFrame += AnimateDir;
- if (AnimateFrame > VORTEX_FRAMES) {
- /*
- ** State changes can only occur on final animation frames.
- */
- AnimateFrame = 1;
- if (StartShutdown) {
- /*
- ** Vortex is in the process of dying.
- */
- if (State == STATE_SHRINK) {
- Set_Redraw();
- Active = false;
- AnimateFrame = 0;
- } else {
- Attack();
- State = STATE_SHRINK;
- }
- } else {
- if (StartHiding) {
- /*
- ** Vortex wants to hide.
- */
- if (State == STATE_SHRINK) {
- /*
- ** Hide the vortex now.
- */
- Set_Redraw();
- StartHiding = false;
- Hidden = true;
- HiddenFrame = Frame;
- if (Random_Pick(0,4) == 4) {
- Disappear();
- }
- } else {
- /*
- ** Start hiding the vortex.
- */
- Attack();
- State = STATE_SHRINK;
- }
- } else {
- Attack();
- if (State == STATE_GROW) {
- State = STATE_ROTATE;
- } else {
- //Attack();
- }
- }
- }
- } else {
- if (AnimateFrame == VORTEX_FRAMES / 2) Attack();
- }
- }
- Animate++;
- Animate &= 1;
- }
- }
- }
- /***********************************************************************************************
- * CVC::Movement -- Movement AI for the vortex. *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/29/96 4:39PM ST : Created *
- *=============================================================================================*/
- void ChronalVortexClass::Movement (void)
- {
- bool newpick = true;
- /*
- ** Update the vortex position by applying the x and y direction variables
- */
- LEPTON x = Coord_X(Position);
- LEPTON y = Coord_Y(Position);
- x += XDir;
- y += YDir;
- Position = XY_Coord (x,y);
- /*
- ** Reverse the direction of the vortex if its drifting off the map.
- */
- if (x > CELL_LEPTON_W *(Map.MapCellX + Map.MapCellWidth -4)) {
- newpick = false;
- if (DesiredXDir >0 ) DesiredXDir = -DesiredXDir;
- }
- if (y > CELL_LEPTON_H *(Map.MapCellY + Map.MapCellHeight -4)) {
- newpick = false;
- if (DesiredYDir >0 ) DesiredYDir = -DesiredYDir;
- }
- if (x < CELL_LEPTON_W *Map.MapCellX + 2*CELL_LEPTON_W) {
- newpick = false;
- if (DesiredXDir <0 ) DesiredXDir = -DesiredXDir;
- }
- if (y < CELL_LEPTON_H *Map.MapCellY + 2*CELL_LEPTON_W) {
- newpick = false;
- if (DesiredYDir <0 ) DesiredYDir = -DesiredYDir;
- }
- /*
- ** Vortex direction tends towards the desired direction unless the vortex is shutting down or
- ** appearing in which case the direction tends towards 0.
- */
- if (State == STATE_ROTATE || Hidden) {
- if (XDir < DesiredXDir) XDir ++;
- if (XDir > DesiredXDir) XDir --;
- if (YDir < DesiredYDir) YDir ++;
- if (YDir > DesiredYDir) YDir --;
- } else {
- if (XDir > 0) XDir -= Speed/8;
- if (XDir < 0) XDir += Speed/8;
- if (YDir > 0) YDir -= Speed/8;
- if (YDir < 0) YDir += Speed/8;
- }
- /*
- ** Occasionally change the direction of the vortex.
- */
- if (newpick && Random_Pick (0, 100) == 100) {
- DesiredXDir = Random_Pick (-Speed, Speed);
- DesiredYDir = Random_Pick (-Speed, Speed);
- }
- }
- /***********************************************************************************************
- * CVC::Set_Target -- Make the vortex zap a particular object. *
- * *
- * *
- * *
- * INPUT: ptr to object to zap *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/29/96 4:42PM ST : Created *
- *=============================================================================================*/
- void ChronalVortexClass::Set_Target (ObjectClass *target)
- {
- if (Active){
- ZapFrame = 0;
- TargetObject = TARGET_NONE;
- if (target != NULL) TargetObject = target->As_Target();
- LastAttackFrame = Frame;
- TargetDistance = (target != NULL) ? Distance (target->Center_Coord(), Position) : 0;
- }
- }
- /***********************************************************************************************
- * CVC::Attack -- look for objects to attack *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/29/96 4:42PM ST : Created *
- *=============================================================================================*/
- void ChronalVortexClass::Attack(void)
- {
- int distance;
- // if(TargetObject) return;
- // if(!TargetObject) return;
- /*
- ** Calculate the position of the center of the vortex.
- */
- int x = Lepton_To_Pixel(Coord_X(Position));
- int y = Lepton_To_Pixel(Coord_Y(Position));
- x += 32;
- y += 12;
- LEPTON lx = Pixel_To_Lepton (x);
- LEPTON ly = Pixel_To_Lepton (y);
- COORDINATE here = XY_Coord (lx, ly);
- /*
- ** Scan through the ground layer objects and see who we should attack
- */
- /*
- ** First scan - find any object directly above the vortex.
- */
- for (unsigned i= 0; i < Map.Layer[LAYER_GROUND].Count(); i++) {
- ObjectClass * obj = Map.Layer[LAYER_GROUND][i];
- if ( obj->Is_Techno() && obj->Strength > 0 ) {
- distance = Distance (obj->Center_Coord(), here);
- if (distance <= CELL_LEPTON_W*2) {
- Set_Target (obj);
- break;
- }
- }
- }
- /*
- ** If we found something to attack then just return
- */
- if (!Target_Legal(TargetObject)) return;
- /*
- ** Scan through all ground level objects.
- **
- ** Objects within range have a chance of being selected based on their distance from the vortex.
- */
- int chance = Random_Pick (0, 1000);
- if (chance > Frame - LastAttackFrame) return;
- for (i= 0; i < Map.Layer[LAYER_GROUND].Count(); i++) {
- ObjectClass * obj = Map.Layer[LAYER_GROUND][i];
- if ( obj && obj->Is_Techno() ) {
- distance = Distance (obj->Center_Coord(), Position);
- if (distance < CELL_LEPTON_W * Range) {
- chance = Random_Pick (0, distance);
- if (chance < CELL_LEPTON_W) {
- Set_Target (obj);
- break;
- }
- }
- }
- }
- }
- /***********************************************************************************************
- * CVC::Zap_Target -- If the vortex has a target object then zap it with lightning. *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/29/96 4:45PM ST : Created *
- *=============================================================================================*/
- #define ZAP_COUNT 1
- void ChronalVortexClass::Zap_Target (void)
- {
- if (!Hidden && Target_Legal(TargetObject) && ZapFrame < ZAP_COUNT) {
- /*
- ** Get the center of the vortex.
- */
- int x = Lepton_To_Pixel(Coord_X(Position));
- int y = Lepton_To_Pixel(Coord_Y(Position));
- x += 32;
- y += 12;
- LEPTON lx = Pixel_To_Lepton (x);
- LEPTON ly = Pixel_To_Lepton (y);
- COORDINATE here = XY_Coord (lx, ly);
- /*
- ** Create a temporary techno object se we can access the lightning ability of the tesla.
- */
- TechnoClass *temptech = new BuildingClass (STRUCT_TESLA, HOUSE_GOOD);
- if (temptech != NULL) {
- temptech->Coord = here;
- ObjectClass * obj = As_Object(TargetObject);
- TARGET target = As_Target (obj->Center_Coord());
- Sound_Effect(VOC_TESLA_ZAP, obj->Center_Coord());
- temptech->Electric_Zap (target, 0, here, LightningRemap);
- delete temptech;
- /*
- ** Flag the whole map to redraw to cover the lightning.
- */
- Map.Flag_To_Redraw(true);
- /*
- ** Zap the target 3 times but only do damage on the last frame.
- */
- ZapFrame++;
- if (ZapFrame == ZAP_COUNT) {
- ZapFrame = 0;
- int damage = Damage;
- obj->Take_Damage(damage, TargetDistance, WARHEAD_TESLA, NULL, 1);
- TargetObject = TARGET_NONE;
- }
- }
- /*
- ** Vortex might pretend to go away after zapping the target.
- */
- if (Random_Pick (0,2) == 2) Hide();
- }
- }
- /***********************************************************************************************
- * CVC::Coordinate_Remap -- Draws the vortex *
- * *
- * *
- * *
- * INPUT: ptr to view port to draw the vortex into *
- * x offset *
- * y offset *
- * width of vortex *
- * height of vortex *
- * ptr to shading remap tables *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/29/96 4:48PM ST : Created *
- *=============================================================================================*/
- void ChronalVortexClass::Coordinate_Remap ( GraphicViewPortClass *inbuffer, int x, int y, int width, int height, unsigned char *remap_table)
- {
- unsigned char getx,gety, remap_color, pixel_color;
- BufferClass destbuf (width * height);
- unsigned char *destptr = (unsigned char*) destbuf.Get_Buffer();
- int destx = x;
- int desty = y;
- int dest_width = width;
- int dest_height = height;
- if (inbuffer->Lock()) {
- /*
- ** Get a pointer to the section of buffer we are going to work on.
- */
- unsigned char *bufptr = (unsigned char *) inbuffer->Get_Offset()
- + destx
- #ifdef WIN32
- + desty* (inbuffer->Get_Width() + inbuffer->Get_XAdd() + inbuffer->Get_Pitch());
- #else
- + desty* (inbuffer->Get_Width() + inbuffer->Get_XAdd());
- #endif
- #ifdef WIN32
- int modulo = inbuffer->Get_Pitch() + inbuffer->Get_XAdd() + inbuffer->Get_Width();
- #else
- int modulo = inbuffer->Get_XAdd() + inbuffer->Get_Width();
- #endif
- for (int yy = desty ; yy < desty+dest_height ; yy++) {
- for (int xx = destx ; xx < destx+dest_width ; xx++) {
- /*
- ** Get the coordinates of the pixel to draw
- */
- getx = *(remap_table++);
- gety = *(remap_table++);
- remap_color = *(remap_table++);
- pixel_color = * (bufptr + getx + (gety * modulo) );
- *(destptr++) = VortexRemapTables [remap_color] [pixel_color];
- }
- remap_table += 3*(width - dest_width);
- destptr += width - dest_width;
- }
- destbuf.To_Page(destx, desty, dest_width, dest_height, *inbuffer);
- inbuffer->Unlock();
- }
- }
- /***********************************************************************************************
- * CVC::Render -- Renders the vortex at its current position. *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/29/96 4:49PM ST : Created *
- *=============================================================================================*/
- void ChronalVortexClass::Render (void)
- {
- if (Active && !Hidden) {
- char fname [80];
- int frame;
- /*
- ** Calculate which coordinate lookup table we should be using for this frame.
- */
- switch (State) {
- case STATE_GROW:
- frame = 0;
- break;
- case STATE_ROTATE:
- frame = VORTEX_FRAMES;
- break;
- case STATE_SHRINK:
- frame = VORTEX_FRAMES*2;
- break;
- }
- frame += AnimateFrame;
- sprintf (fname, "HOLE%04d.lut", frame);
- void const *lut_ptr = MFCD::Retrieve(fname);
- if (lut_ptr) {
- /*
- ** Build a representation of the area of the screen where the vortex will be
- ** in an off-screen buffer.
- ** This is necessary for clipping as we cant remap pixels from off screen if we build
- ** the image from the hidpage.
- */
- if (!RenderBuffer) {
- RenderBuffer = new GraphicBufferClass(CELL_PIXEL_W * 4, CELL_PIXEL_H * 4, (void*)NULL);
- }
- CELL xc = Coord_XCell (Position);
- CELL yc = Coord_YCell (Position);
- CellClass *cellptr;
- CELL cell;
- TemplateTypeClass const * ttype = 0;
- int icon; // The icon number to use from the template set.
- #ifdef WIN32
- GraphicViewPortClass * oldpage = Set_Logic_Page(RenderBuffer);
- #else
- GraphicBufferClass * oldpage = Set_Logic_Page(RenderBuffer);
- #endif
- /*
- ** Temporarily modify the tactical window so it works with our offscreen buffer
- */
- int wx = WindowList[WINDOW_TACTICAL][WINDOWX];
- int wy = WindowList[WINDOW_TACTICAL][WINDOWY];
- int ww = WindowList[WINDOW_TACTICAL][WINDOWWIDTH];
- int wh = WindowList[WINDOW_TACTICAL][WINDOWHEIGHT];
- WindowList[WINDOW_TACTICAL][WINDOWX] = 0;
- WindowList[WINDOW_TACTICAL][WINDOWY] = 0;
- WindowList[WINDOW_TACTICAL][WINDOWWIDTH] = RenderBuffer->Get_Width();
- WindowList[WINDOW_TACTICAL][WINDOWHEIGHT] = RenderBuffer->Get_Height();
- /*
- ** Loop through all the cells that the vortex overlaps and render the template, smudge
- ** and overlay for each cell.
- */
- for (int y = 0 ; y<4 ; y++) {
- for (int x = 0 ; x<4 ; x++) {
- cell = XY_Cell (xc+x,yc+y);
- if (cell != -1) {
- //cellptr = &Map[ Coord_Whole (Cell_Coord(cell)) ];
- cellptr = &Map [cell];
- /*
- ** Fetch a pointer to the template type associated with this cell.
- */
- if (cellptr->TType != TEMPLATE_NONE && cellptr->TType != TEMPLATE_CLEAR1 && cellptr->TType != 255) {
- ttype = &TemplateTypeClass::As_Reference(cellptr->TType);
- icon = cellptr->TIcon;
- } else {
- ttype = &TemplateTypeClass::As_Reference(TEMPLATE_CLEAR1);
- icon = cellptr->Clear_Icon();
- }
- /*
- ** Draw the template
- */
- if (ttype->Get_Image_Data()) {
- RenderBuffer->Draw_Stamp(ttype->Get_Image_Data(), icon, x*CELL_PIXEL_W, y*CELL_PIXEL_H, NULL, WINDOW_MAIN);
- }
- /*
- ** Draw any smudge.
- */
- if (cellptr->Smudge != SMUDGE_NONE) {
- SmudgeTypeClass::As_Reference(cellptr->Smudge).Draw_It(x*CELL_PIXEL_W, y*CELL_PIXEL_H, cellptr->SmudgeData);
- }
- /*
- ** Draw the overlay object.
- */
- if (cellptr->Overlay != OVERLAY_NONE) {
- OverlayTypeClass const & otype = OverlayTypeClass::As_Reference(cellptr->Overlay);
- IsTheaterShape = (bool)otype.IsTheater; //Tell Build_Frame if this overlay is theater specific
- CC_Draw_Shape(otype.Get_Image_Data(),
- cellptr->OverlayData,
- x*CELL_PIXEL_W + (CELL_PIXEL_W >> 1),
- y*CELL_PIXEL_H + (CELL_PIXEL_H >> 1),
- WINDOW_TACTICAL,
- SHAPE_CENTER|SHAPE_WIN_REL|SHAPE_GHOST,
- NULL,
- DisplayClass::UnitShadow);
- IsTheaterShape = false;
- }
- }
- }
- }
- Set_Logic_Page(oldpage);
- /*
- ** Restore the tactical window to its correct value
- */
- WindowList[WINDOW_TACTICAL][WINDOWX] = wx;
- WindowList[WINDOW_TACTICAL][WINDOWY] = wy;
- WindowList[WINDOW_TACTICAL][WINDOWWIDTH] = ww;
- WindowList[WINDOW_TACTICAL][WINDOWHEIGHT] = wh;
- /*
- ** Render the vortex over the cells we just rendered to our buffer
- */
- Coordinate_Remap (RenderBuffer, Lepton_To_Pixel(Coord_X(Coord_Fraction(Position))),
- Lepton_To_Pixel(Coord_Y(Coord_Fraction(Position))),
- 64,
- 64,
- (unsigned char*) lut_ptr);
- /*
- ** Calculate the pixel position of our fresh block of cells on the tactical map so
- ** we can blit it to the hid page.
- */
- COORDINATE render_pos = XY_Coord(xc * CELL_LEPTON_W, yc * CELL_LEPTON_H); //Coord_Whole(Position);
- int xtac = Pixel_To_Lepton(Lepton_To_Pixel(Coord_X(Map.TacticalCoord)));
- int xoff = Pixel_To_Lepton(Lepton_To_Pixel(Coord_X(render_pos)));
- xoff -= xtac;
- int ytac = Pixel_To_Lepton(Lepton_To_Pixel(Coord_Y(Map.TacticalCoord)));
- int yoff = Pixel_To_Lepton(Lepton_To_Pixel(Coord_Y(render_pos)));
- yoff -= ytac;
- /*
- ** Create a view port to blit to
- */
- GraphicViewPortClass target (LogicPage->Get_Graphic_Buffer(),
- 0,
- 8*RESFACTOR + LogicPage->Get_YPos(),
- Lepton_To_Pixel (Map.TacLeptonWidth),
- Lepton_To_Pixel (Map.TacLeptonHeight));
- /*
- ** Do some clipping since the library clipping gets it wrong.
- */
- int diff;
- int source_x = 0;
- int source_y = 0;
- int source_width = CELL_PIXEL_W*4;
- int source_height = CELL_PIXEL_H*4;
- int dest_x = Lepton_To_Pixel (xoff);
- int dest_y = Lepton_To_Pixel (yoff);
- int dest_width = source_width;
- int dest_height = source_height;
- if (dest_x < 0) {
- source_width += dest_x;
- dest_width += dest_x;
- source_x -= dest_x;
- dest_x = 0;
- }
- if (dest_y <0) {
- source_height += dest_y;
- dest_height += dest_y;
- source_y -= dest_y;
- dest_y = 0;
- }
- if (dest_x + dest_width > target.Get_Width() ) {
- diff = dest_x + dest_width - target.Get_Width();
- dest_width -= diff;
- source_width -= diff;
- }
- if (dest_y + dest_height > target.Get_Height() ) {
- diff = dest_y + dest_height - target.Get_Height();
- dest_height -= diff;
- source_height -= diff;
- }
- /*
- ** Blit our freshly draw cells and vortex into their correct position on the hidpage
- */
- if (dest_width > 0 && dest_height > 0) {
- RenderBuffer->Blit (target, source_x, source_y, dest_x, dest_y, dest_width, dest_height, false);
- }
- }
- }
- }
- /***********************************************************************************************
- * CVC::Set_Redraw -- Flags the cells under to vortex to redraw. *
- * *
- * *
- * *
- * INPUT: Nothing *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/29/96 4:50PM ST : Created *
- *=============================================================================================*/
- void ChronalVortexClass::Set_Redraw(void)
- {
- if (Active) {
- CELL xc = Coord_XCell (Position);
- CELL yc = Coord_YCell (Position);
- CELL cell;
- for (int y = MAX(0,yc - 1) ; y< yc+4 ; y++) {
- for (int x = MAX(0, xc-1) ; x< xc + 4 ; x++) {
- cell = XY_Cell (x,y);
- if (cell != -1) {
- Map[cell].Redraw_Objects();
- }
- }
- }
- }
- }
- /***********************************************************************************************
- * CVC::Setup_Remap_Tables -- Initialises the color remap tables based on theater. *
- * *
- * *
- * *
- * INPUT: Theater *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: None *
- * *
- * HISTORY: *
- * 8/29/96 4:51PM ST : Created *
- *=============================================================================================*/
- void ChronalVortexClass::Setup_Remap_Tables (TheaterType theater)
- {
- /*
- ** The names of the remap files for each theater
- */
- static char _remaps[3][13] ={
- "TEMP_VTX.PAL",
- "SNOW_VTX.PAL",
- "INTR_VTX.PAL"
- };
- int i;
- /*
- ** If the theater has changed then load the remap tables from disk if they exist or create
- ** them if they dont.
- */
- if (theater != Theater) {
- Theater = theater;
- CCFileClass file (_remaps[(int)Theater]);
- if (file.Is_Available()) {
- file.Read (VortexRemapTables, MAX_REMAP_SHADES*256);
- } else {
- for (i=0 ; i<MAX_REMAP_SHADES ; i++) {
- Build_Fading_Table ( GamePalette, &VortexRemapTables[i][0], 0, 240- ((i*256)/MAX_REMAP_SHADES) );
- }
- file.Write (VortexRemapTables, MAX_REMAP_SHADES*256);
- }
- }
- /*
- ** Set up the remap table for the lightning
- */
- for (i=0 ; i<256 ; i++) {
- LightningRemap[i] = i;
- }
- LightningRemap[192] = 208;
- LightningRemap[193] = 209;
- LightningRemap[194] = 210;
- LightningRemap[195] = 211;
- LightningRemap[196] = 212;
- LightningRemap[197] = 213;
- LightningRemap[198] = 214;
- LightningRemap[199] = 215;
- }
- /***********************************************************************************************
- * CVC::Build_Fading_Table -- Builds a fading color lookup table. *
- * *
- * *
- * *
- * INPUT: ptr to palette to base tables on *
- * ptr to buffer to put clut in. *
- * color to bias colors to *
- * percentage of bias *
- * *
- * OUTPUT: Nothing *
- * *
- * WARNINGS: Based on Conquer_Build_Fading_Table *
- * *
- * HISTORY: *
- * 8/29/96 4:53PM ST : Created *
- *=============================================================================================*/
- void ChronalVortexClass::Build_Fading_Table(PaletteClass const & palette, void * dest, int color, int frac)
- {
- if (dest) {
- unsigned char * ptr = (unsigned char *)dest;
- /*
- ** Find an appropriate remap color index for every color in the palette.
- ** There are certain exceptions to this, but they are trapped within the
- ** loop.
- */
- for (int index = 0; index < PaletteClass::COLOR_COUNT; index++) {
- /*
- ** If this color should not be remapped, then it will be stored as a remap
- ** to itself. This is effectively no remap.
- */
- if (index == 0 ||
- (index >= CYCLE_COLOR_START && index < (CYCLE_COLOR_START + CYCLE_COLOR_COUNT)) ||
- index == CC_PULSE_COLOR ||
- index == CC_EMBER_COLOR) {
- *ptr++ = index;
- } else {
- /*
- ** Find the color that, ideally, the working color should be remapped
- ** to in the special remap range.
- */
- RGBClass trycolor = palette[index];
- trycolor.Adjust(frac, palette[color]); // Try to match this color.
- /*
- ** Search through the remap range to find the color that should be remapped
- ** to.
- */
- int best = -1;
- int bvalue = 0;
- for (int id = 0; id < PaletteClass::COLOR_COUNT; id++) {
- if (id != 0 &&
- (id < CYCLE_COLOR_START || id >= (CYCLE_COLOR_START + CYCLE_COLOR_COUNT)) &&
- id != CC_PULSE_COLOR &&
- id != CC_EMBER_COLOR) {
- int diff = palette[id].Difference(trycolor);
- if (best == -1 || diff < bvalue) {
- best = id;
- bvalue = diff;
- }
- }
- }
- *ptr++ = best;
- }
- }
- }
- }
- void ChronalVortexClass::Detach(TARGET target)
- {
- if (Target_Legal(target) && target == TargetObject) {
- Set_Target(NULL);
- }
- }
|