VORTEX.CPP 50 KB

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