MAP.CPP 107 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294
  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. /* $Header: /CounterStrike/MAP.CPP 3 3/14/97 5:15p Joe_b $ */
  15. /***********************************************************************************************
  16. *** 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 ***
  17. ***********************************************************************************************
  18. * *
  19. * Project Name : Command & Conquer *
  20. * *
  21. * File Name : MAP.CPP *
  22. * *
  23. * Programmer : Joe L. Bostic *
  24. * *
  25. * Start Date : September 10, 1993 *
  26. * *
  27. * Last Update : October 5, 1996 [JLB] *
  28. * *
  29. *---------------------------------------------------------------------------------------------*
  30. * Functions: *
  31. * MapClass::Base_Region -- Finds the owner and base zone for specified cell. *
  32. * MapClass::Cell_Region -- Determines the region from a specified cell number. *
  33. * MapClass::Cell_Threat -- Gets a houses threat value for a cell *
  34. * MapClass::Close_Object -- Finds a clickable close object to the specified coordinate. *
  35. * MapClass::Destroy_Bridge_At -- Destroyes the bridge at location specified. *
  36. * MapClass::Detach -- Remove specified object from map references. *
  37. * MapClass::In_Radar -- Is specified cell in the radar map? *
  38. * MapClass::Init -- clears all cells *
  39. * MapClass::Intact_Bridge_Count -- Determine the number of intact bridges. *
  40. * MapClass::Logic -- Handles map related logic functions. *
  41. * MapClass::Nearby_Location -- Finds a generally clear location near a specified cell. *
  42. * MapClass::One_Time -- Performs special one time initializations for the map. *
  43. * MapClass::Overlap_Down -- computes & marks object's overlap cells *
  44. * MapClass::Overlap_Up -- Computes & clears object's overlap cells *
  45. * MapClass::Overpass -- Performs any final cleanup to a freshly constructed map. *
  46. * MapClass::Pick_Up -- Removes specified object from the map. *
  47. * MapClass::Place_Down -- Places the specified object onto the map. *
  48. * MapClass::Place_Random_Crate -- Places a crate at random location on map. *
  49. * MapClass::Read_Binary -- Reads the binary data from the straw specified. *
  50. * MapClass::Remove_Crate -- Remove a crate from the specified cell. *
  51. * MapClass::Set_Map_Dimensions -- Initialize the map. *
  52. * MapClass::Sight_From -- Mark as visible the cells within a specified radius. *
  53. * MapClass::Validate -- validates every cell on the map *
  54. * MapClass::Write_Binary -- Pipes the map template data to the destination specified. *
  55. * MapClass::Zone_Reset -- Resets all zone numbers to match the map. *
  56. * MapClass::Zone_Span -- Flood fills the specified zone from the cell origin. *
  57. * MapClass::Pick_Random_Location -- Picks a random location on the map. *
  58. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  59. #include "function.h"
  60. #define MCW MAP_CELL_W
  61. int const MapClass::RadiusOffset[] = {
  62. /* 0 */ 0,
  63. /* 1 */ (-MCW*1)-1,(-MCW*1)+0,(-MCW*1)+1,-1,1,(MCW*1)-1,(MCW*1)+0,(MCW*1)+1,
  64. /* 2 */ (-MCW*2)-1,(-MCW*2)+0,(-MCW*2)+1,(-MCW*1)-2,(-MCW*1)+2,-2,2,(MCW*1)-2,(MCW*1)+2,(MCW*2)-1,(MCW*2)+0,(MCW*2)+1,
  65. /* 3 */ (-MCW*3)-1,(-MCW*3)+0,(-MCW*3)+1,(-MCW*2)-2,(-MCW*2)+2,(-MCW*1)-3,(-MCW*1)+3,-3,3,(MCW*1)-3,(MCW*1)+3,(MCW*2)-2,(MCW*2)+2,(MCW*3)-1,(MCW*3)+0,(MCW*3)+1,
  66. /* 4 */ (-MCW*4)-1,(-MCW*4)+0,(-MCW*4)+1,(-MCW*3)-3,(-MCW*3)-2,(-MCW*3)+2,(-MCW*3)+3,(-MCW*2)-3,(-MCW*2)+3,(-MCW*1)-4,(-MCW*1)+4,-4,4,(MCW*1)-4,(MCW*1)+4,(MCW*2)-3,(MCW*2)+3,(MCW*3)-3,(MCW*3)-2,(MCW*3)+2,(MCW*3)+3,(MCW*4)-1,(MCW*4)+0,(MCW*4)+1,
  67. /* 5 */ (-MCW*5)-1,(-MCW*5)+0,(-MCW*5)+1,(-MCW*4)-3,(-MCW*4)-2,(-MCW*4)+2,(-MCW*4)+3,(-MCW*3)-4,(-MCW*3)+4,(-MCW*2)-4,(-MCW*2)+4,(-MCW*1)-5,(-MCW*1)+5,-5,5,(MCW*1)-5,(MCW*1)+5,(MCW*2)-4,(MCW*2)+4,(MCW*3)-4,(MCW*3)+4,(MCW*4)-3,(MCW*4)-2,(MCW*4)+2,(MCW*4)+3,(MCW*5)-1,(MCW*5)+0,(MCW*5)+1,
  68. /* 6 */ (-MCW*6)-1,(-MCW*6)+0,(-MCW*6)+1,(-MCW*5)-3,(-MCW*5)-2,(-MCW*5)+2,(-MCW*5)+3,(-MCW*4)-4,(-MCW*4)+4,(-MCW*3)-5,(-MCW*3)+5,(-MCW*2)-5,(-MCW*2)+5,(-MCW*1)-6,(-MCW*1)+6,-6,6,(MCW*1)-6,(MCW*1)+6,(MCW*2)-5,(MCW*2)+5,(MCW*3)-5,(MCW*3)+5,(MCW*4)-4,(MCW*4)+4,(MCW*5)-3,(MCW*5)-2,(MCW*5)+2,(MCW*5)+3,(MCW*6)-1,(MCW*6)+0,(MCW*6)+1,
  69. /* 7 */ (-MCW*7)-1,(-MCW*7)+0,(-MCW*7)+1,(-MCW*6)-3,(-MCW*6)-2,(-MCW*6)+2,(-MCW*6)+3,(-MCW*5)-5,(-MCW*5)-4,(-MCW*5)+4,(-MCW*5)+5,(-MCW*4)-5,(-MCW*4)+5,(-MCW*3)-6,(-MCW*3)+6,(-MCW*2)-6,(-MCW*2)+6,(-MCW*1)-7,(-MCW*1)+7,-7,7,(MCW*1)-7,(MCW*1)+7,(MCW*2)-6,(MCW*2)+6,(MCW*3)-6,(MCW*3)+6,(MCW*4)-5,(MCW*4)+5,(MCW*5)-5,(MCW*5)-4,(MCW*5)+4,(MCW*5)+5,(MCW*6)-3,(MCW*6)-2,(MCW*6)+2,(MCW*6)+3,(MCW*7)-1,(MCW*7)+0,(MCW*7)+1,
  70. /* 8 */ (-MCW*8)-1,(-MCW*8)+0,(-MCW*8)+1,(-MCW*7)-3,(-MCW*7)-2,(-MCW*7)+2,(-MCW*7)+3,(-MCW*6)-5,(-MCW*6)-4,(-MCW*6)+4,(-MCW*6)+5,(-MCW*5)-6,(-MCW*5)+6,(-MCW*4)-6,(-MCW*4)+6,(-MCW*3)-7,(-MCW*3)+7,(-MCW*2)-7,(-MCW*2)+7,(-MCW*1)-8,(-MCW*1)+8,-8,8,(MCW*1)-8,(MCW*1)+8,(MCW*2)-7,(MCW*2)+7,(MCW*3)-7,(MCW*3)+7,(MCW*4)-6,(MCW*4)+6,(MCW*5)-6,(MCW*5)+6,(MCW*6)-5,(MCW*6)-4,(MCW*6)+4,(MCW*6)+5,(MCW*7)-3,(MCW*7)-2,(MCW*7)+2,(MCW*7)+3,(MCW*8)-1,(MCW*8)+0,(MCW*8)+1,
  71. /* 9 */ (-MCW*9)-1,(-MCW*9)+0,(-MCW*9)+1,(-MCW*8)-3,(-MCW*8)-2,(-MCW*8)+2,(-MCW*8)+3,(-MCW*7)-5,(-MCW*7)-4,(-MCW*7)+4,(-MCW*7)+5,(-MCW*6)-6,(-MCW*6)+6,(-MCW*5)-7,(-MCW*5)+7,(-MCW*4)-7,(-MCW*4)+7,(-MCW*3)-8,(-MCW*3)+8,(-MCW*2)-8,(-MCW*2)+8,(-MCW*1)-9,(-MCW*1)+9,-9,9,(MCW*1)-9,(MCW*1)+9,(MCW*2)-8,(MCW*2)+8,(MCW*3)-8,(MCW*3)+8,(MCW*4)-7,(MCW*4)+7,(MCW*5)-7,(MCW*5)+7,(MCW*6)-6,(MCW*6)+6,(MCW*7)-5,(MCW*7)-4,(MCW*7)+4,(MCW*7)+5,(MCW*8)-3,(MCW*8)-2,(MCW*8)+2,(MCW*8)+3,(MCW*9)-1,(MCW*9)+0,(MCW*9)+1,
  72. /* 10 */ (-MCW*10)-1,(-MCW*10)+0,(-MCW*10)+1,(-MCW*9)-3,(-MCW*9)-2,(-MCW*9)+2,(-MCW*9)+3,(-MCW*8)-5,(-MCW*8)-4,(-MCW*8)+4,(-MCW*8)+5,(-MCW*7)-7,(-MCW*7)-6,(-MCW*7)+6,(-MCW*7)+7,(-MCW*6)-7,(-MCW*6)+7,(-MCW*5)-8,(-MCW*5)+8,(-MCW*4)-8,(-MCW*4)+8,(-MCW*3)-9,(-MCW*3)+9,(-MCW*2)-9,(-MCW*2)+9,(-MCW*1)-10,(-MCW*1)+10,-10,10,(MCW*1)-10,(MCW*1)+10,(MCW*2)-9,(MCW*2)+9,(MCW*3)-9,(MCW*3)+9,(MCW*4)-8,(MCW*4)+8,(MCW*5)-8,(MCW*5)+8,(MCW*6)-7,(MCW*6)+7,(MCW*7)-7,(MCW*7)-6,(MCW*7)+6,(MCW*7)+7,(MCW*8)-5,(MCW*8)-4,
  73. (MCW*8)+4,(MCW*8)+5,(MCW*9)-3,(MCW*9)-2,(MCW*9)+2,(MCW*9)+3,(MCW*10)-1,(MCW*10)+0,(MCW*10)+1,
  74. };
  75. int const MapClass::RadiusCount[11] = {1,9,21,37,61,89,121,161,205,253,309};
  76. CellClass * BlubCell;
  77. /***********************************************************************************************
  78. * MapClass::One_Time -- Performs special one time initializations for the map. *
  79. * *
  80. * This routine is used by the game initialization function in order to perform any one *
  81. * time initializations required for the map. This includes allocation of the map and *
  82. * setting up its default dimensions. *
  83. * *
  84. * INPUT: none *
  85. * *
  86. * OUTPUT: none *
  87. * *
  88. * WARNINGS: This routine MUST be called once and only once. *
  89. * *
  90. * HISTORY: *
  91. * 05/31/1994 JLB : Created. *
  92. * 12/01/1994 BR : Added CellTriggers initialization *
  93. *=============================================================================================*/
  94. void MapClass::One_Time(void)
  95. {
  96. GScreenClass::One_Time();
  97. XSize = MAP_CELL_W;
  98. YSize = MAP_CELL_H;
  99. Size = XSize * YSize;
  100. /*
  101. ** Allocate the cell array.
  102. */
  103. Alloc_Cells();
  104. }
  105. /***********************************************************************************************
  106. * MapClass::Init_Clear -- clears the map & buffers to a known state *
  107. * *
  108. * INPUT: *
  109. * none. *
  110. * *
  111. * OUTPUT: *
  112. * none. *
  113. * *
  114. * WARNINGS: *
  115. * none. *
  116. * *
  117. * HISTORY: *
  118. * 03/17/1995 BRR : Created. *
  119. *=============================================================================================*/
  120. void MapClass::Init_Clear(void)
  121. {
  122. GScreenClass::Init_Clear();
  123. Init_Cells();
  124. TiberiumScan = 0;
  125. TiberiumGrowthCount = 0;
  126. TiberiumGrowthExcess = 0;
  127. TiberiumSpreadCount = 0;
  128. TiberiumSpreadExcess = 0;
  129. for (int index = 0; index < ARRAY_SIZE(Crates); index++) {
  130. Crates[index].Init();
  131. }
  132. }
  133. /***********************************************************************************************
  134. * MapClass::Alloc_Cells -- allocates the cell array *
  135. * *
  136. * This routine should be called at One_Time, and after loading the Map object from a save *
  137. * game, but prior to loading the cell objects. *
  138. * *
  139. * INPUT: *
  140. * none. *
  141. * *
  142. * OUTPUT: *
  143. * none. *
  144. * *
  145. * WARNINGS: *
  146. * none. *
  147. * *
  148. * HISTORY: *
  149. * 03/17/1995 BRR : Created. *
  150. *=============================================================================================*/
  151. void MapClass::Alloc_Cells(void)
  152. {
  153. /*
  154. ** Assume that whatever the contents of the VectorClass are is garbage
  155. ** (it may have been loaded from a save-game file), so zero it out first.
  156. */
  157. new (&Array) VectorClass<CellClass>;
  158. Array.Resize(Size);
  159. }
  160. /***********************************************************************************************
  161. * MapClass::Free_Cells -- frees the cell array *
  162. * *
  163. * This routine is used by the Load_Game routine to free the map's cell array before loading *
  164. * the map object from disk; the array is then re-allocated & cleared before the cell objects *
  165. * are loaded. *
  166. * *
  167. * INPUT: *
  168. * none. *
  169. * *
  170. * OUTPUT: *
  171. * none. *
  172. * *
  173. * WARNINGS: *
  174. * none. *
  175. * *
  176. * HISTORY: *
  177. * 03/17/1995 BRR : Created. *
  178. *=============================================================================================*/
  179. void MapClass::Free_Cells(void)
  180. {
  181. Array.Clear();
  182. }
  183. /***********************************************************************************************
  184. * MapClass::Init_Cells -- Initializes the cell array to a fresh state. *
  185. * *
  186. * This routine is used by Init_Clear to set the cells to a known state; it's also used by *
  187. * the Load_Game routine to init all cells before loading a set of cells from disk, so it *
  188. * needs to be called separately from the other Init_xxx() routines. *
  189. * *
  190. * INPUT: *
  191. * none. *
  192. * *
  193. * OUTPUT: *
  194. * none. *
  195. * *
  196. * WARNINGS: *
  197. * none. *
  198. * *
  199. * HISTORY: *
  200. * 03/17/1995 BRR : Created. *
  201. *=============================================================================================*/
  202. void MapClass::Init_Cells(void)
  203. {
  204. TotalValue = 0;
  205. for (int index = 0; index < MAP_CELL_TOTAL; index++) {
  206. new (&Array[index]) CellClass;
  207. }
  208. }
  209. /***********************************************************************************************
  210. * MapClass::Set_Map_Dimensions -- Set map dimensions. *
  211. * *
  212. * This routine is used to set the legal limits and position of the *
  213. * map as it relates to the overall map array. Typically, this is *
  214. * called by the scenario loading code. *
  215. * *
  216. * INPUT: x,y -- The X and Y coordinate of the "upper left" corner *
  217. * of the map. *
  218. * *
  219. * w,h -- The width and height of the legal map. *
  220. * *
  221. * OUTPUT: none *
  222. * *
  223. * WARNINGS: none *
  224. * *
  225. * HISTORY: *
  226. * 05/14/1994 JLB : Created. *
  227. *=============================================================================================*/
  228. void MapClass::Set_Map_Dimensions(int x, int y, int w, int h)
  229. {
  230. MapCellX = x;
  231. MapCellY = y;
  232. MapCellWidth = w;
  233. MapCellHeight = h;
  234. }
  235. /***********************************************************************************************
  236. * MapClass::Sight_From -- Mark as visible the cells within a specified radius. *
  237. * *
  238. * This routine is used to reveal the cells around a specific location. *
  239. * Typically, as a unit moves or is deployed, this routine will be *
  240. * called. Since it deals with MANY cells, it needs to be extremely *
  241. * fast. *
  242. * *
  243. * INPUT: cell -- The coordinate that the sighting originates from. *
  244. * *
  245. * sightrange-- The distance in cells that sighting extends. *
  246. * *
  247. * incremental-- Is this an incremental sighting. In other *
  248. * words, has this function been called before where *
  249. * the center coordinate is no more than one cell *
  250. * distant from the last time? *
  251. * *
  252. * OUTPUT: none *
  253. * *
  254. * WARNINGS: none *
  255. * *
  256. * HISTORY: *
  257. * 05/19/1992 JLB : Created. *
  258. * 03/08/1994 JLB : Updated to use sight table and incremental flag. *
  259. * 05/18/1994 JLB : Converted to member function. *
  260. *=============================================================================================*/
  261. void MapClass::Sight_From(CELL cell, int sightrange, HouseClass * house, bool incremental)
  262. {
  263. int xx; // Center cell X coordinate (bounds checking).
  264. int const * ptr; // Offset pointer.
  265. int count; // Counter for number of offsets to process.
  266. /*
  267. ** Units that are off-map cannot sight.
  268. */
  269. if (!In_Radar(cell)) return;
  270. if (!sightrange || sightrange > 10) return;
  271. /*
  272. ** Determine logical cell coordinate for center scan point.
  273. */
  274. xx = Cell_X(cell);
  275. /*
  276. ** Incremental scans only scan the outer rings. Full scans
  277. ** scan all internal cells as well.
  278. */
  279. count = RadiusCount[sightrange];
  280. ptr = &RadiusOffset[0];
  281. if (incremental) {
  282. if (sightrange > 2) {
  283. ptr += RadiusCount[sightrange-3];
  284. count -= RadiusCount[sightrange-3];
  285. }
  286. }
  287. /*
  288. ** Process all offsets required for the desired scan.
  289. */
  290. while (count--) {
  291. CELL newcell; // New cell with offset.
  292. int xdiff; // New cell's X coordinate distance from center.
  293. newcell = cell + *ptr++;
  294. /*
  295. ** Determine if the map edge has been wrapped. If so,
  296. ** then don't process the cell.
  297. */
  298. if ((unsigned)newcell >= MAP_CELL_TOTAL) continue;
  299. xdiff = Cell_X(newcell) - xx;
  300. xdiff = ABS(xdiff);
  301. if (xdiff > sightrange) continue;
  302. if (Distance(Cell_Coord(newcell), Cell_Coord(cell)) > (sightrange * CELL_LEPTON_W)) continue;
  303. /*
  304. ** Map the cell. For incremental scans, then update
  305. ** adjacent cells as well. For full scans, just update
  306. ** the cell itself.
  307. */
  308. //if (!(*this)[newcell].IsMapped) { // ST - 8/7/2019 10:31AM
  309. Map.Map_Cell(newcell, house, true, true);
  310. }
  311. }
  312. /***********************************************************************************************
  313. * MapClass::Shroud_From -- cloak a radius of cells *
  314. * *
  315. * This routine is used to shroud the cells around a specific location. *
  316. * Typically, as a gap generator refreshes (when Encroach_Shadow() is called) this routine's*
  317. * called. Since it deals with MANY cells, it needs to be extremely *
  318. * fast. *
  319. * *
  320. * INPUT: cell -- The coordinate that the shrouding originates from. *
  321. * *
  322. * sightrange-- The distance in cells that sighting extends. *
  323. * *
  324. * OUTPUT: none *
  325. * *
  326. * WARNINGS: none *
  327. * *
  328. * HISTORY: *
  329. * 11/10/1995 BWG : Created. *
  330. * 08/09/2019 ST : Added house parameter *
  331. *=============================================================================================*/
  332. void MapClass::Shroud_From(CELL cell, int sightrange, HouseClass *house)
  333. {
  334. int xx; // Center cell X coordinate (bounds checking).
  335. int const * ptr; // Offset pointer.
  336. int count; // Counter for number of offsets to process.
  337. /*
  338. ** Units that are off-map cannot sight.
  339. */
  340. if (!In_Radar(cell)) return;
  341. if (!sightrange || sightrange > Rule.GapShroudRadius) return;
  342. /*
  343. ** Determine logical cell coordinate for center scan point.
  344. */
  345. xx = Cell_X(cell);
  346. /*
  347. ** Incremental scans only scan the outer rings. Full scans
  348. ** scan all internal cells as well.
  349. */
  350. count = RadiusCount[sightrange];
  351. ptr = &RadiusOffset[0];
  352. /*
  353. ** Process all offsets required for the desired scan.
  354. */
  355. while (count--) {
  356. CELL newcell; // New cell with offset.
  357. int xdiff; // New cell's X coordinate distance from center.
  358. newcell = cell + *ptr++;
  359. /*
  360. ** Determine if the map edge has been wrapped. If so,
  361. ** then don't process the cell.
  362. */
  363. if ((unsigned)newcell >= MAP_CELL_TOTAL) continue;
  364. xdiff = Cell_X(newcell) - xx;
  365. xdiff = ABS(xdiff);
  366. if (xdiff > sightrange) continue;
  367. if (Distance(Cell_Coord(newcell), Cell_Coord(cell)) > (sightrange * CELL_LEPTON_W)) continue;
  368. /*
  369. ** Shroud the cell.
  370. */
  371. Map.Shroud_Cell(newcell, house);
  372. }
  373. }
  374. /***********************************************************************************************
  375. * MapClass::Jam_From -- Mark as jammed the cells within a specified radius. *
  376. * *
  377. * This routine is used to jam the cells around a specific location. *
  378. * Typically, as a gap generator structure is created, this routine will be *
  379. * called. Since it deals with MANY cells, it needs to be extremely *
  380. * fast. *
  381. * *
  382. * INPUT: cell -- The coordinate that the jamming originates from. *
  383. * *
  384. * jamrange -- The distance in cells that jamming extends. *
  385. * *
  386. * *
  387. * OUTPUT: none *
  388. * *
  389. * WARNINGS: none *
  390. * *
  391. * HISTORY: *
  392. * 11/09/1995 BWG : Created. *
  393. *=============================================================================================*/
  394. void MapClass::Jam_From(CELL cell, int jamrange, HouseClass * house)
  395. {
  396. int xx; // Center cell X coordinate (bounds checking).
  397. int const * ptr; // Offset pointer.
  398. int count; // Counter for number of offsets to process.
  399. /*
  400. ** Units that are off-map cannot jam.
  401. */
  402. if (!jamrange || jamrange > Rule.GapShroudRadius) return;
  403. /*
  404. ** Determine logical cell coordinate for center scan point.
  405. */
  406. xx = Cell_X(cell);
  407. /*
  408. ** Incremental scans only scan the outer rings. Full scans
  409. ** scan all internal cells as well.
  410. */
  411. count = RadiusCount[jamrange];
  412. ptr = &RadiusOffset[0];
  413. /*
  414. ** Process all offsets required for the desired scan.
  415. */
  416. while (count--) {
  417. CELL newcell; // New cell with offset.
  418. int xdiff; // New cell's X coordinate distance from center.
  419. newcell = cell + *ptr++;
  420. /*
  421. ** Determine if the map edge has been wrapped. If so,
  422. ** then don't process the cell.
  423. */
  424. if ((unsigned)newcell >= MAP_CELL_TOTAL) continue;
  425. xdiff = Cell_X(newcell) - xx;
  426. xdiff = ABS(xdiff);
  427. if (xdiff > jamrange) continue;
  428. if (Distance(Cell_Coord(newcell), Cell_Coord(cell)) > (jamrange * CELL_LEPTON_W)) continue;
  429. /*
  430. ** Jam the cell. For incremental scans, then update
  431. ** adjacent cells as well. For full scans, just update
  432. ** the cell itself.
  433. */
  434. Map.Jam_Cell(newcell, house/*KO, false*/);
  435. }
  436. /*
  437. ** Updated for client/server multiplayer. ST - 8/12/2019 3:25PM
  438. */
  439. if (Session.Type != GAME_GLYPHX_MULTIPLAYER) {
  440. if (!house->IsPlayerControl) {
  441. Map.Constrained_Look(Cell_Coord(cell), Rule.GapShroudRadius * CELL_LEPTON_W, PlayerPtr);
  442. }
  443. } else {
  444. for (int i = 0; i < Session.Players.Count(); i++) {
  445. HouseClass *player_house = HouseClass::As_Pointer(Session.Players[i]->Player.ID);
  446. if (player_house->IsHuman && player_house != house) {
  447. Map.Constrained_Look(Cell_Coord(cell), Rule.GapShroudRadius * CELL_LEPTON_W, player_house);
  448. }
  449. }
  450. }
  451. #ifdef OBSOLETE
  452. /*
  453. ** The objects on the map need to perform a manual look operation if they happen
  454. ** to have their sight range overlap the gap radius.
  455. */
  456. if (!house->IsPlayerControl) {
  457. // if (house != PlayerPtr) {
  458. for (int index = 0; index < Map.Layer[LAYER_GROUND].Count(); index++) {
  459. ObjectClass * object = Map.Layer[LAYER_GROUND][index];
  460. if (object && object->Is_Techno()) {
  461. TechnoClass * tech = ((TechnoClass *)object);
  462. if (tech->IsDiscoveredByPlayer &&
  463. (tech->Distance(As_Target(cell)) / CELL_LEPTON_W) <= tech->Techno_Type_Class()->SightRange + Rule.GapShroudRadius &&
  464. (tech->House->IsPlayerControl ||
  465. (tech->What_Am_I() == RTTI_BUILDING && Rule.IsAllyReveal && tech->House->Is_Ally(PlayerPtr)))) {
  466. object->Look();
  467. }
  468. }
  469. }
  470. }
  471. #endif
  472. #ifdef OBSOLETE
  473. /*
  474. ** Here all the player's vehicles will perform a look if they're within
  475. ** the shadow.
  476. */
  477. for (int index = 0; index < Units.Count(); index++) {
  478. UnitClass * unit = Units.Ptr(index);
  479. if (unit && !unit->IsInLimbo && unit->House == PlayerPtr) {
  480. int dist = (unit->Distance(As_Target(cell))) / CELL_LEPTON_W;
  481. if (dist <= unit->Class->SightRange + Rule.GapShroudRadius /*gap generator sightrange*/) {
  482. unit->Look();
  483. }
  484. }
  485. }
  486. for (index = 0; index < Infantry.Count(); index++) {
  487. InfantryClass * unit = Infantry.Ptr(index);
  488. if (unit && !unit->IsInLimbo && unit->House == PlayerPtr) {
  489. int dist = (unit->Distance(As_Target(cell))) / CELL_LEPTON_W;
  490. if (dist <= unit->Class->SightRange + Rule.GapShroudRadius /*gap generator sightrange*/) {
  491. unit->Look();
  492. }
  493. }
  494. }
  495. for (index = 0; index < Vessels.Count(); index++) {
  496. VesselClass * unit = Vessels.Ptr(index);
  497. if (unit && !unit->IsInLimbo && unit->House == PlayerPtr) {
  498. int dist = (unit->Distance(As_Target(cell))) / CELL_LEPTON_W;
  499. if (dist <= unit->Class->SightRange + Rule.GapShroudRadius /*gap generator sightrange*/) {
  500. unit->Look();
  501. }
  502. }
  503. }
  504. }
  505. #endif
  506. }
  507. /***********************************************************************************************
  508. * MapClass::UnJam_From -- Remove jamming on the cells within a specified radius. *
  509. * *
  510. * This routine is used to jam the cells around a specific location. *
  511. * Typically, as a gap generator structure is created, this routine will be *
  512. * called. Since it deals with MANY cells, it needs to be extremely *
  513. * fast. *
  514. * *
  515. * INPUT: cell -- The coordinate that the jamming originates from. *
  516. * *
  517. * jamrange -- The distance in cells that jamming extends. *
  518. * *
  519. * OUTPUT: none *
  520. * *
  521. * WARNINGS: none *
  522. * *
  523. * HISTORY: *
  524. * 11/09/1995 BWG : Created. *
  525. *=============================================================================================*/
  526. void MapClass::UnJam_From(CELL cell, int jamrange, HouseClass * house)
  527. {
  528. int xx; // Center cell X coordinate (bounds checking).
  529. int const * ptr; // Offset pointer.
  530. int count; // Counter for number of offsets to process.
  531. /*
  532. ** Units that are off-map cannot jam.
  533. */
  534. if (!jamrange || jamrange > Rule.GapShroudRadius) return;
  535. /*
  536. ** Determine logical cell coordinate for center scan point.
  537. */
  538. xx = Cell_X(cell);
  539. /*
  540. ** Incremental scans only scan the outer rings. Full scans
  541. ** scan all internal cells as well.
  542. */
  543. count = RadiusCount[jamrange];
  544. ptr = &RadiusOffset[0];
  545. /*
  546. ** Process all offsets required for the desired scan.
  547. */
  548. while (count--) {
  549. CELL newcell; // New cell with offset.
  550. int xdiff; // New cell's X coordinate distance from center.
  551. newcell = cell + *ptr++;
  552. /*
  553. ** Determine if the map edge has been wrapped. If so,
  554. ** then don't process the cell.
  555. */
  556. if ((unsigned)newcell >= MAP_CELL_TOTAL) continue;
  557. xdiff = Cell_X(newcell) - xx;
  558. xdiff = ABS(xdiff);
  559. if (xdiff > jamrange) continue;
  560. if (Distance(Cell_Coord(newcell), Cell_Coord(cell)) > (jamrange * CELL_LEPTON_W)) continue;
  561. /*
  562. ** Jam the cell. For incremental scans, then update
  563. ** adjacent cells as well. For full scans, just update
  564. ** the cell itself.
  565. */
  566. Map.UnJam_Cell(newcell, house);
  567. }
  568. }
  569. /***********************************************************************************************
  570. * MapClass::In_Radar -- Is specified cell in the radar map? *
  571. * *
  572. * This determines if the specified cell can be within the navigable *
  573. * bounds of the map. Technically, this means, any cell that can be *
  574. * scanned by radar. If a cell returns false from this function, then *
  575. * the player could never move to or pass over this cell. *
  576. * *
  577. * INPUT: cell -- The cell to examine. *
  578. * *
  579. * OUTPUT: bool; Is this cell possible to be displayed on radar? *
  580. * *
  581. * WARNINGS: none *
  582. * *
  583. * HISTORY: *
  584. * 10/07/1992 JLB : Created. *
  585. * 04/30/1994 JLB : Converted to member function. *
  586. * 05/01/1994 JLB : Speeded up. *
  587. *=============================================================================================*/
  588. bool MapClass::In_Radar(CELL cell) const
  589. {
  590. /*
  591. ** If the cell value is WAY out of range, then it obviously can't be part of the game
  592. ** playfield.
  593. */
  594. if ((unsigned)cell > MAP_CELL_TOTAL) return(false);
  595. /*
  596. ** If the cell is off the left or right edge of the playfield, then return the "not in
  597. ** radar" flag.
  598. */
  599. if ((unsigned)(Cell_X(cell) - MapCellX) >= (unsigned)MapCellWidth) return(false);
  600. /*
  601. ** If the cell is off the top or bottom edge of the playfield, then return the "not in
  602. ** radar" flag.
  603. */
  604. if ((unsigned)(Cell_Y(cell) - MapCellY) >= (unsigned)MapCellHeight) return(false);
  605. return(true);
  606. }
  607. /***********************************************************************************************
  608. * MapClass::Place_Down -- Places the specified object onto the map. *
  609. * *
  610. * This routine is used to place an object onto the map. It updates the "occupier" of the *
  611. * cells that this object covers. The cells are determined from the Occupy_List function *
  612. * provided by the object. Only one cell can have an occupier and this routine is the only *
  613. * place that sets this condition. *
  614. * *
  615. * INPUT: cell -- The cell to base object occupation around. *
  616. * *
  617. * object -- The object to place onto the map. *
  618. * *
  619. * OUTPUT: none *
  620. * *
  621. * WARNINGS: none *
  622. * *
  623. * HISTORY: *
  624. * 07/31/1994 JLB : Created. *
  625. *=============================================================================================*/
  626. void MapClass::Place_Down(CELL cell, ObjectClass * object)
  627. {
  628. if (!object) return;
  629. if (object->Class_Of().IsFootprint && object->In_Which_Layer() == LAYER_GROUND) {
  630. short xlist[32];
  631. List_Copy(object->Occupy_List(), ARRAY_SIZE(xlist), xlist);
  632. short const * list = xlist;
  633. while (*list != REFRESH_EOL) {
  634. CELL newcell = cell + *list++;
  635. if ((unsigned)newcell < MAP_CELL_TOTAL) {
  636. (*this)[newcell].Occupy_Down(object);
  637. (*this)[newcell].Recalc_Attributes();
  638. (*this)[newcell].Redraw_Objects();
  639. }
  640. }
  641. List_Copy(object->Overlap_List(), ARRAY_SIZE(xlist), xlist);
  642. list = xlist;
  643. while (*list != REFRESH_EOL) {
  644. CELL newcell = cell + *list++;
  645. if ((unsigned)newcell < MAP_CELL_TOTAL) {
  646. (*this)[newcell].Overlap_Down(object);
  647. (*this)[newcell].Redraw_Objects();
  648. }
  649. }
  650. }
  651. }
  652. /***********************************************************************************************
  653. * MapClass::Pick_Up -- Removes specified object from the map. *
  654. * *
  655. * The object specified is removed from the map by this routine. This will remove the *
  656. * occupation flag for all the cells that the object covers. The cells that are covered *
  657. * are determined from the Occupy_List function. *
  658. * *
  659. * INPUT: cell -- The cell that the object is centered about. *
  660. * *
  661. * object -- Pointer to the object that will be removed. *
  662. * *
  663. * OUTPUT: none *
  664. * *
  665. * WARNINGS: none *
  666. * *
  667. * HISTORY: *
  668. * 07/31/1994 JLB : Created. *
  669. *=============================================================================================*/
  670. void MapClass::Pick_Up(CELL cell, ObjectClass * object)
  671. {
  672. if (!object) return;
  673. if (object->Class_Of().IsFootprint && object->In_Which_Layer() == LAYER_GROUND) {
  674. short xlist[32];
  675. List_Copy(object->Occupy_List(), ARRAY_SIZE(xlist), xlist);
  676. short const * list = xlist;
  677. while (*list != REFRESH_EOL) {
  678. CELL newcell = cell + *list++;
  679. if ((unsigned)newcell < MAP_CELL_TOTAL) {
  680. (*this)[newcell].Occupy_Up(object);
  681. (*this)[newcell].Recalc_Attributes();
  682. (*this)[newcell].Redraw_Objects();
  683. }
  684. }
  685. List_Copy(object->Overlap_List(), ARRAY_SIZE(xlist), xlist);
  686. list = xlist;
  687. while (*list != REFRESH_EOL) {
  688. CELL newcell = cell + *list++;
  689. if ((unsigned)newcell < MAP_CELL_TOTAL) {
  690. (*this)[newcell].Overlap_Up(object);
  691. (*this)[newcell].Redraw_Objects();
  692. }
  693. }
  694. }
  695. }
  696. /***********************************************************************************************
  697. * MapClass::Overlap_Down -- computes & marks object's overlap cells *
  698. * *
  699. * This routine is just like Place_Down, but it doesn't mark the cell's Occupier. *
  700. * This routine is used to implement MARK_OVERLAP_DOWN, which is useful for changing *
  701. * an object's render size, but not its logical size (ie when it's selected or an *
  702. * animation is attached to it). *
  703. * *
  704. * INPUT: *
  705. * cell -- The cell to base object overlap around. *
  706. * object -- The object to place onto the map. *
  707. * *
  708. * OUTPUT: *
  709. * none. *
  710. * *
  711. * WARNINGS: *
  712. * none. *
  713. * *
  714. * HISTORY: *
  715. * 07/12/1995 BRR : Created. *
  716. *=============================================================================================*/
  717. void MapClass::Overlap_Down(CELL cell, ObjectClass * object)
  718. {
  719. if (!object) return;
  720. if (object->Class_Of().IsFootprint && object->In_Which_Layer() == LAYER_GROUND) {
  721. short xlist[32];
  722. List_Copy(object->Overlap_List(), ARRAY_SIZE(xlist), xlist);
  723. short const * list = xlist;
  724. while (*list != REFRESH_EOL) {
  725. CELL newcell = cell + *list++;
  726. if ((unsigned)newcell < MAP_CELL_TOTAL) {
  727. (*this)[newcell].Overlap_Down(object);
  728. (*this)[newcell].Redraw_Objects();
  729. }
  730. }
  731. }
  732. }
  733. /***********************************************************************************************
  734. * MapClass::Overlap_Up -- Computes & clears object's overlap cells *
  735. * *
  736. * This routine is just like Pick_Up, but it doesn't mark the cell's Occupier. *
  737. * This routine is used to implement MARK_OVERLAP_UP, which is useful for changing *
  738. * an object's render size, but not its logical size (ie when it's selected or an *
  739. * animation is attached to it). *
  740. * *
  741. * INPUT: *
  742. * cell -- The cell to base object overlap around. *
  743. * object -- The object to place onto the map. *
  744. * *
  745. * OUTPUT: *
  746. * none. *
  747. * *
  748. * WARNINGS: *
  749. * none. *
  750. * *
  751. * HISTORY: *
  752. * 07/12/1995 BRR : Created. *
  753. *=============================================================================================*/
  754. void MapClass::Overlap_Up(CELL cell, ObjectClass * object)
  755. {
  756. if (!object) return;
  757. if (object->Class_Of().IsFootprint && object->In_Which_Layer() == LAYER_GROUND) {
  758. short xlist[32];
  759. List_Copy(object->Overlap_List(), ARRAY_SIZE(xlist), xlist);
  760. short const * list = xlist;
  761. while (*list != REFRESH_EOL) {
  762. CELL newcell = cell + *list++;
  763. if ((unsigned)newcell < MAP_CELL_TOTAL) {
  764. (*this)[newcell].Overlap_Up(object);
  765. (*this)[newcell].Redraw_Objects();
  766. }
  767. }
  768. }
  769. }
  770. /***********************************************************************************************
  771. * MapClass::Overpass -- Performs any final cleanup to a freshly constructed map. *
  772. * *
  773. * This routine will clean up anything necessary with the presumption that the map has *
  774. * been freshly created. Such things to clean up include various tiberium concentrations. *
  775. * *
  776. * INPUT: none *
  777. * *
  778. * OUTPUT: Returns the total credit value of the tiberium on the map. *
  779. * *
  780. * WARNINGS: none *
  781. * *
  782. * HISTORY: *
  783. * 09/19/1994 JLB : Created. *
  784. * 02/13/1995 JLB : Returns total tiberium worth. *
  785. * 02/15/1995 JLB : Optimal scan. *
  786. *=============================================================================================*/
  787. long MapClass::Overpass(void)
  788. {
  789. long value = 0;
  790. /*
  791. ** Smooth out Tiberium. Cells that are not surrounded by other tiberium
  792. ** will be reduced in density.
  793. */
  794. for (int y = 0; y < MapCellHeight; y++) {
  795. for (int x = 0; x < MapCellWidth; x++) {
  796. CELL cell = (MapCellY+y) * MAP_CELL_W + (MapCellX+x);
  797. value += (*this)[cell].Tiberium_Adjust(true);
  798. (*this)[cell].Recalc_Attributes();
  799. }
  800. }
  801. return(value);
  802. }
  803. /***********************************************************************************************
  804. * MapClass::Write_Binary -- Pipes the map template data to the destination specified. *
  805. * *
  806. * This stores the template data from the map to the output pipe specified. The template *
  807. * data consists of the template type number and template icon number for every cell on *
  808. * the map. The output is organized in such a way so as to get maximum compression. *
  809. * *
  810. * INPUT: pipe -- Reference to the output pipe that will receive the map template data. *
  811. * *
  812. * OUTPUT: Returns with the total number of bytes output to the pipe. *
  813. * *
  814. * WARNINGS: none *
  815. * *
  816. * HISTORY: *
  817. * 07/03/1996 JLB : Created. *
  818. *=============================================================================================*/
  819. int MapClass::Write_Binary(Pipe & pipe)
  820. {
  821. int total = 0;
  822. LCWPipe comp(LCWPipe::COMPRESS);
  823. comp.Put_To(&pipe);
  824. CellClass * cellptr = &Array[0];
  825. for (int i = 0; i < MAP_CELL_TOTAL; i++) {
  826. total += comp.Put(&cellptr->TType, sizeof(cellptr->TType));
  827. cellptr++;
  828. }
  829. cellptr = &Array[0];
  830. for (int i = 0; i < MAP_CELL_TOTAL; i++) {
  831. total += comp.Put(&cellptr->TIcon, sizeof(cellptr->TIcon));
  832. cellptr++;
  833. }
  834. return(total);
  835. }
  836. /***********************************************************************************************
  837. * MapClass::Read_Binary -- Reads the binary data from the straw specified. *
  838. * *
  839. * This routine will retrieve the map template data from the straw specified. *
  840. * *
  841. * INPUT: straw -- Reference to the straw that will supply the map template data. *
  842. * *
  843. * OUTPUT: bool; Was the template data retrieved? *
  844. * *
  845. * WARNINGS: none *
  846. * *
  847. * HISTORY: *
  848. * 07/03/1996 JLB : Created. *
  849. *=============================================================================================*/
  850. bool MapClass::Read_Binary(Straw & straw)
  851. {
  852. LCWStraw decomp(LCWStraw::DECOMPRESS);
  853. decomp.Get_From(&straw);
  854. CELL cell;
  855. CellClass * cellptr;
  856. switch (NewINIFormat) {
  857. default:
  858. cellptr = &Array[0];
  859. for (cell = 0; cell < MAP_CELL_TOTAL; cell++) {
  860. decomp.Get(&cellptr->TType, sizeof(cellptr->TType));
  861. cellptr++;
  862. }
  863. cellptr = &Array[0];
  864. for (cell = 0; cell < MAP_CELL_TOTAL; cell++) {
  865. decomp.Get(&cellptr->TIcon, sizeof(cellptr->TIcon));
  866. cellptr->Recalc_Attributes();
  867. cellptr++;
  868. }
  869. break;
  870. case 0:
  871. case 1:
  872. case 2:
  873. cellptr = &Array[0];
  874. for (cell = 0; cell < MAP_CELL_TOTAL; cell++) {
  875. decomp.Get(&cellptr->TType, sizeof(cellptr->TType));
  876. decomp.Get(&cellptr->TIcon, sizeof(cellptr->TIcon));
  877. cellptr->Recalc_Attributes();
  878. cellptr++;
  879. }
  880. break;
  881. }
  882. return(true);
  883. }
  884. /***********************************************************************************************
  885. * MapClass::Logic -- Handles map related logic functions. *
  886. * *
  887. * Manages tiberium growth and spread. *
  888. * *
  889. * INPUT: none *
  890. * *
  891. * OUTPUT: none *
  892. * *
  893. * WARNINGS: none *
  894. * *
  895. * HISTORY: *
  896. * 05/11/1995 JLB : Created. *
  897. * 07/09/1995 JLB : Handles two directional scan. *
  898. * 08/01/1995 JLB : Gives stronger weight to blossom trees. *
  899. *=============================================================================================*/
  900. void MapClass::Logic(void)
  901. {
  902. if (Debug_Force_Crash) { *((int *)0) = 1; }
  903. /*
  904. ** Crate regeneration is handled here.
  905. */
  906. if (Session.Type != GAME_NORMAL && Session.Options.Goodies) {
  907. /*
  908. ** Find any crate that has expired and then regenerate it at a new
  909. ** spot.
  910. */
  911. for (int index = 0; index < ARRAY_SIZE(Crates); index++) {
  912. if (Crates[index].Is_Expired()) {
  913. Crates[index].Remove_It();
  914. Place_Random_Crate();
  915. }
  916. }
  917. }
  918. /*
  919. ** Bail early if there is no allowed growth or spread of Tiberium.
  920. */
  921. if (!Rule.IsTGrowth && !Rule.IsTSpread) return;
  922. /*
  923. ** Scan another block of the map in order to accumulate the potential
  924. ** Tiberium cells that can grow or spread.
  925. */
  926. int subcount = MAP_CELL_TOTAL / (Rule.GrowthRate * TICKS_PER_MINUTE);
  927. /*
  928. ** Use the Tiberium setting as a multiplier on growth rate. ST - 7/1/2020 3:05PM
  929. */
  930. if (Session.Type == GAME_GLYPHX_MULTIPLAYER) {
  931. if (Session.Options.Tiberium > 1) {
  932. subcount *= Session.Options.Tiberium;
  933. }
  934. }
  935. subcount = max(subcount, 1);
  936. int index;
  937. for (index = TiberiumScan; index < MAP_CELL_TOTAL; index++) {
  938. CELL cell = index;
  939. if (In_Radar(cell)) {
  940. CellClass * ptr = &(*this)[cell];
  941. /*
  942. ** Tiberium cells can grow.
  943. */
  944. if (ptr->Can_Tiberium_Grow()) {
  945. /*
  946. ** Either replace an existing recorded cell value or add the new cell value to
  947. ** the list.
  948. */
  949. if (Random_Pick(0, TiberiumGrowthExcess) <= TiberiumGrowthCount) {
  950. if (TiberiumGrowthCount < sizeof(TiberiumGrowth)/sizeof(TiberiumGrowth[0])) {
  951. TiberiumGrowth[TiberiumGrowthCount++] = cell;
  952. } else {
  953. TiberiumGrowth[Random_Pick(0, TiberiumGrowthCount-1)] = cell;
  954. }
  955. }
  956. TiberiumGrowthExcess++;
  957. }
  958. /*
  959. ** Heavy Tiberium growth can spread.
  960. */
  961. if (ptr->Can_Tiberium_Spread()) {
  962. /*
  963. ** Either replace an existing recorded cell value or add the new cell value to
  964. ** the list.
  965. */
  966. if (Random_Pick(0, TiberiumSpreadExcess) <= TiberiumSpreadCount) {
  967. if (TiberiumSpreadCount < ARRAY_SIZE(TiberiumSpread)) {
  968. TiberiumSpread[TiberiumSpreadCount++] = cell;
  969. } else {
  970. TiberiumSpread[Random_Pick(0, TiberiumSpreadCount-1)] = cell;
  971. }
  972. }
  973. TiberiumSpreadExcess++;
  974. }
  975. }
  976. subcount--;
  977. if (subcount == 0) break;
  978. }
  979. TiberiumScan = index;
  980. /*
  981. ** When the entire map has been processed, proceed with tiberium (ore) growth
  982. ** and spread action.
  983. */
  984. if (TiberiumScan >= MAP_CELL_TOTAL) {
  985. TiberiumScan = 0;
  986. /*
  987. ** Growth logic.
  988. */
  989. if (TiberiumGrowthCount) {
  990. for (int i = 0; i < TiberiumGrowthCount; i++) {
  991. CELL cell = TiberiumGrowth[i];
  992. CellClass * newcell = &(*this)[cell];
  993. newcell->Grow_Tiberium();
  994. }
  995. }
  996. TiberiumGrowthCount = 0;
  997. TiberiumGrowthExcess = 0;
  998. /*
  999. ** Spread logic.
  1000. */
  1001. if (TiberiumSpreadCount) {
  1002. for (int i = 0; i < TiberiumSpreadCount; i++) {
  1003. Map[TiberiumSpread[i]].Spread_Tiberium();
  1004. }
  1005. }
  1006. TiberiumSpreadCount = 0;
  1007. TiberiumSpreadExcess = 0;
  1008. }
  1009. }
  1010. /***********************************************************************************************
  1011. * MapClass::Cell_Region -- Determines the region from a specified cell number. *
  1012. * *
  1013. * Use this routine to determine what region a particular cell lies in. *
  1014. * *
  1015. * INPUT: cell -- The cell number to examine. *
  1016. * *
  1017. * OUTPUT: Returns with the region that the specified cell occupies. *
  1018. * *
  1019. * WARNINGS: none *
  1020. * *
  1021. * HISTORY: *
  1022. * 03/15/1995 JLB : Created. *
  1023. *=============================================================================================*/
  1024. int MapClass::Cell_Region(CELL cell)
  1025. {
  1026. return((Cell_X(cell) / REGION_WIDTH) + 1) + (((Cell_Y(cell) / REGION_HEIGHT) + 1) * MAP_REGION_WIDTH);
  1027. }
  1028. /***************************************************************************
  1029. * MapClass::Cell_Threat -- Gets a houses threat value for a cell *
  1030. * *
  1031. * INPUT: CELL cell - the cell number to check *
  1032. * HouseType house - the house to check *
  1033. * *
  1034. * OUTPUT: *
  1035. * *
  1036. * WARNINGS: *
  1037. * *
  1038. * HISTORY: *
  1039. * 04/25/1995 PWG : Created. *
  1040. *=========================================================================*/
  1041. int MapClass::Cell_Threat(CELL cell, HousesType house)
  1042. {
  1043. int threat = HouseClass::As_Pointer(house)->Regions[Map.Cell_Region(Map[cell].Cell_Number())].Threat_Value();
  1044. //using function for IsVisible so we have different results for different players - JAS 2019/09/30
  1045. if (!threat && Map[cell].Is_Visible(house)) {
  1046. threat = 1;
  1047. }
  1048. return(threat);
  1049. }
  1050. /***********************************************************************************************
  1051. * MapClass::Place_Random_Crate -- Places a crate at random location on map. *
  1052. * *
  1053. * This routine will place a crate at a random location on the map. This routine will only *
  1054. * make a limited number of attempts to place and if unsuccessful, it will not place any. *
  1055. * *
  1056. * INPUT: none *
  1057. * *
  1058. * OUTPUT: Was a crate successfully placed? *
  1059. * *
  1060. * WARNINGS: none *
  1061. * *
  1062. * HISTORY: *
  1063. * 07/08/1995 JLB : Created. *
  1064. *=============================================================================================*/
  1065. bool MapClass::Place_Random_Crate(void)
  1066. {
  1067. /*
  1068. ** Find a crate index that is free for assignment. If there are
  1069. ** no free slots, then return with failure to place crate.
  1070. */
  1071. int crateindex = 0;
  1072. for (crateindex = 0; crateindex < ARRAY_SIZE(Crates); crateindex++) {
  1073. if (!Crates[crateindex].Is_Valid()) break;
  1074. }
  1075. if (crateindex == ARRAY_SIZE(Crates)) {
  1076. return(false);
  1077. }
  1078. /*
  1079. ** Give a good effort to scan for and place a crate down on the map.
  1080. */
  1081. for (int index = 0; index < 1000; index++) {
  1082. CELL cell = Map.Pick_Random_Location();
  1083. if (Crates[crateindex].Create_Crate(cell)) {
  1084. return(true);
  1085. }
  1086. }
  1087. return(false);
  1088. }
  1089. /***********************************************************************************************
  1090. * MapClass::Remove_Crate -- Remove a crate from the specified cell. *
  1091. * *
  1092. * This will examine the cell and remove any crates there. *
  1093. * *
  1094. * INPUT: cell -- The cell to examine for crates and remove from. *
  1095. * *
  1096. * OUTPUT: bool; Was a crate found at the location specified and was it removed? *
  1097. * *
  1098. * WARNINGS: none *
  1099. * *
  1100. * HISTORY: *
  1101. * 08/26/1996 JLB : Created. *
  1102. *=============================================================================================*/
  1103. bool MapClass::Remove_Crate(CELL cell)
  1104. {
  1105. if (Session.Type != GAME_NORMAL) {
  1106. for (int index = 0; index < ARRAY_SIZE(Crates); index++) {
  1107. if (Crates[index].Is_Here(cell)) {
  1108. return(Crates[index].Remove_It());
  1109. }
  1110. }
  1111. }
  1112. // if (Session.Type == GAME_NORMAL) {
  1113. CellClass * cellptr = &(*this)[cell];
  1114. if (cellptr->Overlay != OVERLAY_NONE && OverlayTypeClass::As_Reference(cellptr->Overlay).IsCrate) {
  1115. cellptr->Overlay = OVERLAY_NONE;
  1116. cellptr->OverlayData = 0;
  1117. return(true);
  1118. }
  1119. // } else {
  1120. // for (int index = 0; index < ARRAY_SIZE(Crates); index++) {
  1121. // if (Crates[index].Is_Here(cell)) {
  1122. // return(Crates[index].Remove_It());
  1123. // }
  1124. // }
  1125. // }
  1126. return(false);
  1127. }
  1128. /***************************************************************************
  1129. * MapClass::Validate -- validates every cell on the map *
  1130. * *
  1131. * This is a debugging routine, designed to detect memory trashers that *
  1132. * alter the map. This routine is slow, but thorough. *
  1133. * *
  1134. * INPUT: *
  1135. * none. *
  1136. * *
  1137. * OUTPUT: *
  1138. * true = map is OK, false = an error was found *
  1139. * *
  1140. * WARNINGS: *
  1141. * none. *
  1142. * *
  1143. * HISTORY: *
  1144. * 07/08/1995 BRR : Created. *
  1145. *=========================================================================*/
  1146. int MapClass::Validate(void)
  1147. {
  1148. CELL cell;
  1149. TemplateType ttype;
  1150. unsigned char ticon;
  1151. TemplateTypeClass const *tclass;
  1152. unsigned char map[13*8];
  1153. OverlayType overlay;
  1154. SmudgeType smudge;
  1155. ObjectClass * obj;
  1156. LandType land;
  1157. int i;
  1158. BlubCell = &Array[797];
  1159. if (BlubCell->Overlapper[1]) {
  1160. obj = BlubCell->Overlapper[1];
  1161. if (obj) {
  1162. if (obj->IsInLimbo)
  1163. obj = obj;
  1164. }
  1165. }
  1166. /*
  1167. ** Check every cell on the map, even those that aren't displayed,
  1168. ** in the hopes of detecting a memory trasher.
  1169. */
  1170. for (cell = 0; cell < MAP_CELL_TOTAL; cell++) {
  1171. /*
  1172. ** Validate Template & Icon data
  1173. */
  1174. ttype = (*this)[cell].TType;
  1175. ticon = (*this)[cell].TIcon;
  1176. if (ttype >= TEMPLATE_COUNT && ttype != TEMPLATE_NONE)
  1177. return(false);
  1178. /*
  1179. ** To validate the icon value, we have to get a copy of the template's
  1180. ** "icon map"; this map will have 0xff's in spots where there is no
  1181. ** icon. If the icon value is out of range or points to an invalid spot,
  1182. ** return an error.
  1183. */
  1184. if (ttype != TEMPLATE_NONE) {
  1185. tclass = &TemplateTypeClass::As_Reference(ttype);
  1186. ticon = (*this)[cell].TIcon;
  1187. Mem_Copy(Get_Icon_Set_Map(tclass->Get_Image_Data()), map, tclass->Width * tclass->Height);
  1188. if (ticon < 0 || ticon >= (tclass->Width * tclass->Height) || map[ticon]==0xff) {
  1189. return (false);
  1190. }
  1191. }
  1192. /*
  1193. ** Validate Overlay
  1194. */
  1195. overlay = (*this)[cell].Overlay;
  1196. if (overlay < OVERLAY_NONE || overlay >= OVERLAY_COUNT) {
  1197. return(false);
  1198. }
  1199. /*
  1200. ** Validate Smudge
  1201. */
  1202. smudge = (*this)[cell].Smudge;
  1203. if (smudge < SMUDGE_NONE || smudge >= SMUDGE_COUNT) {
  1204. return(false);
  1205. }
  1206. /*
  1207. ** Validate LandType
  1208. */
  1209. land = (*this)[cell].Land_Type();
  1210. if (land < LAND_CLEAR || land >= LAND_COUNT) {
  1211. return(false);
  1212. }
  1213. /*
  1214. ** Validate Occupier
  1215. */
  1216. obj = (*this)[cell].Cell_Occupier();
  1217. if (obj) {
  1218. if (
  1219. ((unsigned int)obj & 0xff000000) ||
  1220. ((unsigned int)obj->Next & 0xff000000) ||
  1221. // ((unsigned int)obj->Trigger & 0xff000000) ||
  1222. obj->IsInLimbo ||
  1223. ((unsigned int)Coord_Cell(obj->Coord) >= MAP_CELL_TOTAL)) {
  1224. return (false);
  1225. }
  1226. }
  1227. /*
  1228. ** Validate Overlappers
  1229. */
  1230. for (i = 0; i < ARRAY_SIZE((*this)[cell].CellClass::Overlapper); i++) {
  1231. obj = (*this)[cell].Overlapper[i];
  1232. if (obj) {
  1233. if (
  1234. ((unsigned int)obj & 0xff000000) ||
  1235. ((unsigned int)obj->Next & 0xff000000) ||
  1236. // ((unsigned int)obj->Trigger & 0xff000000) ||
  1237. obj->IsInLimbo ||
  1238. ((unsigned int)Coord_Cell(obj->Coord) >= MAP_CELL_TOTAL)) {
  1239. return (false);
  1240. }
  1241. }
  1242. }
  1243. }
  1244. return (true);
  1245. }
  1246. /***********************************************************************************************
  1247. * MapClass::Close_Object -- Finds a clickable close object to the specified coordinate. *
  1248. * *
  1249. * This routine is used by the mouse input processing code to find a clickable object *
  1250. * close to coordinate specified. This is for targeting as well as selection determination. *
  1251. * *
  1252. * INPUT: coord -- The coordinate to scan for close object from. *
  1253. * *
  1254. * OUTPUT: Returns with a pointer to an object that is nearby the specified coordinate. *
  1255. * *
  1256. * WARNINGS: There could be a cloaked object at the location, but it won't be considered *
  1257. * if it is not owned by the player. *
  1258. * *
  1259. * HISTORY: *
  1260. * 08/20/1995 JLB : Created. *
  1261. *=============================================================================================*/
  1262. ObjectClass * MapClass::Close_Object(COORDINATE coord) const
  1263. {
  1264. ObjectClass * object = 0;
  1265. int distance = 0;
  1266. CELL cell = Coord_Cell(coord);
  1267. /*
  1268. ** Scan through current and adjacent cells, looking for the
  1269. ** closest object (within reason) to the specified coordinate.
  1270. */
  1271. static int _offsets[] = {0, -1, 1, -MAP_CELL_W, MAP_CELL_W, MAP_CELL_W-1, MAP_CELL_W+1, -(MAP_CELL_W-1), -(MAP_CELL_W+1)};
  1272. for (int index = 0; index < (sizeof(_offsets) / sizeof(_offsets[0])); index++) {
  1273. /*
  1274. ** Examine the cell for close object. Make sure that the cell actually is a
  1275. ** legal one.
  1276. */
  1277. CELL newcell = cell + _offsets[index];
  1278. if (In_Radar(newcell)) {
  1279. /*
  1280. ** Search through all objects that occupy this cell and then
  1281. ** find the closest object. Check against any previously found object
  1282. ** to ensure that it is actually closer.
  1283. */
  1284. ObjectClass * o = Array[newcell].Cell_Occupier();
  1285. while (o != NULL) {
  1286. /*
  1287. ** Special case check to ignore cloaked object if not allied with the player.
  1288. */
  1289. // Change for client/server multiplayer. ST - 8/7/2019 10:35AM
  1290. //if (!o->Is_Techno() || ((TechnoClass *)o)->IsOwnedByPlayer || ((TechnoClass *)o)->Cloak != CLOAKED) {
  1291. if (!o->Is_Techno() || !((TechnoClass *)o)->Is_Cloaked(PlayerPtr)) {
  1292. int d=-1;
  1293. if (o->What_Am_I() == RTTI_BUILDING) {
  1294. d = Distance(coord, Cell_Coord(newcell));
  1295. if (d > 0x00C0) d = -1;
  1296. } else {
  1297. d = Distance(coord, o->Center_Coord());
  1298. }
  1299. if (d >= 0 && (!object || d < distance)) {
  1300. distance = d;
  1301. object = o;
  1302. }
  1303. }
  1304. o = o->Next;
  1305. }
  1306. }
  1307. }
  1308. /*
  1309. ** Handle aircraft selection separately, since they aren't tracked in cells while flying
  1310. */
  1311. for (int index = 0; index < Aircraft.Count(); index++) {
  1312. AircraftClass * aircraft = Aircraft.Ptr(index);
  1313. if (aircraft->In_Which_Layer() != LAYER_GROUND) {
  1314. if (!aircraft->Is_Cloaked(PlayerPtr)) {
  1315. int d = Distance(coord, Coord_Add(aircraft->Center_Coord(), XY_Coord(0, -aircraft->Height)));
  1316. if (d >= 0 && (!object || d < distance)) {
  1317. distance = d;
  1318. object = aircraft;
  1319. }
  1320. }
  1321. }
  1322. }
  1323. /*
  1324. ** Only return the object if it is within 1/4 cell distance from the specified
  1325. ** coordinate.
  1326. */
  1327. if (object && distance > 0xC0) {
  1328. object = 0;
  1329. }
  1330. return(object);
  1331. }
  1332. /***********************************************************************************************
  1333. * MapClass::Zone_Reset -- Resets all zone numbers to match the map. *
  1334. * *
  1335. * This routine will rescan the map and fill in the zone values for each of the cells. *
  1336. * All cells that are contiguous are given the same zone number. *
  1337. * *
  1338. * INPUT: method -- The method to recalculate the zones upon. If 1 then recalc non *
  1339. * crushable zone. If 2 then recalc crushable zone. If 3, then *
  1340. * recalc both zones. *
  1341. * *
  1342. * OUTPUT: none *
  1343. * *
  1344. * WARNINGS: This is a time consuming routine. Call it as infrequently as possible. It must *
  1345. * be called whenever something that would affect contiguousness occurs. Example: *
  1346. * when a bridge is built or destroyed. *
  1347. * *
  1348. * HISTORY: *
  1349. * 09/22/1995 JLB : Created. *
  1350. *=============================================================================================*/
  1351. bool MapClass::Zone_Reset(int method)
  1352. {
  1353. /*
  1354. ** Zero out all zones to a null state.
  1355. */
  1356. for (int index = 0; index < MAP_CELL_TOTAL; index++) {
  1357. if (method & MZONEF_NORMAL) {
  1358. Array[index].Zones[MZONE_NORMAL] = 0;
  1359. }
  1360. if (method & MZONEF_CRUSHER) {
  1361. Array[index].Zones[MZONE_CRUSHER] = 0;
  1362. }
  1363. if (method & MZONEF_DESTROYER) {
  1364. Array[index].Zones[MZONE_DESTROYER] = 0;
  1365. }
  1366. if (method & MZONEF_WATER) {
  1367. Array[index].Zones[MZONE_WATER] = 0;
  1368. }
  1369. }
  1370. /*
  1371. ** Normal zone recalculation.
  1372. */
  1373. if (method & MZONEF_NORMAL) {
  1374. int zone = 1; // Starting zone number.
  1375. for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) {
  1376. if (Zone_Span(cell, zone, MZONE_NORMAL)) {
  1377. zone++;
  1378. }
  1379. }
  1380. }
  1381. /*
  1382. ** Crushable wall recalculation.
  1383. */
  1384. if (method & MZONEF_CRUSHER) {
  1385. int zone = 1; // Starting zone number.
  1386. for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) {
  1387. if (Zone_Span(cell, zone, MZONE_CRUSHER)) {
  1388. zone++;
  1389. }
  1390. }
  1391. }
  1392. /*
  1393. ** Wall destroyer zone recalculation.
  1394. */
  1395. if (method & MZONEF_DESTROYER) {
  1396. int zone = 1; // Starting zone number.
  1397. for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) {
  1398. if (Zone_Span(cell, zone, MZONE_DESTROYER)) {
  1399. zone++;
  1400. }
  1401. }
  1402. }
  1403. /*
  1404. ** Water based zone recalcuation.
  1405. */
  1406. if (method & MZONEF_WATER) {
  1407. int zone = 1; // Starting zone number.
  1408. for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) {
  1409. if (Zone_Span(cell, zone, MZONE_WATER)) {
  1410. zone++;
  1411. }
  1412. }
  1413. }
  1414. return(false);
  1415. }
  1416. /***********************************************************************************************
  1417. * MapClass::Zone_Span -- Flood fills the specified zone from the cell origin. *
  1418. * *
  1419. * This routine is used to fill a zone value into the map. The map is "flood filled" from *
  1420. * the cell specified. All adjacent (8 connected) and generally passable terrain cells are *
  1421. * given the zone number specified. This routine checks for legality before filling *
  1422. * occurs. The routine is safe to call even if the legality of the cell is unknown at the *
  1423. * time of the call. *
  1424. * *
  1425. * INPUT: cell -- The cell to begin filling from. *
  1426. * *
  1427. * zone -- The zone number to assign to all adjacent cells. *
  1428. * *
  1429. * check -- The zone type to check against. *
  1430. * *
  1431. * OUTPUT: Returns with the number of cells marked by this routine. *
  1432. * *
  1433. * WARNINGS: This routine is slow and recursive. Only use when necessary. *
  1434. * *
  1435. * HISTORY: *
  1436. * 09/25/1995 JLB : Created. *
  1437. * 10/05/1996 JLB : Examines crushable walls. *
  1438. *=============================================================================================*/
  1439. int MapClass::Zone_Span(CELL cell, int zone, MZoneType check)
  1440. {
  1441. int filled = 0;
  1442. int xbegin = Cell_X(cell);
  1443. int xend = xbegin;
  1444. int y = Cell_Y(cell);
  1445. /*
  1446. ** Perform some preliminary legality checks. If the cell specified
  1447. ** is illegal, then no further processing is necessary.
  1448. */
  1449. if (y < MapCellY || y >= MapCellY+MapCellHeight || xbegin < MapCellX || xbegin >= MapCellX+MapCellWidth) {
  1450. return(0);
  1451. }
  1452. /*
  1453. ** Find the full extent of the current span by first scanning leftward
  1454. ** until a boundary is reached.
  1455. */
  1456. for (; xbegin >= MapCellX; xbegin--) {
  1457. CellClass * cellptr = &(*this)[XY_Cell(xbegin, y)];
  1458. if (cellptr->Zones[check] != 0 || (!cellptr->Is_Clear_To_Move(check == MZONE_WATER ? SPEED_FLOAT : SPEED_TRACK, true, true, -1, check))) {
  1459. /*
  1460. ** Special short circuit code to bail from this entire routine if
  1461. ** it was called for a cell that is not a legal candidate for
  1462. ** zone marking. This eliminates redundant processing and allows this
  1463. ** routine to be called for illegal cells without causing an error.
  1464. */
  1465. if (xbegin == Cell_X(cell)) return(0);
  1466. /*
  1467. ** Otherwise break out of the left scan since a boundary was discovered.
  1468. */
  1469. xbegin++;
  1470. break;
  1471. }
  1472. }
  1473. xbegin = max(xbegin, MapCellX);
  1474. /*
  1475. ** Scan rightward until a boundary is reached. This will then define the
  1476. ** extent of the current span.
  1477. */
  1478. for (; xend < MapCellX+MapCellWidth; xend++) {
  1479. CellClass * cellptr = &(*this)[XY_Cell(xend, y)];
  1480. if (cellptr->Zones[check] != 0 || (!cellptr->Is_Clear_To_Move(check == MZONE_WATER ? SPEED_FLOAT : SPEED_TRACK, true, true, -1, check))) {
  1481. xend--;
  1482. break;
  1483. }
  1484. }
  1485. xend = min(xend, MapCellX+MapCellWidth-1);
  1486. /*
  1487. ** At this point we know the bounds of the current span. Fill in the zone values
  1488. ** for the entire span.
  1489. */
  1490. for (int x = xbegin; x <= xend; x++) {
  1491. (*this)[XY_Cell(x, y)].Zones[check] = zone;
  1492. filled++;
  1493. }
  1494. /*
  1495. ** Now scan the upper and lower shadow rows. If any of these rows contain
  1496. ** candidate cells, then recursively call the span process for them. Take
  1497. ** note that the adjacent span scanning starts one cell wider on each
  1498. ** end of the scan. This is necessary because diagonals are considered
  1499. ** adjacent.
  1500. */
  1501. for (int x = xbegin-1; x <= xend; x++) {
  1502. filled += Zone_Span(XY_Cell(x, y-1), zone, check);
  1503. filled += Zone_Span(XY_Cell(x, y+1), zone, check);
  1504. }
  1505. return(filled);
  1506. }
  1507. /***********************************************************************************************
  1508. * MapClass::Nearby_Location -- Finds a generally clear location near a specified cell. *
  1509. * *
  1510. * This routine is used to find a location that probably will be ok to move to that is *
  1511. * located as close as possible to the specified cell. The computer uses this when it has *
  1512. * determined the ideal location for an object, but then needs to give a valid movement *
  1513. * destination to a unit. *
  1514. * *
  1515. * INPUT: cell -- The cell that scanning should radiate out from. *
  1516. * *
  1517. * zone -- The zone that must be matched to find a legal location (value of -1 means *
  1518. * any zone will do). *
  1519. * *
  1520. * *
  1521. * check -- The type of zone to check against. Only valid if a zone value is given. *
  1522. * *
  1523. * checkflagged -- Whether the cell's flagged status is checked (used when dropping). *
  1524. * *
  1525. * OUTPUT: Returns with the cell that is generally clear (legal to move to) that is close *
  1526. * to the specified cell. *
  1527. * *
  1528. * WARNINGS: none *
  1529. * *
  1530. * HISTORY: *
  1531. * 10/05/1995 JLB : Created. *
  1532. *=============================================================================================*/
  1533. CELL MapClass::Nearby_Location(CELL cell, SpeedType speed, int zone, MZoneType check, bool checkflagged, int locationmod) const
  1534. {
  1535. CELL topten[10];
  1536. int count = 0;
  1537. int xx = Cell_X(cell);
  1538. int yy = Cell_Y(cell);
  1539. /*
  1540. ** Determine the limits of the scanning in the four directions so that
  1541. ** it won't scan past the edge of the world.
  1542. */
  1543. int left = MapCellX;
  1544. int right = MapCellX + MapCellWidth - 1;
  1545. int top = MapCellY;
  1546. int bottom = MapCellY + MapCellHeight - 1;
  1547. /*
  1548. ** Radiate outward from the specified location, looking for the closest
  1549. ** location that is generally clear.
  1550. */
  1551. for (int radius = 0; radius < MAP_CELL_W; radius++) {
  1552. CELL newcell;
  1553. CellClass const * cellptr;
  1554. /*
  1555. ** Scan the top and bottom rows of the "box".
  1556. */
  1557. for (int x = xx-radius; x <= xx+radius; x++) {
  1558. if (x >= left && x <= right) {
  1559. int y = yy-radius;
  1560. if (y >= top) {
  1561. newcell = XY_Cell(x, y);
  1562. cellptr = &Map[newcell];
  1563. if (Map.In_Radar(newcell) && cellptr->Is_Clear_To_Move(speed, false, false, zone, check) && (!checkflagged || !cellptr->IsFlagged)) {
  1564. topten[count++] = newcell;
  1565. }
  1566. }
  1567. if (count == ARRAY_SIZE(topten)) break;
  1568. y = yy+radius;
  1569. if (y <= bottom) {
  1570. newcell = XY_Cell(x, y);
  1571. cellptr = &Map[newcell];
  1572. if (Map.In_Radar(newcell) && cellptr->Is_Clear_To_Move(speed, false, false, zone, check) && (!checkflagged || !cellptr->IsFlagged)) {
  1573. topten[count++] = newcell;
  1574. }
  1575. }
  1576. if (count == ARRAY_SIZE(topten)) break;
  1577. }
  1578. }
  1579. if (count == ARRAY_SIZE(topten)) break;
  1580. /*
  1581. ** Scan the left and right columns of the "box".
  1582. */
  1583. for (int y = yy-radius; y <= yy+radius; y++) {
  1584. if (y >= top && y <= bottom) {
  1585. int x = xx-radius;
  1586. if (x >= left) {
  1587. newcell = XY_Cell(x, y);
  1588. cellptr = &Map[newcell];
  1589. if (Map.In_Radar(newcell) && cellptr->Is_Clear_To_Move(speed, false, false, zone, check) && (!checkflagged || !cellptr->IsFlagged)) {
  1590. topten[count++] = newcell;
  1591. }
  1592. }
  1593. if (count == ARRAY_SIZE(topten)) break;
  1594. x = xx+radius;
  1595. if (x <= right) {
  1596. newcell = XY_Cell(x, y);
  1597. cellptr = &Map[newcell];
  1598. if (Map.In_Radar(newcell) && cellptr->Is_Clear_To_Move(speed, false, false, zone, check) && (!checkflagged || !cellptr->IsFlagged)) {
  1599. topten[count++] = newcell;
  1600. }
  1601. }
  1602. if (count == ARRAY_SIZE(topten)) break;
  1603. }
  1604. }
  1605. if (count > 0) break;
  1606. }
  1607. if (count > 0) {
  1608. return(topten[(Frame+locationmod) % count]);
  1609. }
  1610. return(0);
  1611. }
  1612. /***********************************************************************************************
  1613. * MapClass::Base_Region -- Finds the owner and base zone for specified cell. *
  1614. * *
  1615. * This routine is used to determine what base the specified cell is close to and what *
  1616. * zone of that base the cell lies in. This routine is particularly useful in letting the *
  1617. * computer know when the player targets a destination near a computer's base. *
  1618. * *
  1619. * INPUT: cell -- The cell that is to be checked. *
  1620. * *
  1621. * house -- Reference to the house type number. This value will be set if a base *
  1622. * was found nearby the specified cell. *
  1623. * *
  1624. * zone -- The zone that the cell is located in IF the cell is near a base. *
  1625. * *
  1626. * *
  1627. * OUTPUT: Was a base near the specified cell found? If not, then the 'house' and 'zone' *
  1628. * reference values are left in an undefined state and the return value will be *
  1629. * false. *
  1630. * *
  1631. * WARNINGS: none *
  1632. * *
  1633. * HISTORY: *
  1634. * 10/05/1995 JLB : Created. *
  1635. *=============================================================================================*/
  1636. bool MapClass::Base_Region(CELL cell, HousesType & house, ZoneType & zone) const
  1637. {
  1638. if ((unsigned)cell < MAP_CELL_TOTAL && In_Radar(cell)) {
  1639. for (house = HOUSE_FIRST; house < HOUSE_COUNT; house++) {
  1640. HouseClass * h = HouseClass::As_Pointer(house);
  1641. if (h && h->IsActive && !h->IsDefeated && h->Center) {
  1642. zone = h->Which_Zone(cell);
  1643. if (zone != ZONE_NONE) {
  1644. return(true);
  1645. }
  1646. }
  1647. }
  1648. }
  1649. return(false);
  1650. }
  1651. /***********************************************************************************************
  1652. * MapClass::Destroy_Bridge_At -- Destroyes the bridge at location specified. *
  1653. * *
  1654. * This routine will destroy the bridge at the location specified. *
  1655. * *
  1656. * INPUT: cell -- A cell that can uniquely identify the bridge. *
  1657. * *
  1658. * OUTPUT: bool; Was the bridge destroyed? *
  1659. * *
  1660. * WARNINGS: none *
  1661. * *
  1662. * HISTORY: *
  1663. * 07/29/1996 JLB : Created. *
  1664. *=============================================================================================*/
  1665. // Need to inform the server of the cell change so it can communicate with the clients - SKY
  1666. extern void On_Update_Map_Cell(int cell_x, int cell_y, const char* template_type_name);
  1667. struct CellUpdateStruct
  1668. {
  1669. const TemplateTypeClass* Type;
  1670. CELL Cell;
  1671. };
  1672. static const int MAX_UPDATES = 8;
  1673. static void Add_Cell_Update(CellUpdateStruct* updates, int& count, TemplateType type, CELL cell)
  1674. {
  1675. new TemplateClass(type, cell);
  1676. assert(count < MAX_UPDATES);
  1677. if (count < MAX_UPDATES)
  1678. {
  1679. updates[count].Type = TemplateTypes.Ptr((int)type);
  1680. updates[count].Cell = cell;
  1681. count++;
  1682. }
  1683. }
  1684. bool MapClass::Destroy_Bridge_At(CELL cell)
  1685. {
  1686. bool destroyed = false;
  1687. if (In_Radar(cell) && !Special.IsCaptureTheFlag) {
  1688. CellClass * cellptr = &(*this)[cell];
  1689. TemplateType ttype = cellptr->TType;
  1690. CellUpdateStruct cell_updates[MAX_UPDATES];
  1691. int update_count = 0;
  1692. if (ttype == TEMPLATE_BRIDGE1 || ttype == TEMPLATE_BRIDGE2) {
  1693. int icon = cellptr->TIcon;
  1694. int w = TemplateTypeClass::As_Reference(ttype).Width;
  1695. int h = TemplateTypeClass::As_Reference(ttype).Height;
  1696. cell -= icon % w;
  1697. cell -= MAP_CELL_W * (icon / w);
  1698. if (ttype == TEMPLATE_BRIDGE1) {
  1699. Add_Cell_Update(cell_updates, update_count, TEMPLATE_BRIDGE1H, cell);
  1700. } else {
  1701. Add_Cell_Update(cell_updates, update_count, TEMPLATE_BRIDGE2H, cell);
  1702. }
  1703. new AnimClass(ANIM_NAPALM3, Cell_Coord(cell + w/2 + (h/2)*MAP_CELL_W));
  1704. }
  1705. if (ttype == TEMPLATE_BRIDGE1H || ttype == TEMPLATE_BRIDGE2H) {
  1706. int icon = cellptr->TIcon;
  1707. int bridge_w = TemplateTypeClass::As_Reference(ttype).Width;
  1708. int bridge_h = TemplateTypeClass::As_Reference(ttype).Height;
  1709. cell -= icon % bridge_w;
  1710. cell -= MAP_CELL_W * (icon / bridge_w);
  1711. if (ttype == TEMPLATE_BRIDGE1H) {
  1712. Add_Cell_Update(cell_updates, update_count, TEMPLATE_BRIDGE1D, cell);
  1713. } else {
  1714. Add_Cell_Update(cell_updates, update_count, TEMPLATE_BRIDGE2D, cell);
  1715. }
  1716. Scen.BridgeCount--;
  1717. Scen.IsBridgeChanged = true;
  1718. new AnimClass(ANIM_NAPALM3, Cell_Coord(cell + bridge_w/2 + (bridge_h/2)*MAP_CELL_W));
  1719. Map.Zone_Reset(MZONEF_ALL);
  1720. /*
  1721. ** Now, loop through all the bridge cells and find anyone standing
  1722. ** on a destroyed part (which is now river), and nuke them.
  1723. */
  1724. CELL cell2 = cell;
  1725. for (int y = 0; y < bridge_h; y++) {
  1726. for (int x = 0; x < bridge_w; x++) {
  1727. CellClass * bridge_cell = &(*this)[cell2];
  1728. if (bridge_cell->TType == ttype) {
  1729. /*
  1730. ** Any unit that is firing on the bridge at this location, will stop
  1731. ** firing because the bridge has been destroyed.
  1732. */
  1733. Detach_This_From_All(As_Target(cell2), true);
  1734. ObjectClass * obj = bridge_cell->Cell_Occupier();
  1735. while (obj != NULL) {
  1736. ObjectClass * next = obj->Next;
  1737. if (obj->Is_Techno()) {
  1738. int damage = obj->Strength;
  1739. obj->Take_Damage(damage, 0, WARHEAD_HE, NULL, true);
  1740. }
  1741. obj = next;
  1742. }
  1743. }
  1744. cell2++;
  1745. }
  1746. cell2 += MAP_CELL_W - bridge_w;
  1747. }
  1748. Shake_The_Screen(3);
  1749. destroyed = true;
  1750. } else {
  1751. /*
  1752. ** All this code is for the multi-part bridges.
  1753. */
  1754. if (ttype >= TEMPLATE_BRIDGE_1A && ttype <= TEMPLATE_BRIDGE_3E) {
  1755. int icon = cellptr->TIcon;
  1756. int w = TemplateTypeClass::As_Reference(ttype).Width;
  1757. int h = TemplateTypeClass::As_Reference(ttype).Height;
  1758. cell -= icon % w;
  1759. cell -= MAP_CELL_W * (icon / w);
  1760. switch (ttype) {
  1761. case TEMPLATE_BRIDGE_1A:
  1762. case TEMPLATE_BRIDGE_1B:
  1763. case TEMPLATE_BRIDGE_2A:
  1764. case TEMPLATE_BRIDGE_2B:
  1765. case TEMPLATE_BRIDGE_3A:
  1766. case TEMPLATE_BRIDGE_3B:
  1767. ttype++;
  1768. Add_Cell_Update(cell_updates, update_count, ttype, cell);
  1769. break;
  1770. }
  1771. /*
  1772. ** If we were a middle piece that just got blown up, update the
  1773. ** adjoining pieces to make sure they're shaped properly.
  1774. */
  1775. if (ttype == TEMPLATE_BRIDGE_3C) {
  1776. // check the template below us, at x-1, y+1
  1777. CELL cell2 = cell + (MAP_CELL_W - 1);
  1778. CellClass * celptr = &(*this)[cell2];
  1779. if (celptr->TType == TEMPLATE_BRIDGE_3C) {
  1780. // It was also destroyed. Update us and it.
  1781. Add_Cell_Update(cell_updates, update_count, TEMPLATE_BRIDGE_3D, cell);
  1782. Add_Cell_Update(cell_updates, update_count, TEMPLATE_BRIDGE_3E, cell2);
  1783. }
  1784. // Now check the template above us, at x+1, y-1.
  1785. cell2 = cell - (MAP_CELL_W - 1);
  1786. celptr = &(*this)[cell2];
  1787. if (celptr->TType == TEMPLATE_BRIDGE_3C) {
  1788. if (cellptr->TType == TEMPLATE_BRIDGE_3D) {
  1789. // if we're already one-sided, turn us to all water
  1790. Add_Cell_Update(cell_updates, update_count, TEMPLATE_BRIDGE_3F, cell);
  1791. } else {
  1792. Add_Cell_Update(cell_updates, update_count, TEMPLATE_BRIDGE_3E, cell);
  1793. }
  1794. Add_Cell_Update(cell_updates, update_count, TEMPLATE_BRIDGE_3D, cell2);
  1795. }
  1796. Map.Zone_Reset(MZONEF_ALL);
  1797. }
  1798. /*
  1799. ** If we're an end bridge piece, update the adjoining piece to
  1800. ** be the proper shape.
  1801. */
  1802. if (cellptr->TType == TEMPLATE_BRIDGE_1C) {
  1803. Scen.BridgeCount--;
  1804. Scen.IsBridgeChanged = true;
  1805. // Point to the template below us, x-1, y+2
  1806. CELL cell2 = cell + (MAP_CELL_W * 2) - 1;
  1807. switch ((*this)[cell2].TType) {
  1808. case TEMPLATE_BRIDGE_3A:
  1809. case TEMPLATE_BRIDGE_3B:
  1810. case TEMPLATE_BRIDGE_3C:
  1811. Add_Cell_Update(cell_updates, update_count, TEMPLATE_BRIDGE_3E, cell2);
  1812. break;
  1813. case TEMPLATE_BRIDGE_3D:
  1814. Add_Cell_Update(cell_updates, update_count, TEMPLATE_BRIDGE_3F, cell2);
  1815. break;
  1816. }
  1817. } else {
  1818. if (cellptr->TType == TEMPLATE_BRIDGE_2C) {
  1819. // Point to the template above us, x+2, y-1
  1820. CELL cell2 = cell - (MAP_CELL_W - 2);
  1821. switch ((*this)[cell2].TType) {
  1822. case TEMPLATE_BRIDGE_3A:
  1823. case TEMPLATE_BRIDGE_3B:
  1824. case TEMPLATE_BRIDGE_3C:
  1825. Add_Cell_Update(cell_updates, update_count, TEMPLATE_BRIDGE_3D, cell2);
  1826. break;
  1827. case TEMPLATE_BRIDGE_3E:
  1828. Add_Cell_Update(cell_updates, update_count, TEMPLATE_BRIDGE_3F, cell2);
  1829. break;
  1830. }
  1831. }
  1832. }
  1833. if (cellptr->TType == TEMPLATE_BRIDGE_1C ||
  1834. cellptr->TType == TEMPLATE_BRIDGE_2C ||
  1835. (cellptr->TType >= TEMPLATE_BRIDGE_3C && cellptr->TType <= TEMPLATE_BRIDGE_3E)) {
  1836. int x, y, tdata = 0;
  1837. for (y = 0; y < h; y++) {
  1838. for (x = 0; x < w; x++) {
  1839. CellClass * ptr = &(*this)[(CELL)(cell + x)];
  1840. if (ptr->TType == cellptr->TType || ptr->Land_Type() == LAND_RIVER || ptr->Land_Type() == LAND_WATER) {
  1841. Detach_This_From_All(As_Target((CELL)(cell+tdata)), true);
  1842. ObjectClass * obj = ptr->Cell_Occupier();
  1843. while (obj != NULL) {
  1844. ObjectClass * next = obj->Next;
  1845. if (obj->Is_Techno()) {
  1846. int damage = obj->Strength;
  1847. obj->Take_Damage(damage, 0, WARHEAD_HE, NULL, true);
  1848. }
  1849. obj = next;
  1850. }
  1851. }
  1852. tdata++;
  1853. }
  1854. cell += MAP_CELL_W;
  1855. }
  1856. Map.Zone_Reset(MZONEF_ALL);
  1857. destroyed = true;
  1858. }
  1859. Shake_The_Screen(3);
  1860. }
  1861. }
  1862. int cell_index = 0;
  1863. char cell_name[_MAX_PATH] = { 0 };
  1864. char icon_number[32] = { 0 };
  1865. int icon = 0;
  1866. void *image_data = 0;
  1867. for (int i = 0; i < update_count; i++) {
  1868. const TemplateTypeClass* type = cell_updates[i].Type;
  1869. CELL cell = cell_updates[i].Cell;
  1870. for (int y = 0; y < type->Height; y++) {
  1871. for (int x = 0; x < type->Width; x++) {
  1872. CELL newcell = cell + y * MAP_CELL_W + x;
  1873. if (Map.In_Radar(newcell)) {
  1874. CellClass * newcellptr = &Map[newcell];
  1875. if (newcellptr->Get_Template_Info(cell_name, icon, image_data)) {
  1876. itoa(icon, icon_number, 10);
  1877. strncat(cell_name, "_i", 32);
  1878. strncat(cell_name, icon_number, 32);
  1879. strncat(cell_name, ".tga", 32);
  1880. On_Update_Map_Cell(Cell_X(newcell), Cell_Y(newcell), cell_name);
  1881. }
  1882. }
  1883. }
  1884. }
  1885. }
  1886. }
  1887. return(destroyed);
  1888. }
  1889. /***********************************************************************************************
  1890. * MapClass::Detach -- Remove specified object from map references. *
  1891. * *
  1892. * This routine will take the object (represented by a target value) and remove all *
  1893. * references to it from the map. Typically, this is used to remove trigger reference. *
  1894. * *
  1895. * INPUT: target -- The target object to remove from the map. *
  1896. * *
  1897. * OUTPUT: none *
  1898. * *
  1899. * WARNINGS: none *
  1900. * *
  1901. * HISTORY: *
  1902. * 07/28/1996 JLB : Created. *
  1903. *=============================================================================================*/
  1904. void MapClass::Detach(TARGET target, bool)
  1905. {
  1906. /*
  1907. ** Remove this trigger from the map zone/line tracking list.
  1908. */
  1909. if (Is_Target_Trigger(target)) {
  1910. for (int index = 0; index < MapTriggers.Count(); index++) {
  1911. if (MapTriggers[index] == As_Trigger(target)) {
  1912. MapTriggers.Delete(index);
  1913. break;
  1914. }
  1915. }
  1916. /*
  1917. ** Loop through all cells; remove any reference to this trigger
  1918. */
  1919. for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) {
  1920. if ((*this)[cell].Trigger == As_Trigger(target)) {
  1921. (*this)[cell].Trigger = NULL;
  1922. }
  1923. }
  1924. }
  1925. }
  1926. /***********************************************************************************************
  1927. * MapClass::Intact_Bridge_Count -- Determine the number of intact bridges. *
  1928. * *
  1929. * This will examine the entire map and return the number of bridges that are intact. An *
  1930. * intact bridge is one that units can travel over. *
  1931. * *
  1932. * INPUT: none *
  1933. * *
  1934. * OUTPUT: Returns with the number of intact bridges on the map. *
  1935. * *
  1936. * WARNINGS: none *
  1937. * *
  1938. * HISTORY: *
  1939. * 07/28/1996 JLB : Created. *
  1940. *=============================================================================================*/
  1941. int MapClass::Intact_Bridge_Count(void) const
  1942. {
  1943. /*
  1944. ** Count all non-destroyed bridges on the map.
  1945. */
  1946. int count = 0;
  1947. CellClass const * cellptr = &(*this)[(CELL)0];
  1948. for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) {
  1949. switch (cellptr->TType) {
  1950. case TEMPLATE_BRIDGE1:
  1951. case TEMPLATE_BRIDGE1H:
  1952. case TEMPLATE_BRIDGE2:
  1953. case TEMPLATE_BRIDGE2H:
  1954. case TEMPLATE_BRIDGE_1A:
  1955. case TEMPLATE_BRIDGE_1B:
  1956. if (cellptr->TIcon == 6) {
  1957. count++;
  1958. }
  1959. break;
  1960. default:
  1961. break;
  1962. }
  1963. cellptr++;
  1964. }
  1965. return(count);
  1966. }
  1967. /***********************************************************************************************
  1968. * MapClass::Pick_Random_Location -- Picks a random location on the map. *
  1969. * *
  1970. * This routine will pick a random location on the map. It performs no legality checking *
  1971. * other than forcing the cell to be on the map proper. *
  1972. * *
  1973. * INPUT: none *
  1974. * *
  1975. * OUTPUT: Returns with a cell that is within the map. *
  1976. * *
  1977. * WARNINGS: none *
  1978. * *
  1979. * HISTORY: *
  1980. * 09/25/1996 JLB : Created. *
  1981. *=============================================================================================*/
  1982. CELL MapClass::Pick_Random_Location(void) const
  1983. {
  1984. int x = Map.MapCellX + Random_Pick(0, Map.MapCellWidth-1);
  1985. int y = Map.MapCellY + Random_Pick(0, Map.MapCellHeight-1);
  1986. return(XY_Cell(x, y));
  1987. }
  1988. #if (1)
  1989. /***********************************************************************************************
  1990. * MapClass::Shroud_The_Map -- cover the whole map in darkness (usually from blackout crate) *
  1991. * *
  1992. * INPUT: House to shroud *
  1993. * *
  1994. * OUTPUT: None
  1995. * *
  1996. * WARNINGS: none *
  1997. * *
  1998. * HISTORY: *
  1999. * 10/19/1996 BWG : Created. *
  2000. * 08/12/2019 ST : Updated for client/server multiplayer *
  2001. *=============================================================================================*/
  2002. void MapClass::Shroud_The_Map(HouseClass *house)
  2003. {
  2004. for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) {
  2005. CellClass * cellptr = &Map[cell];
  2006. if (cellptr->Is_Mapped(house) || cellptr->Is_Visible(house)) {
  2007. cellptr->Redraw_Objects();
  2008. /*
  2009. ** BG: remove "ring of darkness" around edge of map.
  2010. */
  2011. int x = Cell_X(cell);
  2012. int y = Cell_Y(cell);
  2013. if (x >= Map.MapCellX && x < (Map.MapCellX + Map.MapCellWidth) &&
  2014. y >= Map.MapCellY && y < (Map.MapCellY + Map.MapCellHeight)) {
  2015. cellptr->Set_Mapped(house, false);
  2016. cellptr->Set_Visible(house, false);
  2017. }
  2018. }
  2019. }
  2020. for (int obj_index = 0; obj_index < DisplayClass::Layer[LAYER_GROUND].Count(); obj_index++) {
  2021. ObjectClass * layer_object = DisplayClass::Layer[LAYER_GROUND][obj_index];
  2022. if (layer_object && layer_object->Is_Techno() && ((TechnoClass *)layer_object)->House == house) {
  2023. layer_object->Look();
  2024. }
  2025. }
  2026. Flag_To_Redraw(true);
  2027. }
  2028. #else
  2029. //
  2030. // Old code for posterity. ST - 8/12/2019 11:34AM
  2031. //
  2032. /***********************************************************************************************
  2033. * MapClass::Shroud_The_Map -- cover the whole map in darkness (usually from blackout crate) *
  2034. * *
  2035. * INPUT: none *
  2036. * *
  2037. * OUTPUT: Returns with a cell that is within the map. *
  2038. * *
  2039. * WARNINGS: none *
  2040. * *
  2041. * HISTORY: *
  2042. * 10/19/1996 BWG : Created. *
  2043. *=============================================================================================*/
  2044. void MapClass::Shroud_The_Map(void)
  2045. {
  2046. for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) {
  2047. CellClass * cellptr = &Map[cell];
  2048. if (cellptr->IsMapped || cellptr->IsVisible) {
  2049. cellptr->Redraw_Objects();
  2050. /*
  2051. ** BG: remove "ring of darkness" around edge of map.
  2052. */
  2053. int x = Cell_X(cell);
  2054. int y = Cell_Y(cell);
  2055. if (x >= Map.MapCellX && x < (Map.MapCellX + Map.MapCellWidth) &&
  2056. y >= Map.MapCellY && y < (Map.MapCellY + Map.MapCellHeight)) {
  2057. cellptr->IsMapped = false;
  2058. cellptr->IsVisible = false;
  2059. }
  2060. }
  2061. }
  2062. for (int obj_index = 0; obj_index < DisplayClass::Layer[LAYER_GROUND].Count(); obj_index++) {
  2063. ObjectClass * layer_object = DisplayClass::Layer[LAYER_GROUND][obj_index];
  2064. if (layer_object && layer_object->Is_Techno() && ((TechnoClass *)layer_object)->House == PlayerPtr) {
  2065. layer_object->Look();
  2066. }
  2067. }
  2068. Flag_To_Redraw(true);
  2069. }
  2070. #endif