VORTEX.CPP 50 KB

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