DISPLAY.CPP 191 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509
  1. /*
  2. ** Command & Conquer Red Alert(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /* $Header: /CounterStrike/DISPLAY.CPP 3 3/09/97 8:04p Joe_bostic $ */
  19. /***********************************************************************************************
  20. *** 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 ***
  21. ***********************************************************************************************
  22. * *
  23. * Project Name : Command & Conquer *
  24. * *
  25. * File Name : DISPLAY.CPP *
  26. * *
  27. * Programmer : Joe L. Bostic *
  28. * *
  29. * Start Date : September 10, 1993 *
  30. * *
  31. * Last Update : October 20, 1996 [JLB] *
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * Functions: *
  35. * DisplayClass::Compute_Start_Pos -- Computes player's start pos from unit coords. *
  36. * DisplayClass::AI -- Handles the maintenance tasks for the map display. *
  37. * DisplayClass::All_To_Look -- Direct all objects to look around for the player. *
  38. * DisplayClass::Calculated_Cell -- Fetch a map cell based on specified method. *
  39. * DisplayClass::Cell_Object -- Determines what has been clicked on. *
  40. * DisplayClass::Cell_Shadow -- Determine what shadow icon to use for the cell. *
  41. * DisplayClass::Center_Map -- Centers the map about the currently selected objects *
  42. * DisplayClass::Click_Cell_Calc -- Determines cell from screen X & Y. *
  43. * DisplayClass::Closest_Free_Spot -- Finds the closest cell sub spot that is free. *
  44. * DisplayClass::Coord_To_Pixel -- Determines X and Y pixel coordinates. *
  45. * DisplayClass::Cursor_Mark -- Set or resets the cursor display flag bits. *
  46. * DisplayClass::DisplayClass -- Default constructor for display class. *
  47. * DisplayClass::Draw_It -- Draws the tactical map. *
  48. * DisplayClass::Encroach_Shadow -- Causes the shadow to creep back by one cell. *
  49. * DisplayClass::Flag_Cell -- Flag the specified cell to be redrawn. *
  50. * DisplayClass::Flag_To_Redraw -- Flags the display so that it will be redrawn as soon as poss*
  51. * DisplayClass::Get_Occupy_Dimensions -- computes width & height of the given occupy list *
  52. * DisplayClass::Good_Reinforcement_Cell -- Checks cell for renforcement legality. *
  53. * DisplayClass::In_View -- Determines if cell is visible on screen. *
  54. * DisplayClass::Init_Clear -- Clears the display to a known state. *
  55. * DisplayClass::Init_IO -- Creates the map's button list *
  56. * DisplayClass::Init_Theater -- Theater-specific initialization *
  57. * DisplayClass::Is_Spot_Free -- Determines if cell sub spot is free of occupation. *
  58. * DisplayClass::Map_Cell -- Mark specified cell as having been mapped. *
  59. * DisplayClass::Mouse_Left_Held -- Handles the left button held down. *
  60. * DisplayClass::Mouse_Left_Press -- Handles the left mouse button press. *
  61. * DisplayClass::Mouse_Left_Release -- Handles the left mouse button release. *
  62. * DisplayClass::Mouse_Left_Up -- Handles the left mouse "cruising" over the map. *
  63. * DisplayClass::Mouse_Right_Press -- Handles the right mouse button press. *
  64. * DisplayClass::Next_Object -- Searches for next object on display. *
  65. * DisplayClass::One_Time -- Performs any special one time initializations. *
  66. * DisplayClass::Passes_Proximity_Check -- Determines if building placement is near friendly sq*
  67. * DisplayClass::Pixel_To_Coord -- converts screen coord to COORDINATE *
  68. * DisplayClass::Prev_Object -- Searches for the previous object on the map. *
  69. * DisplayClass::Read_INI -- Reads map control data from INI file. *
  70. * DisplayClass::Redraw_Icons -- Draws all terrain icons necessary. *
  71. * DisplayClass::Redraw_Shadow -- Draw the shadow overlay. *
  72. * DisplayClass::Refresh_Band -- Causes all cells under the rubber band to be redrawn. *
  73. * DisplayClass::Refresh_Cells -- Redraws all cells in list. *
  74. * DisplayClass::Remove -- Removes a game object from the rendering system. *
  75. * DisplayClass::Repair_Mode_Control -- Controls the repair mode. *
  76. * DisplayClass::Scroll_Map -- Scroll the tactical map in desired direction. *
  77. * DisplayClass::Select_These -- All selectable objects in region are selected. *
  78. * DisplayClass::Sell_Mode_Control -- Controls the sell mode. *
  79. * DisplayClass::Set_Cursor_Pos -- Controls the display and animation of the tac cursor. *
  80. * DisplayClass::Set_Cursor_Shape -- Changes the shape of the terrain square cursor. *
  81. * DisplayClass::Set_Tactical_Position -- Sets the tactical view position. *
  82. * DisplayClass::Set_View_Dimensions -- Sets the tactical display screen coordinates. *
  83. * DisplayClass::Shroud_Cell -- Returns the specified cell into the shrouded condition. *
  84. * DisplayClass::Submit -- Adds a game object to the map rendering system. *
  85. * DisplayClass::TacticalClass::Action -- Processes input for the tactical map. *
  86. * DisplayClass::Text_Overlap_List -- Creates cell overlap list for specified text string. *
  87. * DisplayClass::Write_INI -- Write the map data to the INI file specified. *
  88. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  89. #include "function.h"
  90. #include "vortex.h"
  91. /*
  92. ** These layer control elements are used to group the displayable objects
  93. ** so that proper overlap can be obtained.
  94. */
  95. LayerClass DisplayClass::Layer[LAYER_COUNT];
  96. /*
  97. ** Fading tables
  98. */
  99. unsigned char DisplayClass::FadingBrighten[256];
  100. unsigned char DisplayClass::FadingShade[256];
  101. unsigned char DisplayClass::FadingWayDark[256];
  102. unsigned char DisplayClass::FadingLight[256];
  103. unsigned char DisplayClass::FadingGreen[256];
  104. unsigned char DisplayClass::FadingYellow[256];
  105. unsigned char DisplayClass::FadingRed[256];
  106. unsigned char DisplayClass::TranslucentTable[(MAGIC_COL_COUNT+1)*256];
  107. unsigned char DisplayClass::WhiteTranslucentTable[(1+1)*256];
  108. unsigned char DisplayClass::MouseTranslucentTable[(4+1)*256];
  109. void const * DisplayClass::TransIconset;
  110. unsigned char DisplayClass::UnitShadow[(USHADOW_COL_COUNT+1)*256];
  111. unsigned char DisplayClass::UnitShadowAir[(USHADOW_COL_COUNT+1)*256];
  112. unsigned char DisplayClass::SpecialGhost[2*256];
  113. void const * DisplayClass::ShadowShapes;
  114. unsigned char DisplayClass::ShadowTrans[(SHADOW_COL_COUNT+1)*256];
  115. /*
  116. ** Bit array of cell redraw flags
  117. */
  118. BooleanVectorClass DisplayClass::CellRedraw;
  119. /*
  120. ** The main button that intercepts user input to the map
  121. */
  122. DisplayClass::TacticalClass DisplayClass::TacButton;
  123. static int const TEX_X = 0;
  124. static int const TEX_Y = 6;
  125. static int const TEX_W = 14;
  126. /***********************************************************************************************
  127. * DisplayClass::DisplayClass -- Default constructor for display class. *
  128. * *
  129. * This constructor for the display class just initializes some of the display settings. *
  130. * Most settings are initialized with the correct values at the time that the Init function *
  131. * is called. There are some cases where default values are wise and this routine fills *
  132. * those particular ones in. *
  133. * *
  134. * INPUT: none *
  135. * *
  136. * OUTPUT: none *
  137. * *
  138. * WARNINGS: none *
  139. * *
  140. * HISTORY: *
  141. * 12/06/1994 JLB : Created. *
  142. *=============================================================================================*/
  143. DisplayClass::DisplayClass(void) :
  144. TacticalCoord(0),
  145. TacLeptonWidth(0),
  146. TacLeptonHeight(0),
  147. ZoneCell(0),
  148. ZoneOffset(0),
  149. CursorSize(0),
  150. ProximityCheck(false),
  151. PendingObjectPtr(0),
  152. PendingObject(0),
  153. PendingHouse(HOUSE_NONE),
  154. TacPixelX(0),
  155. TacPixelY(0),
  156. DesiredTacticalCoord(0),
  157. IsToRedraw(true),
  158. IsRepairMode(false),
  159. IsSellMode(false),
  160. IsTargettingMode(SPC_NONE),
  161. IsRubberBand(false),
  162. IsTentative(false),
  163. IsShadowPresent(false),
  164. BandX(0),
  165. BandY(0),
  166. NewX(0),
  167. NewY(0)
  168. {
  169. ShadowShapes = 0;
  170. TransIconset = 0;
  171. Set_View_Dimensions(0, 8, 320/CELL_PIXEL_W, 200/CELL_PIXEL_H);
  172. }
  173. /***********************************************************************************************
  174. * DisplayClass::One_Time -- Performs any special one time initializations. *
  175. * *
  176. * This routine is called from the game initialization process. It is to perform any one *
  177. * time initializations necessary for the map display system. It allocates the staging *
  178. * buffer needed for the radar map. *
  179. * *
  180. * INPUT: none *
  181. * *
  182. * OUTPUT: none *
  183. * *
  184. * WARNINGS: This routine must be called ONCE and only once. *
  185. * *
  186. * HISTORY: *
  187. * 05/31/1994 JLB : Created. *
  188. * 05/31/1994 JLB : Handles layer system now. *
  189. * 06/02/1994 JLB : Takes care of misc display tables and data allocation. *
  190. *=============================================================================================*/
  191. void DisplayClass::One_Time(void)
  192. {
  193. MapClass::One_Time();
  194. /*
  195. ** Init the CellRedraw bit array. Do not do this in the constructor, since the
  196. ** BooleanVector may not have been constructed yet.
  197. */
  198. CellRedraw.Resize(MAP_CELL_TOTAL);
  199. for (LayerType layer = LAYER_FIRST; layer < LAYER_COUNT; layer++) {
  200. Layer[layer].One_Time();
  201. }
  202. /*
  203. ** Load the generic transparent icon set.
  204. */
  205. TransIconset = MFCD::Retrieve("TRANS.ICN");
  206. #ifndef NDEBUG
  207. RawFileClass file("SHADOW.SHP");
  208. if (file.Is_Available()) {
  209. ShadowShapes = Load_Alloc_Data(file);
  210. } else {
  211. ShadowShapes = MFCD::Retrieve("SHADOW.SHP");
  212. }
  213. #else
  214. ShadowShapes = MFCD::Retrieve("SHADOW.SHP");
  215. #endif
  216. Set_View_Dimensions(0, 8 * RESFACTOR);
  217. }
  218. /***********************************************************************************************
  219. * DisplayClass::Init_Clear -- clears the display to a known state *
  220. * *
  221. * INPUT: *
  222. * none. *
  223. * *
  224. * OUTPUT: *
  225. * none. *
  226. * *
  227. * WARNINGS: *
  228. * none. *
  229. * *
  230. * HISTORY: *
  231. * 03/17/1995 BRR : Created. *
  232. *=============================================================================================*/
  233. void DisplayClass::Init_Clear(void)
  234. {
  235. MapClass::Init_Clear();
  236. /*
  237. ** Clear any object being placed
  238. */
  239. PendingObjectPtr = 0;
  240. PendingObject = 0;
  241. PendingHouse = HOUSE_NONE;
  242. CursorSize = 0;
  243. IsTargettingMode = SPC_NONE;
  244. IsRepairMode = false;
  245. IsRubberBand = false;
  246. IsTentative = false;
  247. IsSellMode = false;
  248. /*
  249. ** Empty all the display's layers
  250. */
  251. for (LayerType layer = LAYER_FIRST; layer < LAYER_COUNT; layer++) {
  252. Layer[layer].Init();
  253. }
  254. }
  255. /***********************************************************************************************
  256. * DisplayClass::Init_IO -- clears & re-builds the map's button list *
  257. * *
  258. * INPUT: *
  259. * none. *
  260. * *
  261. * OUTPUT: *
  262. * none. *
  263. * *
  264. * WARNINGS: *
  265. * none. *
  266. * *
  267. * HISTORY: *
  268. * 03/17/1995 BRR : Created. *
  269. *=============================================================================================*/
  270. void DisplayClass::Init_IO(void)
  271. {
  272. MapClass::Init_IO();
  273. /*
  274. ** Re-attach our buttons to the main map button list, only in non-edit mode.
  275. */
  276. if (!Debug_Map) {
  277. TacButton.Zap();
  278. Add_A_Button(TacButton);
  279. }
  280. }
  281. /***********************************************************************************************
  282. * DisplayClass::Init_Theater -- Performs theater-specific initialization (mixfiles, etc) *
  283. * *
  284. * INPUT: *
  285. * theater new theater *
  286. * *
  287. * OUTPUT: *
  288. * none. *
  289. * *
  290. * WARNINGS: *
  291. * none. *
  292. * *
  293. * HISTORY: *
  294. * 03/17/1995 BRR : Created. *
  295. * 05/07/1996 JLB : Added translucent tables. *
  296. *=============================================================================================*/
  297. void DisplayClass::Init_Theater(TheaterType theater)
  298. {
  299. char fullname[16];
  300. static TLucentType const MouseCols[4] = {
  301. {BLACK, BLACK, 110, 0},
  302. {WHITE, WHITE, 110, 0},
  303. {LTGREY, LTGREY, 110, 0},
  304. {DKGREY, DKGREY, 110, 0}
  305. };
  306. static TLucentType const MagicCols[MAGIC_COL_COUNT] = {
  307. {32,32,110,0},
  308. {33,33,110,0},
  309. {34,34,110,0},
  310. {35,35,110,0},
  311. {36,36,110,0},
  312. {37,37,110,0},
  313. {38,38,110,0},
  314. {39,39,110,0},
  315. {BLACK, BLACK, 200, 0},
  316. {WHITE, BLACK, 40, 0},
  317. {LTGREY, BLACK, 80, 0},
  318. {DKGREY, BLACK, 140, 0},
  319. {LTGREEN, BLACK,130,0}
  320. };
  321. static TLucentType const WhiteCols[1] = {
  322. {1, WHITE, 80, 0}
  323. };
  324. static TLucentType const ShadowCols[SHADOW_COL_COUNT] = {
  325. {WHITE+1, BLACK,130,0},
  326. {WHITE, BLACK,170,0},
  327. {LTGRAY, BLACK,250,0},
  328. {DKGRAY, BLACK,250,0}
  329. };
  330. static TLucentType const UShadowCols[USHADOW_COL_COUNT] = {
  331. {LTGREEN, BLACK,130,0}
  332. };
  333. static TLucentType const UShadowColsAir[USHADOW_COL_COUNT] = {
  334. {LTGREEN, WHITE,0,0}
  335. };
  336. static TLucentType const UShadowColsSnow[USHADOW_COL_COUNT] = {
  337. {LTGREEN, BLACK,75,0}
  338. };
  339. /*
  340. ** Invoke parent's init routine.
  341. */
  342. MapClass::Init_Theater(theater);
  343. /*
  344. ** Save the new theater value
  345. */
  346. Scen.Theater = theater;
  347. /*
  348. ** Unload old mixfiles, and cache the new ones
  349. */
  350. sprintf(fullname, "%s.MIX", Theaters[theater].Root);
  351. #ifndef WIN32
  352. LastTheater = THEATER_NONE;
  353. #endif
  354. if (Scen.Theater != LastTheater) {
  355. if (TheaterData != NULL) {
  356. delete TheaterData;
  357. }
  358. TheaterData = new MFCD(fullname, &FastKey);
  359. assert(TheaterData != NULL);
  360. bool theaterload = TheaterData->Cache(TheaterBuffer);
  361. assert(theaterload);
  362. // LastTheater = Scen.Theater;
  363. }
  364. /*
  365. ** Load the custom palette associated with this theater.
  366. ** The fading palettes will have to be generated as well.
  367. */
  368. sprintf(fullname, "%s.PAL", Theaters[theater].Root);
  369. PaletteClass const * ptr = (PaletteClass *)MFCD::Retrieve(fullname);
  370. GamePalette = * ptr;
  371. OriginalPalette = GamePalette;
  372. Build_Fading_Table(GamePalette, FadingGreen, GREEN, 110);
  373. Build_Fading_Table(GamePalette, FadingYellow, YELLOW, 140);
  374. Build_Fading_Table(GamePalette, FadingRed, RED, 140);
  375. Build_Translucent_Table(GamePalette, &MouseCols[0], 4, MouseTranslucentTable);
  376. Build_Translucent_Table(GamePalette, &MagicCols[0], MAGIC_COL_COUNT, TranslucentTable);
  377. Build_Translucent_Table(GamePalette, &WhiteCols[0], 1, WhiteTranslucentTable);
  378. Build_Translucent_Table(GamePalette, &ShadowCols[0], SHADOW_COL_COUNT, ShadowTrans);
  379. Conquer_Build_Translucent_Table(GamePalette, &UShadowColsAir[0], USHADOW_COL_COUNT, UnitShadowAir);
  380. memcpy(&UnitShadowAir[256], ColorRemaps[PCOLOR_GOLD].RemapTable, sizeof(ColorRemaps[PCOLOR_GOLD].RemapTable));
  381. if (theater == THEATER_SNOW) {
  382. Conquer_Build_Translucent_Table(GamePalette, &UShadowColsSnow[0], USHADOW_COL_COUNT, UnitShadow);
  383. } else {
  384. Conquer_Build_Translucent_Table(GamePalette, &UShadowCols[0], USHADOW_COL_COUNT, UnitShadow);
  385. }
  386. if (theater == THEATER_SNOW) {
  387. Conquer_Build_Fading_Table(GamePalette, FadingShade, BLACK, 75);
  388. } else {
  389. Conquer_Build_Fading_Table(GamePalette, FadingShade, BLACK, 130);
  390. }
  391. Conquer_Build_Fading_Table(GamePalette, FadingLight, WHITE, 85);
  392. /*
  393. ** Create the shadow color used by aircraft.
  394. */
  395. Conquer_Build_Fading_Table(GamePalette, &SpecialGhost[256], BLACK, 100);
  396. for (int index = 0; index < 256; index++) {
  397. SpecialGhost[index] = 0;
  398. }
  399. Make_Fading_Table(GamePalette, FadingBrighten, WHITE, 25);
  400. Make_Fading_Table(GamePalette, FadingWayDark, DKGRAY, 192);
  401. /*
  402. ** Adjust the palette according to the visual control option settings.
  403. */
  404. Options.Fixup_Palette();
  405. }
  406. /***********************************************************************************************
  407. * DisplayClass::Text_Overlap_List -- Creates cell overlap list for specified text string. *
  408. * *
  409. * This routine is used to create an overlap list that specifies all the cells that are *
  410. * covered by the specified text string. This overlap list is used to handle map refresh *
  411. * logic. *
  412. * *
  413. * INPUT: text -- Pointer to the text that would appear on the map and must have an *
  414. * overlap list generated. *
  415. * *
  416. * x,y -- The coordinates that the text would appear (upper left corner). *
  417. * *
  418. * OUTPUT: Returns with a pointer to an overlap list that covers all cells "under" the text *
  419. * if were displayed at the coordinates specified. The list is actually a series of *
  420. * offsets from the display's upper left corner cell number. *
  421. * *
  422. * WARNINGS: none *
  423. * *
  424. * HISTORY: *
  425. * 12/06/1994 JLB : Created. *
  426. * 12/07/1994 JLB : Sidebar fixup. *
  427. * 08/13/1995 JLB : Optimized for variable sized help text. *
  428. *=============================================================================================*/
  429. short const * DisplayClass::Text_Overlap_List(char const * text, int x, int y) const
  430. {
  431. static short _list[60];
  432. int count = ARRAY_SIZE(_list);
  433. if (text != NULL) {
  434. short * ptr = &_list[0];
  435. int len = String_Pixel_Width(text)+CELL_PIXEL_W;
  436. int right = TacPixelX + Lepton_To_Pixel(TacLeptonWidth);
  437. /*
  438. ** If the help text would spill into the sidebar, then flag this fact, but
  439. ** shorten the apparent length so that the icon list calculation will
  440. ** function correctly.
  441. */
  442. if (x+len >= TacPixelX+Lepton_To_Pixel(TacLeptonWidth)) {
  443. len = right-x;
  444. *ptr++ = REFRESH_SIDEBAR;
  445. count--;
  446. }
  447. /*
  448. ** Build the list of overlap cell offset values according to the text
  449. ** coordinate and the length.
  450. */
  451. if (x <= right) {
  452. CELL ul = Click_Cell_Calc(x, y-1);
  453. CELL lr = Click_Cell_Calc(x+len-1, Bound(y+24, TacPixelY, TacPixelY+Lepton_To_Pixel(TacLeptonHeight) - 1));
  454. if (ul == -1) ul = Click_Cell_Calc(x, y);
  455. if (ul != -1 && lr != -1) {
  456. for (int yy = Cell_Y(ul); yy <= Cell_Y(lr); yy++) {
  457. for (int xx = Cell_X(ul); xx <= Cell_X(lr); xx++) {
  458. *ptr++ = XY_Cell(xx, yy) - Coord_Cell(TacticalCoord);
  459. count--;
  460. if (count < 2) break;
  461. }
  462. if (count < 2) break;
  463. }
  464. }
  465. }
  466. *ptr = REFRESH_EOL;
  467. }
  468. return(_list);
  469. }
  470. /***********************************************************************************************
  471. * DisplayClass::Set_View_Dimensions -- Sets the tactical display screen coordinates. *
  472. * *
  473. * Use this routine to set the tactical map screen coordinates and dimensions. This routine *
  474. * is typically used when the screen size or position changes as a result of the sidebar *
  475. * changing position or appearance. *
  476. * *
  477. * INPUT: x,y -- The X and Y pixel position on the screen for the tactical map upper left *
  478. * corner. *
  479. * *
  480. * width -- The width of the tactical display (in icons). If this parameter is *
  481. * omitted, then the width will be as wide as the screen will allow. *
  482. * *
  483. * height-- The height of the tactical display (in icons). If this parameter is *
  484. * omitted, then the width will be as wide as the screen will allow. *
  485. * *
  486. * OUTPUT: none *
  487. * *
  488. * WARNINGS: none *
  489. * *
  490. * HISTORY: *
  491. * 12/06/1994 JLB : Created. *
  492. * 06/27/1995 JLB : Adjusts tactical map position if necessary. *
  493. *=============================================================================================*/
  494. void DisplayClass::Set_View_Dimensions(int x, int y, int width, int height)
  495. {
  496. if (width == -1) {
  497. TacLeptonWidth = Pixel_To_Lepton(SeenBuff.Get_Width()-x);
  498. } else {
  499. TacLeptonWidth = width * CELL_LEPTON_W;
  500. }
  501. if (height == -1) {
  502. height = (SeenBuff.Get_Height()-y) / CELL_PIXEL_H;
  503. }
  504. TacLeptonHeight = height * CELL_LEPTON_H;
  505. /*
  506. ** Adjust the tactical cell if it is now in an invalid position
  507. ** because of the changed dimensions.
  508. */
  509. int xx = Coord_X(TacticalCoord) - (MapCellX * CELL_LEPTON_W);
  510. int yy = Coord_Y(TacticalCoord) - (MapCellY * CELL_LEPTON_H);
  511. Confine_Rect(&xx, &yy, TacLeptonWidth, TacLeptonHeight, MapCellWidth * CELL_LEPTON_W, MapCellHeight * CELL_LEPTON_H);
  512. Set_Tactical_Position(XY_Coord(xx + (MapCellX * CELL_LEPTON_W), yy + (MapCellY * CELL_LEPTON_H)));
  513. TacPixelX = x;
  514. TacPixelY = y;
  515. WindowList[WINDOW_TACTICAL][WINDOWX] = x;
  516. WindowList[WINDOW_TACTICAL][WINDOWY] = y;
  517. WindowList[WINDOW_TACTICAL][WINDOWWIDTH] = Lepton_To_Pixel(TacLeptonWidth);
  518. WindowList[WINDOW_TACTICAL][WINDOWHEIGHT] = Lepton_To_Pixel(TacLeptonHeight);
  519. if (Window == WINDOW_TACTICAL) {
  520. Change_Window(0);
  521. Change_Window(Window);
  522. }
  523. IsToRedraw = true;
  524. Flag_To_Redraw(false);
  525. TacButton.X = TacPixelX;
  526. TacButton.Y = TacPixelY;
  527. TacButton.Width = Lepton_To_Pixel(TacLeptonWidth);
  528. TacButton.Height = Lepton_To_Pixel(TacLeptonHeight);
  529. }
  530. /***********************************************************************************************
  531. * DisplayClass::Set_Cursor_Shape -- Changes the shape of the terrain square cursor. *
  532. * *
  533. * This routine is used to set up the terrain cursor according to the size of the object *
  534. * that is to be placed down. The terrain cursor looks like an arbitrary collection of *
  535. * hatched square overlays. Typical use is when placing buildings. *
  536. * *
  537. * INPUT: list -- A pointer to the list that contains offsets to the cells that are to *
  538. * be marked. *
  539. * *
  540. * OUTPUT: none *
  541. * *
  542. * WARNINGS: none *
  543. * *
  544. * HISTORY: *
  545. * 06/03/1994 JLB : Created. *
  546. * 06/26/1995 JLB : Puts placement cursor into static buffer. *
  547. *=============================================================================================*/
  548. void DisplayClass::Set_Cursor_Shape(short const * list)
  549. {
  550. if (CursorSize) {
  551. Cursor_Mark(ZoneCell+ZoneOffset, false);
  552. }
  553. ZoneOffset = 0;
  554. if (list) {
  555. int w,h;
  556. static short _list[50];
  557. memcpy(_list, list, sizeof(_list));
  558. CursorSize = _list;
  559. Get_Occupy_Dimensions (w, h, CursorSize);
  560. ZoneOffset = -(((h/2)*MAP_CELL_W)+(w/2));
  561. Cursor_Mark(ZoneCell+ZoneOffset, true);
  562. } else {
  563. CursorSize = 0;
  564. }
  565. }
  566. /***********************************************************************************************
  567. * DisplayClass::Passes_Proximity_Check -- Determines if building placement is near friendly sq*
  568. * *
  569. * This routine is used by the building placement cursor logic to determine whether the *
  570. * at the current cursor position if the building would be adjacent to another friendly *
  571. * building. In cases where this is not true, then the building cannot be placed at all. *
  572. * This determination is returned by the function. *
  573. * *
  574. * INPUT: object -- The building object that the current placement system is examining. *
  575. * *
  576. * house -- The house to base the proximity check upon. Typically this is the *
  577. * player's house, but in multiplay, the computer needs to check for *
  578. * proximity as well. *
  579. * *
  580. * list -- Pointer to the building's offset list. *
  581. * *
  582. * trycell -- The cell to base the offset list on. *
  583. * *
  584. * OUTPUT: bool; Can the pending building object be placed at the present cursor location *
  585. * checking only for proximity to friendly buildings? If this isn't for a *
  586. * building type object, then this routine always returns true. *
  587. * *
  588. * WARNINGS: none *
  589. * *
  590. * HISTORY: *
  591. * 06/06/1994 JLB : Created. *
  592. * 06/07/1994 JLB : Handles concrete check. *
  593. * 10/11/1994 BWG : Added IsProximate check for ore refineries *
  594. *=============================================================================================*/
  595. bool DisplayClass::Passes_Proximity_Check(ObjectTypeClass const * object, HousesType house, short const * list, CELL trycell) const
  596. {
  597. short const * ptr;
  598. int retval = -1;
  599. bool noradar = false;
  600. bool nomapped = false;
  601. bool shipyard = false;
  602. if (house == PlayerPtr->Class->House) {
  603. PassedProximity = false;
  604. }
  605. /*
  606. ** In editor mode, the proximity check always passes.
  607. */
  608. if (Debug_Map) {
  609. return(true);
  610. }
  611. if (list == NULL || trycell == 0) {
  612. return(true);
  613. }
  614. if (object == NULL || object->What_Am_I() != RTTI_BUILDINGTYPE) {
  615. return(true);
  616. }
  617. BuildingTypeClass const * building = (BuildingTypeClass const *)object;
  618. /*
  619. ** Scan through all cells that the building foundation would cover. If any adjacent
  620. ** cells to these are of friendly persuasion, then consider the proximity check to
  621. ** have been a success.
  622. */
  623. ptr = list;
  624. // ptr = CursorSize;
  625. CELL cell = trycell;
  626. // CELL cell = ZoneCell;
  627. if (building->Adjacent == 1) {
  628. while (*ptr != REFRESH_EOL && (retval == -1) ) {
  629. cell = trycell + *ptr++;
  630. // cell = ZoneCell + ZoneOffset + *ptr++;
  631. if (!In_Radar(cell)) {
  632. retval = false;
  633. noradar = true;
  634. break;
  635. }
  636. for (FacingType facing = FACING_FIRST; facing < FACING_COUNT; facing++) {
  637. CELL newcell = Adjacent_Cell(cell, facing);
  638. if (!In_Radar(newcell)) continue;
  639. if (!(*this)[newcell].IsMapped) {
  640. nomapped = true;
  641. }
  642. TechnoClass * base = (*this)[newcell].Cell_Techno();
  643. /*
  644. ** The special cell ownership flag allows building adjacent
  645. ** to friendly walls and bibs even though there is no official
  646. ** building located there.
  647. */
  648. //BG: Modified so only walls can be placed next to walls - buildings can't.
  649. //JLB: Except for bibs, in which case buildings can be placed next to these.
  650. if (building->IsWall ||
  651. ((*this)[newcell].Smudge != SMUDGE_NONE && SmudgeTypeClass::As_Reference((*this)[newcell].Smudge).IsBib)) {
  652. if ((*this)[newcell].Owner == house) {
  653. retval = true;
  654. break;
  655. }
  656. }
  657. // we've found a building...
  658. if (base != NULL && base->What_Am_I() == RTTI_BUILDING && base->House->Class->House == house && ((BuildingClass *)base)->Class->IsBase) {
  659. retval = true;
  660. break;
  661. }
  662. /* BG: modifications to allow buildings one cell away from other buildings.
  663. ** This is done by scanning each cell that fails the check (hence getting
  664. ** to this point) and looking at the n/s/e/w adjacent cells to see if they
  665. ** have buildings in them. If they do, and they match us, then succeed.
  666. */
  667. if (retval != -1) break;
  668. for (FacingType newface = FACING_N; newface < FACING_COUNT; newface++) {
  669. CELL newercell = Adjacent_Cell(newcell, newface);
  670. if (building->IsWall ||
  671. ((*this)[newercell].Smudge != SMUDGE_NONE && SmudgeTypeClass::As_Reference((*this)[newercell].Smudge).IsBib)) {
  672. if ((*this)[newercell].Owner == house) {
  673. retval = true;
  674. break;
  675. }
  676. }
  677. TechnoClass * newbase = (*this)[newercell].Cell_Techno();
  678. // we've found a building...
  679. if (newbase != NULL && newbase->What_Am_I() == RTTI_BUILDING && newbase->House->Class->House == house && ((BuildingClass const *)newbase)->Class->IsBase) {
  680. retval = true;
  681. break;
  682. }
  683. }
  684. if (retval != -1) break;
  685. }
  686. }
  687. }
  688. if (retval == -1) retval = false;
  689. if (house == PlayerPtr->Class->House) {
  690. PassedProximity = (retval != false);
  691. }
  692. /*
  693. ** If this object has special dispensation to be placed further than one cell from
  694. ** other regular buildings, then check for this case now. Only bother to check if
  695. ** it hasn't already been given permission to be placed down.
  696. */
  697. if (!retval && !noradar && object->What_Am_I() == RTTI_BUILDINGTYPE) {
  698. // For land mines, let's make it check proximity within 10 squares
  699. if (building->Adjacent > 1) {
  700. for (int index = 0; index < Buildings.Count(); index++) {
  701. BuildingClass * obj = Buildings.Ptr(index);
  702. if (obj != NULL && !obj->IsInLimbo && obj->House->Class->House == house && obj->Class->IsBase) {
  703. int centdist = ::Distance(obj->Center_Coord(), Cell_Coord(cell));
  704. centdist /= CELL_LEPTON_W;
  705. centdist -= (obj->Class->Width() + obj->Class->Height()) / 2;
  706. if (centdist <= building->Adjacent) {
  707. retval = true;
  708. break;
  709. }
  710. }
  711. }
  712. }
  713. }
  714. return((bool)retval);
  715. }
  716. /***********************************************************************************************
  717. * DisplayClass::Set_Cursor_Pos -- Controls the display and animation of the tac cursor. *
  718. * *
  719. * This routine controls the location, display, and animation of the *
  720. * tactical map cursor. *
  721. * *
  722. * INPUT: pos -- Position to move the cursor do. If -1 is passed then *
  723. * the cursor will just be hidden. If the position *
  724. * passed is the same as the last position passed in, *
  725. * then animation could occur (based on timers). *
  726. * *
  727. * OUTPUT: none *
  728. * *
  729. * WARNINGS: none *
  730. * *
  731. * HISTORY: *
  732. * 05/22/1991 JLB : Created. *
  733. * 06/02/1994 JLB : Converted to member function. *
  734. * 06/08/1994 JLB : If position is -1, then follow mouse. *
  735. * 02/28/1995 JLB : Forces placement cursor to fit on map. *
  736. *=============================================================================================*/
  737. CELL DisplayClass::Set_Cursor_Pos(CELL pos)
  738. {
  739. CELL prevpos; // Last position of cursor (for jump-back reasons).
  740. /*
  741. ** Follow the mouse position if no cell number is provided.
  742. */
  743. if (pos == -1) {
  744. pos = Click_Cell_Calc(Get_Mouse_X(), Get_Mouse_Y());
  745. }
  746. if (CursorSize == NULL) {
  747. prevpos = ZoneCell;
  748. ZoneCell = pos;
  749. return(prevpos);
  750. }
  751. /*
  752. ** Adjusts the position so that the placement cursor is never part way off the
  753. ** tactical map.
  754. */
  755. int w,h;
  756. Get_Occupy_Dimensions(w, h, CursorSize);
  757. int x = Cell_X(pos + ZoneOffset);
  758. int y = Cell_Y(pos + ZoneOffset);
  759. if (x < Coord_XCell(TacticalCoord)) x = Coord_XCell(TacticalCoord);
  760. if (y < Coord_YCell(TacticalCoord)) y = Coord_YCell(TacticalCoord);
  761. if (x+w >= Coord_XCell(TacticalCoord) + Lepton_To_Cell(TacLeptonWidth)) x = Coord_XCell(TacticalCoord)+Lepton_To_Cell(TacLeptonWidth)-w;
  762. if (y+h >= Coord_YCell(TacticalCoord) + Lepton_To_Cell(TacLeptonHeight)) y = Coord_YCell(TacticalCoord)+Lepton_To_Cell(TacLeptonHeight)-h;
  763. pos = XY_Cell(x, y) - ZoneOffset;
  764. /*
  765. ** This checks to see if NO animation or drawing is to occur and, if so,
  766. ** exits.
  767. */
  768. if (pos == ZoneCell) return(pos);
  769. prevpos = ZoneCell;
  770. /*
  771. ** If the cursor is visible, then handle the graphic update.
  772. ** Otherwise, just update the global position of the cursor.
  773. */
  774. if (CursorSize != NULL) {
  775. /*
  776. ** Erase the old cursor (if it exists) AND the cursor is moving.
  777. */
  778. if (pos != ZoneCell && ZoneCell != -1) {
  779. Cursor_Mark(ZoneCell+ZoneOffset, false);
  780. }
  781. /*
  782. ** Render the cursor (could just be animation).
  783. */
  784. if (pos != -1) {
  785. Cursor_Mark(pos+ZoneOffset, true);
  786. }
  787. }
  788. ZoneCell = pos;
  789. ProximityCheck = Passes_Proximity_Check(PendingObject, PendingHouse, CursorSize, ZoneCell+ZoneOffset);
  790. return(prevpos);
  791. }
  792. /***********************************************************************************************
  793. * DisplayClass::Get_Occupy_Dimensions -- computes width & height of the given occupy list *
  794. * *
  795. * INPUT: *
  796. * w ptr to fill in with height *
  797. * h ptr to fill in with width *
  798. * *
  799. * OUTPUT: *
  800. * none. *
  801. * *
  802. * WARNINGS: *
  803. * none. *
  804. * *
  805. * HISTORY: *
  806. * 03/31/1995 BRR : Created. *
  807. *=============================================================================================*/
  808. void DisplayClass::Get_Occupy_Dimensions(int & w, int & h, short const * list) const
  809. {
  810. int min_x = MAP_CELL_W;
  811. int max_x = -MAP_CELL_W;
  812. int min_y = MAP_CELL_H;
  813. int max_y = -MAP_CELL_H;
  814. int x,y;
  815. w = 0;
  816. h = 0;
  817. if (!list) {
  818. /*
  819. ** Loop through all cell offsets, accumulating max & min x- & y-coords
  820. */
  821. while (*list != REFRESH_EOL) {
  822. /*
  823. ** Compute x & y coords of the current cell offset. We can't use Cell_X()
  824. ** & Cell_Y(), because they use shifts to compute the values, and if the
  825. ** offset is negative we'll get a bogus coordinate!
  826. */
  827. x = (*list) % MAP_CELL_W;
  828. y = (*list) / MAP_CELL_H;
  829. max_x = max(max_x, x);
  830. min_x = min(min_x, x);
  831. max_y = max(max_y, y);
  832. min_y = min(min_y, y);
  833. list++;
  834. }
  835. w = max(1, max_x - min_x + 1);
  836. h = min(1, max_y - min_y + 1);
  837. }
  838. }
  839. /***********************************************************************************************
  840. * DisplayClass::Cursor_Mark -- Set or resets the cursor display flag bits. *
  841. * *
  842. * This routine will clear or set the cursor display bits on the map. *
  843. * If the bit is set, then the cursor will be rendered on that map *
  844. * icon. *
  845. * *
  846. * INPUT: pos -- Position of the upper left corner of the cursor. *
  847. * *
  848. * on -- Should the bit be turned on? *
  849. * *
  850. * OUTPUT: none *
  851. * *
  852. * WARNINGS: Be sure that every call to set the bits is matched by a *
  853. * corresponding call to clear the bits. *
  854. * *
  855. * HISTORY: *
  856. * 09/04/1991 JLB : Created. *
  857. * 06/02/1994 JLB : Converted to member function. *
  858. *=============================================================================================*/
  859. void DisplayClass::Cursor_Mark(CELL pos, bool on)
  860. {
  861. CELL const * ptr;
  862. CellClass * cellptr;
  863. if (pos == -1) return;
  864. /*
  865. ** For every cell in the CursorSize list, invoke its Redraw_Objects and
  866. ** toggle its IsCursorHere flag
  867. */
  868. ptr = CursorSize;
  869. while (*ptr != REFRESH_EOL) {
  870. CELL cell = pos + *ptr++;
  871. if (In_Radar(cell)) {
  872. cellptr = &(*this)[cell];
  873. cellptr->Redraw_Objects();
  874. if (on) {
  875. cellptr->IsCursorHere = true;
  876. } else {
  877. cellptr->IsCursorHere = false;
  878. }
  879. }
  880. }
  881. /*
  882. ** For every cell in the PendingObjectPtr's Overlap_List, invoke its
  883. ** Redraw_Objects routine.
  884. */
  885. if (PendingObjectPtr) {
  886. ptr = PendingObjectPtr->Overlap_List();
  887. while (*ptr != REFRESH_EOL) {
  888. CELL cell = pos + *ptr++;
  889. if (In_Radar(cell)) {
  890. cellptr = &(*this)[cell];
  891. cellptr->Redraw_Objects();
  892. }
  893. }
  894. }
  895. }
  896. /***********************************************************************************************
  897. * DisplayClass::AI -- Handles the maintenance tasks for the map display. *
  898. * *
  899. * This routine is called once per game display frame (15 times per second). It handles *
  900. * the mouse shape tracking and map scrolling as necessary. *
  901. * *
  902. * INPUT: input -- The next key just fetched from the input queue. *
  903. * *
  904. * x,y -- Mouse coordinates. *
  905. * *
  906. * OUTPUT: Modifies the input code if necessary. When the input code is consumed, it gets *
  907. * set to 0. *
  908. * *
  909. * WARNINGS: none *
  910. * *
  911. * HISTORY: *
  912. * 06/01/1994 JLB : Created. *
  913. * 06/02/1994 JLB : Filters mouse click input. *
  914. * 06/07/1994 JLB : Fixed so template click will behave right. *
  915. * 10/14/1994 JLB : Changing cursor shape over target. *
  916. * 12/31/1994 JLB : Takes mouse coordinates as parameters. *
  917. * 06/27/1995 JLB : Breaks out of rubber band mode if mouse leaves map. *
  918. *=============================================================================================*/
  919. void DisplayClass::AI(KeyNumType & input, int x, int y)
  920. {
  921. if (
  922. IsRubberBand &&
  923. (Get_Mouse_X() < TacPixelX ||
  924. Get_Mouse_Y() < TacPixelY ||
  925. Get_Mouse_X() >= (TacPixelX + Lepton_To_Pixel(TacLeptonWidth)) ||
  926. Get_Mouse_Y() >= (TacPixelY + Lepton_To_Pixel(TacLeptonHeight)))) {
  927. Mouse_Left_Release(-1, Get_Mouse_X(), Get_Mouse_Y(), NULL, ACTION_NONE);
  928. }
  929. MapClass::AI(input, x, y);
  930. }
  931. /***********************************************************************************************
  932. * DisplayClass::Submit -- Adds a game object to the map rendering system. *
  933. * *
  934. * This routine is used to add an arbitrary (but tangible) game object to the map. It will *
  935. * be rendered (made visible) once it is submitted to this function. This function builds *
  936. * the list of game objects that get rendered each frame as necessary. It is possible to *
  937. * submit the game object to different rendering layers. All objects in a layer get drawn *
  938. * at the same time. Using this layer method it becomes possible to have objects "below" *
  939. * other objects. *
  940. * *
  941. * INPUT: object -- Pointer to the object to add. *
  942. * *
  943. * layer -- The layer to add the object to. *
  944. * *
  945. * OUTPUT: none *
  946. * *
  947. * WARNINGS: none *
  948. * *
  949. * HISTORY: *
  950. * 05/31/1994 JLB : Created. *
  951. * 05/31/1994 JLB : Improved layer system. *
  952. * 05/31/1994 JLB : Sorts object position if this is for the ground layer. *
  953. *=============================================================================================*/
  954. void DisplayClass::Submit(ObjectClass const * object, LayerType layer)
  955. {
  956. if (object) {
  957. Layer[layer].Submit(object, (layer == LAYER_GROUND));
  958. }
  959. }
  960. /***********************************************************************************************
  961. * DisplayClass::Remove -- Removes a game object from the rendering system. *
  962. * *
  963. * Every object that is to disappear from the map must be removed from the rendering *
  964. * system. *
  965. * *
  966. * INPUT: object -- The object to remove. *
  967. * *
  968. * layer -- The layer to remove it from. *
  969. * *
  970. * OUTPUT: none *
  971. * *
  972. * WARNINGS: none *
  973. * *
  974. * HISTORY: *
  975. * 05/31/1994 JLB : Created. *
  976. * 05/31/1994 JLB : Improved layer system. *
  977. *=============================================================================================*/
  978. void DisplayClass::Remove(ObjectClass const * object, LayerType layer)
  979. {
  980. assert(object != 0);
  981. assert(object->IsActive);
  982. if (object) {
  983. Layer[layer].Delete((ObjectClass *)object);
  984. }
  985. }
  986. /***********************************************************************************************
  987. * DisplayClass::Click_Cell_Calc -- Determines cell from screen X & Y. *
  988. * *
  989. * This routine is used to determine the cell that is located at the *
  990. * screen pixel coordinates given. Typical use is when the player *
  991. * clicks with the mouse on the tactical map. *
  992. * *
  993. * INPUT: x,y -- Screen pixel coordinates. *
  994. * *
  995. * OUTPUT: Returns with cell that is under the coordinates specified. *
  996. * If the coordinate specified is outside of the tactical *
  997. * map, then -1 is returned. *
  998. * *
  999. * WARNINGS: none *
  1000. * *
  1001. * HISTORY: *
  1002. * 05/27/1994 JLB : Created. *
  1003. *=============================================================================================*/
  1004. CELL DisplayClass::Click_Cell_Calc(int x, int y) const
  1005. {
  1006. x -= TacPixelX;
  1007. x = Pixel_To_Lepton(x);
  1008. y -= TacPixelY;
  1009. y = Pixel_To_Lepton(y);
  1010. if ((unsigned)x < TacLeptonWidth && (unsigned)y < TacLeptonHeight) {
  1011. COORDINATE tcoord = XY_Coord(Pixel_To_Lepton(Lepton_To_Pixel(Coord_X(TacticalCoord))), Pixel_To_Lepton(Lepton_To_Pixel(Coord_Y(TacticalCoord))));
  1012. return(Coord_Cell(Coord_Add(tcoord, XY_Coord(x, y))));
  1013. }
  1014. return(-1);
  1015. }
  1016. /***********************************************************************************************
  1017. * DisplayClass::Scroll_Map -- Scroll the tactical map in desired direction. *
  1018. * *
  1019. * This routine is used to scroll the tactical map view in the desired *
  1020. * direction. It can also be used to determine if scrolling would be *
  1021. * legal without actually performing any scrolling action. *
  1022. * *
  1023. * INPUT: facing -- The direction to scroll the tactical map. *
  1024. * *
  1025. * distance -- The distance in leptons to scroll the map. *
  1026. * *
  1027. * really -- Should the map actually be scrolled? If false, *
  1028. * then only the legality of a scroll is checked. *
  1029. * *
  1030. * OUTPUT: bool; Would scrolling in the desired direction be possible? *
  1031. * *
  1032. * WARNINGS: none *
  1033. * *
  1034. * HISTORY: *
  1035. * 10/07/1992 JLB : Created. *
  1036. * 05/20/1994 JLB : Converted to member function. *
  1037. * 08/09/1995 JLB : Added distance parameter. *
  1038. * 08/10/1995 JLB : Any direction scrolling. *
  1039. *=============================================================================================*/
  1040. bool DisplayClass::Scroll_Map(DirType facing, int & distance, bool really)
  1041. {
  1042. /*
  1043. ** If the distance is invalid then no further checking is required. Bail
  1044. ** with a no-can-do flag.
  1045. */
  1046. if (distance == 0) return(false);
  1047. FacingType crude = Dir_Facing(facing);
  1048. if (Coord_X(TacticalCoord) == Cell_To_Lepton(MapCellX) && crude != FACING_W) {
  1049. if (crude == FACING_SW) facing = DIR_S;
  1050. if (crude == FACING_NW) facing = DIR_N;
  1051. }
  1052. if (Coord_Y(TacticalCoord) == Cell_To_Lepton(MapCellY) && crude != FACING_N) {
  1053. if (crude == FACING_NW) facing = DIR_W;
  1054. if (crude == FACING_NE) facing = DIR_E;
  1055. }
  1056. if (Coord_X(TacticalCoord) + TacLeptonWidth == Cell_To_Lepton(MapCellX+MapCellWidth) && crude != FACING_E) {
  1057. if (crude == FACING_NE) facing = DIR_N;
  1058. if (crude == FACING_SE) facing = DIR_S;
  1059. }
  1060. if (Coord_Y(TacticalCoord) + TacLeptonHeight == Cell_To_Lepton(MapCellY+MapCellHeight) && crude != FACING_S) {
  1061. if (crude == FACING_SE) facing = DIR_E;
  1062. if (crude == FACING_SW) facing = DIR_W;
  1063. }
  1064. /*
  1065. ** Determine the coordinate that it wants to scroll to.
  1066. */
  1067. COORDINATE coord = Coord_Move(TacticalCoord, facing, distance);
  1068. /*
  1069. ** Clip the new coordinate to the edges of the game world.
  1070. */
  1071. int xx = (int)(short)Coord_X(coord) - (short)Cell_To_Lepton(MapCellX);
  1072. int yy = (int)(short)Coord_Y(coord) - (short)Cell_To_Lepton(MapCellY);
  1073. bool shifted = Confine_Rect(&xx, &yy, TacLeptonWidth, TacLeptonHeight, Cell_To_Lepton(MapCellWidth), Cell_To_Lepton(MapCellHeight));
  1074. if (xx < 0) {
  1075. xx = 0;
  1076. shifted = true;
  1077. }
  1078. if (yy < 0) {
  1079. yy = 0;
  1080. shifted = true;
  1081. }
  1082. coord = XY_Coord(xx + Cell_To_Lepton(MapCellX), yy + Cell_To_Lepton(MapCellY));
  1083. /*
  1084. ** If the desired scroll was bound by the edge of the map, then adjust the distance to more accurately
  1085. ** reflect the actual distance moved.
  1086. */
  1087. if (shifted) {
  1088. distance = Distance(TacticalCoord, coord);
  1089. }
  1090. /*
  1091. ** If the new coordinate is the same as the old, then no scrolling would occur.
  1092. */
  1093. if (!distance || coord == TacticalCoord) return(false);
  1094. /*
  1095. ** Since the new coordinate is different than the old one, possibly adjust the real
  1096. ** tactical map accordingly.
  1097. */
  1098. if (really) {
  1099. Set_Tactical_Position(coord);
  1100. IsToRedraw = true;
  1101. Flag_To_Redraw(false);
  1102. /*
  1103. ** Scrolled map REQUIRES all top layer units to be redrawn.
  1104. */
  1105. for (int index = 0; index < Layer[LAYER_TOP].Count(); index++) {
  1106. Layer[LAYER_TOP][index]->Mark(MARK_CHANGE);
  1107. }
  1108. for (index = 0; index < Layer[LAYER_AIR].Count(); index++) {
  1109. Layer[LAYER_AIR][index]->Mark(MARK_CHANGE);
  1110. }
  1111. }
  1112. return(true);
  1113. }
  1114. /***********************************************************************************************
  1115. * DisplayClass::Refresh_Cells -- Redraws all cells in list. *
  1116. * *
  1117. * This routine is used to flag all cells in the specified list for *
  1118. * redrawing. *
  1119. * *
  1120. * INPUT: cell -- The origin cell that the list is offset from. *
  1121. * *
  1122. * list -- Pointer to a list of offsets from the origin cell. *
  1123. * Each cell so specified is flagged for redraw. *
  1124. * *
  1125. * OUTPUT: none *
  1126. * *
  1127. * WARNINGS: This routine is rather slow (by definition). *
  1128. * *
  1129. * HISTORY: *
  1130. * 05/14/1994 JLB : Created. *
  1131. * 08/01/1994 JLB : Simplified. *
  1132. *=============================================================================================*/
  1133. void DisplayClass::Refresh_Cells(CELL cell, short const * list)
  1134. {
  1135. short tlist[36];
  1136. if (*list == REFRESH_SIDEBAR) {
  1137. list++;
  1138. }
  1139. List_Copy(list, ARRAY_SIZE(tlist), tlist);
  1140. short * tt = tlist;
  1141. while (*tt != REFRESH_EOL) {
  1142. CELL newcell = cell + *tt++;
  1143. if (In_Radar(newcell)) {
  1144. (*this)[newcell].Redraw_Objects();
  1145. }
  1146. }
  1147. }
  1148. /***********************************************************************************************
  1149. * DisplayClass::Cell_Shadow -- Determine what shadow icon to use for the cell. *
  1150. * *
  1151. * This routine will examine the specified cell and adjacent cells to *
  1152. * determine what shadow icon to use. *
  1153. * *
  1154. * INPUT: cell -- The cell to examine. *
  1155. * *
  1156. * OUTPUT: Returns with the shadow icon to use. -2= all black. *
  1157. * -1= map cell. *
  1158. * *
  1159. * WARNINGS: none *
  1160. * *
  1161. * HISTORY: *
  1162. * 03/01/1994 JLB : Created. *
  1163. * 04/04/1994 JLB : Revamped for new shadow icon method. *
  1164. * 04/30/1994 JLB : Converted to member function. *
  1165. *=============================================================================================*/
  1166. int DisplayClass::Cell_Shadow(CELL cell) const
  1167. {
  1168. static char const _shadow[256]={
  1169. -1,33, 2, 2,34,37, 2, 2,
  1170. 4,26, 6, 6, 4,26, 6, 6,
  1171. 35,45,17,17,38,41,17,17,
  1172. 4,26, 6, 6, 4,26, 6, 6,
  1173. 8,21,10,10,27,31,10,10,
  1174. 12,23,14,14,12,23,14,14,
  1175. 8,21,10,10,27,31,10,10,
  1176. 12,23,14,14,12,23,14,14,
  1177. 32,36,25,25,44,40,25,25,
  1178. 19,30,20,20,19,30,20,20,
  1179. 39,43,29,29,42,46,29,29,
  1180. 19,30,20,20,19,30,20,20,
  1181. 8,21,10,10,27,31,10,10,
  1182. 12,23,14,14,12,23,14,14,
  1183. 8,21,10,10,27,31,10,10,
  1184. 12,23,14,14,12,23,14,14,
  1185. 1, 1, 3, 3,16,16, 3, 3,
  1186. 5, 5, 7, 7, 5, 5, 7, 7,
  1187. 24,24,18,18,28,28,18,18,
  1188. 5, 5, 7, 7, 5, 5, 7, 7,
  1189. 9, 9,11,11,22,22,11,11,
  1190. 13,13,-2,-2,13,13,-2,-2,
  1191. 9, 9,11,11,22,22,11,11,
  1192. 13,13,-2,-2,13,13,-2,-2,
  1193. 1, 1, 3, 3,16,16, 3, 3,
  1194. 5, 5, 7, 7, 5, 5, 7, 7,
  1195. 24,24,18,18,28,28,18,18,
  1196. 5, 5, 7, 7, 5, 5, 7, 7,
  1197. 9, 9,11,11,22,22,11,11,
  1198. 13,13,-2,-2,13,13,-2,-2,
  1199. 9, 9,11,11,22,22,11,11,
  1200. 13,13,-2,-2,13,13,-2,-2
  1201. };
  1202. int index = 0, value = -1;
  1203. /*
  1204. ** Don't map cells that are at the top or bottom edge. This solves
  1205. ** problem of accessing cells off the top or bottom of the map and into
  1206. ** who-knows-what memory.
  1207. */
  1208. #ifdef FIXIT_CSII // checked - ajw 9/28/98
  1209. if ((unsigned)(Cell_Y(cell)-1) >= MAP_CELL_H-2) return(-1);
  1210. #else
  1211. if ((unsigned)(Cell_Y(cell)-1) > MAP_CELL_H-2) return(-1);
  1212. #endif
  1213. //if ((unsigned)(Cell_Y(cell)-1) > MAP_CELL_H-2) return(-2);
  1214. CellClass const * cellptr = &(*this)[cell];
  1215. /*
  1216. ** Presume solid black if that is what is here already.
  1217. */
  1218. if (!cellptr->IsVisible && !cellptr->IsMapped) value = -2;
  1219. if (cellptr->IsMapped /*&& !cellptr->IsVisible*/) {
  1220. /*
  1221. ** Build an index into the lookup table using all 8 surrounding cells.
  1222. ** We're mapping a revealed cell and we only care about the existence
  1223. ** of black cells. Bit numbering starts at the upper-right corner and
  1224. ** goes around the cell clockwise, so 0x80 = directly north.
  1225. */
  1226. cellptr-= MAP_CELL_W + 1;
  1227. if (!cellptr->IsMapped) index |= 0x40;
  1228. cellptr++;
  1229. if (!cellptr->IsMapped) index |= 0x80;
  1230. cellptr++;
  1231. if (!cellptr->IsMapped) index |= 0x01;
  1232. cellptr += MAP_CELL_W - 2;
  1233. if (!cellptr->IsMapped) index |= 0x20;
  1234. cellptr += 2;
  1235. if (!cellptr->IsMapped) index |= 0x02;
  1236. cellptr += MAP_CELL_W - 2;
  1237. if (!cellptr->IsMapped) index |= 0x10;
  1238. cellptr++;
  1239. if (!cellptr->IsMapped) index |= 0x08;
  1240. cellptr++;
  1241. if (!cellptr->IsMapped) index |= 0x04;
  1242. value = _shadow[index];
  1243. }
  1244. return(value);
  1245. }
  1246. /***********************************************************************************************
  1247. * DisplayClass::Map_Cell -- Mark specified cell as having been mapped. *
  1248. * *
  1249. * This routine maps the specified cell. The cell must not already *
  1250. * have been mapped and the mapping player must be the human. *
  1251. * This routine will update any adjacent cell map icon as appropriate. *
  1252. * *
  1253. * INPUT: cell -- The cell to be mapped. *
  1254. * *
  1255. * house -- The player that is doing the mapping. *
  1256. * *
  1257. * OUTPUT: bool; Was action taken to map this cell? *
  1258. * *
  1259. * WARNINGS: none. *
  1260. * *
  1261. * HISTORY: *
  1262. * 08/05/1992 JLB : Created. *
  1263. * 04/30/1994 JLB : Converted to member function. *
  1264. * 05/24/1994 JLB : Takes pointer to HouseClass. *
  1265. * 02/20/1996 JLB : Allied units reveal the map for the player. *
  1266. *=============================================================================================*/
  1267. bool DisplayClass::Map_Cell(CELL cell, HouseClass * house)
  1268. {
  1269. /*
  1270. ** First check for the condition where we're spying on a house's radar
  1271. ** facility, to see if his mapping is applicable to us.
  1272. */
  1273. if (house && house != PlayerPtr) {
  1274. if (house->RadarSpied & (1<<(PlayerPtr->Class->House))) house = PlayerPtr;
  1275. if (Session.Type == GAME_NORMAL && house->Is_Ally(PlayerPtr)) house = PlayerPtr;
  1276. }
  1277. if (house != PlayerPtr || !In_Radar(cell)) return(false);
  1278. CellClass * cellptr = &(*this)[cell];
  1279. /*
  1280. ** Don't bother remapping this cell if it is already mapped.
  1281. */
  1282. if (cellptr->IsMapped) {
  1283. if (!cellptr->IsVisible) {
  1284. cellptr->Redraw_Objects();
  1285. }
  1286. return(false);
  1287. }
  1288. /*
  1289. ** Mark the cell as being mapped. This must be done first because
  1290. ** if the IsVisible flag must be set, then it might affect the
  1291. ** adjacent cell processing.
  1292. */
  1293. cellptr->IsMapped = true;
  1294. cellptr->Redraw_Objects();
  1295. if (Cell_Shadow(cell) == -1) {
  1296. cellptr->IsVisible = true;
  1297. }
  1298. /*
  1299. ** Check out all adjacent cells to see if they need
  1300. ** to be mapped as well. This is necessary because of the
  1301. ** "unique" method of showing shadowed cells. Many combinations
  1302. ** are not allowed, and to fix this, just map the cells until
  1303. ** all is ok.
  1304. */
  1305. for (FacingType dir = FACING_FIRST; dir < FACING_COUNT; dir++) {
  1306. int shadow;
  1307. CELL c;
  1308. c = Adjacent_Cell(cell, dir);
  1309. CellClass * cptr = &(*this)[c];
  1310. cptr->Redraw_Objects();
  1311. if (c != cell && !cptr->IsVisible) {
  1312. shadow = Cell_Shadow(c);
  1313. if (shadow == -1) {
  1314. if (!cptr->IsMapped) {
  1315. Map_Cell(c, house);
  1316. } else {
  1317. cptr->IsVisible = true;
  1318. }
  1319. } else {
  1320. if (shadow != -2 && !cptr->IsMapped) {
  1321. Map_Cell(c, house);
  1322. }
  1323. }
  1324. }
  1325. }
  1326. TechnoClass * tech = (*this)[cell].Cell_Techno();
  1327. if (tech) {
  1328. tech->Revealed(house);
  1329. }
  1330. return(true);
  1331. }
  1332. /***********************************************************************************************
  1333. * DisplayClass::Coord_To_Pixel -- Determines X and Y pixel coordinates. *
  1334. * *
  1335. * This is the routine that figures out the location on the screen for *
  1336. * a specified coordinate. It is one of the fundamental routines *
  1337. * necessary for rendering the game objects. It performs some quick *
  1338. * tests to see if the coordinate is in a visible region and returns *
  1339. * this check as a boolean value. *
  1340. * *
  1341. * INPUT: coord -- The coordinate to check. *
  1342. * *
  1343. * x,y -- Reference to the pixel coordinates that this *
  1344. * coordinate would be when rendered. *
  1345. * *
  1346. * OUTPUT: bool; Is this coordinate in a visible portion of the map? *
  1347. * *
  1348. * WARNINGS: If the coordinate is not in a visible portion of the *
  1349. * map, then this X and Y parameters are not set. *
  1350. * *
  1351. * HISTORY: *
  1352. * 05/14/1994 JLB : Created. *
  1353. * 12/15/1994 JLB : Converted to member function. *
  1354. * 01/07/1995 JLB : Uses inline functions to extract coord components. *
  1355. * 08/09/1995 JLB : Uses new coordinate system. *
  1356. *=============================================================================================*/
  1357. #define EDGE_ZONE (CELL_LEPTON_W*2)
  1358. bool DisplayClass::Coord_To_Pixel(COORDINATE coord, int &x, int &y) const
  1359. {
  1360. if (coord) {
  1361. int xtac = Pixel_To_Lepton(Lepton_To_Pixel(Coord_X(TacticalCoord)));
  1362. int xoff = Pixel_To_Lepton(Lepton_To_Pixel(Coord_X(coord)));
  1363. xoff = (xoff+EDGE_ZONE) - xtac;
  1364. if ((unsigned)xoff <= TacLeptonWidth + EDGE_ZONE*2) {
  1365. int ytac = Pixel_To_Lepton(Lepton_To_Pixel(Coord_Y(TacticalCoord)));
  1366. int yoff = Pixel_To_Lepton(Lepton_To_Pixel(Coord_Y(coord)));
  1367. yoff = (yoff+EDGE_ZONE) - ytac;
  1368. if ((unsigned)yoff <= TacLeptonHeight + EDGE_ZONE*2) {
  1369. x = Lepton_To_Pixel(xoff)-CELL_PIXEL_W*2;
  1370. y = Lepton_To_Pixel(yoff)-CELL_PIXEL_H*2;
  1371. return(true);
  1372. }
  1373. }
  1374. }
  1375. return(false);
  1376. }
  1377. /***********************************************************************************************
  1378. * DisplayClass::Push_Onto_TacMap -- Moves x & y coords to being on tactical map *
  1379. * *
  1380. * This routine expects a line to be drawn between SOURCE & DEST, so it pushes the coords to *
  1381. * be within the region bounded by TacMapX,Y - + TacMapW,H. *
  1382. * *
  1383. * INPUT: source, dest -- References to the coordinates to check. *
  1384. * *
  1385. * *
  1386. * OUTPUT: bool; Are these coordinates in a visible portion of the map? *
  1387. * Returns true if the pushed source & dest are visible, but if neither are *
  1388. * within the map, then it returns false. *
  1389. * *
  1390. * *
  1391. * HISTORY: *
  1392. * 03/27/1995 BWG : Created. *
  1393. *=============================================================================================*/
  1394. bool DisplayClass::Push_Onto_TacMap(COORDINATE & source, COORDINATE & dest)
  1395. {
  1396. if (!source || !dest) return(false);
  1397. int x1 = Coord_X(source);
  1398. int y1 = Coord_Y(source);
  1399. int x2 = Coord_X(dest);
  1400. int y2 = Coord_Y(dest);
  1401. int left = Coord_X(TacticalCoord);
  1402. int right = Coord_X(TacticalCoord) + TacLeptonWidth;
  1403. int top = Coord_Y(TacticalCoord);
  1404. int bottom = Coord_Y(TacticalCoord) + TacLeptonHeight;
  1405. if (x1 < left && x2 < left) return(false);
  1406. if (x1 > right && x2 > right) return(false);
  1407. if (y1 < top && y2 < top) return(false);
  1408. if (y1 > bottom && y2 > bottom) return(false);
  1409. x1 = Bound(x1, left, right);
  1410. x2 = Bound(x2, left, right);
  1411. y1 = Bound(y1, top, bottom);
  1412. y2 = Bound(y2, top, bottom);
  1413. source = XY_Coord(x1, y1);
  1414. dest = XY_Coord(x2, y2);
  1415. return(true);
  1416. }
  1417. /***********************************************************************************************
  1418. * DisplayClass::Cell_Object -- Determines what has been clicked on. *
  1419. * *
  1420. * This routine is used to determine what the player has clicked on. *
  1421. * It is passed the cell that the click was on and it then examines *
  1422. * the cell and returns with a pointer to the object that is there. *
  1423. * *
  1424. * INPUT: cell -- The cell that has been clicked upon. *
  1425. * *
  1426. * x,y -- Optional offsets from the upper left corner of the cell to be used in *
  1427. * determining exactly which object in the cell is desired. *
  1428. * *
  1429. * OUTPUT: Returns with a pointer to the object that is "clickable" in *
  1430. * the specified cell. *
  1431. * *
  1432. * WARNINGS: none *
  1433. * *
  1434. * HISTORY: *
  1435. * 05/14/1994 JLB : Created. *
  1436. *=============================================================================================*/
  1437. ObjectClass * DisplayClass::Cell_Object(CELL cell, int x, int y) const
  1438. {
  1439. return(*this)[cell].Cell_Object(x, y);
  1440. }
  1441. /***********************************************************************************************
  1442. * DisplayClass::Draw_It -- Draws the tactical map. *
  1443. * *
  1444. * This will draw the tactical map at the recorded position. This *
  1445. * routine is used whenever the tactical map moves or needs to be *
  1446. * completely redrawn. It will handle making the necessary adjustments *
  1447. * to accomodate a moving cursor. *
  1448. * *
  1449. * INPUT: forced -- bool; force redraw of the entire display? *
  1450. * *
  1451. * OUTPUT: none *
  1452. * *
  1453. * WARNINGS: none *
  1454. * *
  1455. * HISTORY: *
  1456. * 04/15/1991 JLB : Created. (benchmark = 292) *
  1457. * 04/15/1991 JLB : Added _cell2meta[] reference array (206) *
  1458. * 04/15/1991 JLB : Added actual map reference for terrain (207) *
  1459. * 04/16/1991 JLB : _cell2meta converted to int (194) *
  1460. * 04/16/1991 JLB : References actual CellIcon[] array (204) *
  1461. * 04/16/1991 JLB : Cell size increased to 16 x 16 (167) *
  1462. * 04/17/1991 JLB : Cell based tactical map rendering (165) *
  1463. * 04/22/1991 JLB : Uses Draw_Stamp() for icon rendering (426) *
  1464. * 04/22/1991 JLB : Draw_Stamp uses LogicPage now (276) *
  1465. * 04/23/1991 JLB : Map active location cursor (334) *
  1466. * 05/02/1991 JLB : Added smoothing and 3 icons sets (431) *
  1467. * 05/22/1991 JLB : Broken into Draw_Map() and Refresh_Map(). *
  1468. * 09/14/1991 JLB : Uses Refresh_Cell when new cells scroll onto display. *
  1469. * 05/12/1992 JLB : Destination page support. *
  1470. * 02/14/1994 JLB : Revamped. *
  1471. * 05/01/1994 JLB : Converted to member function. *
  1472. * 12/15/1994 JLB : Updated to work with display hierarchy. *
  1473. * 12/24/1994 JLB : Examines redraw bit intelligently. *
  1474. * 12/24/1994 JLB : Combined with old Refresh_Map() function. *
  1475. * 01/10/1995 JLB : Rubber band drawing. *
  1476. *=============================================================================================*/
  1477. void DisplayClass::Draw_It(bool forced)
  1478. {
  1479. int x,y; // Working cell index values.
  1480. MapClass::Draw_It(forced);
  1481. if (IsToRedraw || forced) {
  1482. BStart(BENCH_TACTICAL);
  1483. IsToRedraw = false;
  1484. /*
  1485. ** In rubber band mode, mark all cells under the "rubber band" to be
  1486. ** redrawn.
  1487. */
  1488. Refresh_Band();
  1489. /*
  1490. ** Mark all cells under the vortex to be redrawn
  1491. */
  1492. ChronalVortex.Set_Redraw();
  1493. /*
  1494. ** If the multiplayer message system is displaying one or more messages,
  1495. ** flag all cells covered by the messages to redraw. This will prevent
  1496. ** messages from smearing the map if it scrolls.
  1497. */
  1498. int num = Session.Messages.Num_Messages();
  1499. if (num > 0) {
  1500. for (CELL cell = Coord_Cell(TacticalCoord); cell < Coord_Cell(TacticalCoord) + Lepton_To_Cell(TacLeptonWidth)+1; cell++) {
  1501. (*this)[cell].Redraw_Objects();
  1502. }
  1503. for (cell = Coord_Cell(TacticalCoord) + MAP_CELL_W;
  1504. cell < Coord_Cell(TacticalCoord) + MAP_CELL_W + Lepton_To_Cell(TacLeptonWidth)+1; cell++) {
  1505. (*this)[cell].Redraw_Objects();
  1506. }
  1507. if (num > 1) {
  1508. for (cell = Coord_Cell(TacticalCoord) + MAP_CELL_W*2;
  1509. cell < Coord_Cell(TacticalCoord) + MAP_CELL_W*2 + Lepton_To_Cell(TacLeptonWidth)+1; cell++) {
  1510. (*this)[cell].Redraw_Objects();
  1511. }
  1512. }
  1513. if (num > 2) {
  1514. for (cell = Coord_Cell(TacticalCoord) + MAP_CELL_W*3;
  1515. cell < Coord_Cell(TacticalCoord) + MAP_CELL_W*3 + Lepton_To_Cell(TacLeptonWidth)+1; cell++) {
  1516. (*this)[cell].Redraw_Objects();
  1517. }
  1518. }
  1519. if (num > 3) {
  1520. for (cell = Coord_Cell(TacticalCoord) + MAP_CELL_W*4;
  1521. cell < Coord_Cell(TacticalCoord) + MAP_CELL_W*4 + Lepton_To_Cell(TacLeptonWidth)+1; cell++) {
  1522. (*this)[cell].Redraw_Objects();
  1523. }
  1524. }
  1525. }
  1526. /*
  1527. ** Check for a movement of the tactical map. If there has been some
  1528. ** movement, then part (or all) of the icons must be redrawn.
  1529. */
  1530. if (Lepton_To_Pixel(Coord_X(DesiredTacticalCoord)) != Lepton_To_Pixel(Coord_X(TacticalCoord)) ||
  1531. Lepton_To_Pixel(Coord_Y(DesiredTacticalCoord)) != Lepton_To_Pixel(Coord_Y(TacticalCoord))) {
  1532. int xmod = Lepton_To_Pixel(Coord_X(DesiredTacticalCoord));
  1533. int ymod = Lepton_To_Pixel(Coord_Y(DesiredTacticalCoord));
  1534. int oldx = Lepton_To_Pixel(Coord_X(TacticalCoord))-xmod; // Old relative offset.
  1535. int oldy = Lepton_To_Pixel(Coord_Y(TacticalCoord))-ymod;
  1536. int oldw = Lepton_To_Pixel(TacLeptonWidth)-ABS(oldx); // Replicable width.
  1537. int oldh = Lepton_To_Pixel(TacLeptonHeight)-ABS(oldy); // Replicable height.
  1538. if (oldw < 1) forced = true;
  1539. if (oldh < 1) forced = true;
  1540. #ifdef WIN32 //For WIN32 only redraw the edges of the map that move into view
  1541. /*
  1542. ** Work out which map edges need to be redrawn
  1543. */
  1544. BOOL redraw_right = (oldx < 0) ? true : false; //Right hand edge
  1545. BOOL redraw_left = (oldx > 0) ? true : false; //Left hand edge
  1546. BOOL redraw_bottom= (oldy < 0) ? true : false; //Bottom edge
  1547. BOOL redraw_top = (oldy > 0) ? true : false; //Top edge
  1548. /*
  1549. ** Blit any replicable block to avoid having to drawstamp.
  1550. */
  1551. if (!forced && (oldw != Lepton_To_Pixel(TacLeptonWidth) || oldh != Lepton_To_Pixel(TacLeptonHeight))) {
  1552. Set_Cursor_Pos(-1);
  1553. /*
  1554. ** If hid page is in video memory then blit from the seen page to avoid blitting
  1555. ** an overlapped region.
  1556. */
  1557. if (HidPage.Get_IsDirectDraw()) {
  1558. Hide_Mouse();
  1559. SeenBuff.Blit(HidPage,
  1560. ((oldx < 0) ? -oldx : 0) +TacPixelX,
  1561. ((oldy < 0) ? -oldy : 0) +TacPixelY,
  1562. ((oldx < 0) ? 0 : oldx) +TacPixelX,
  1563. ((oldy < 0) ? 0 : oldy) +TacPixelY,
  1564. oldw,
  1565. oldh);
  1566. Show_Mouse();
  1567. } else {
  1568. HidPage.Blit(HidPage,
  1569. ((oldx < 0) ? -oldx : 0) +TacPixelX,
  1570. ((oldy < 0) ? -oldy : 0) +TacPixelY,
  1571. ((oldx < 0) ? 0 : oldx) +TacPixelX,
  1572. ((oldy < 0) ? 0 : oldy) +TacPixelY,
  1573. oldw,
  1574. oldh);
  1575. }
  1576. } else {
  1577. forced = true;
  1578. }
  1579. if (oldx < 0) oldx = 0;
  1580. if (oldy < 0) oldy = 0;
  1581. /*
  1582. ** Record new map position for future reference.
  1583. */
  1584. ScenarioInit++;
  1585. Set_Tactical_Position(DesiredTacticalCoord);
  1586. ScenarioInit--;
  1587. if (!forced) {
  1588. /*
  1589. **
  1590. ** Set the 'redraw stamp' bit for any cells that could not be copied.
  1591. **
  1592. */
  1593. int startx = -Lepton_To_Pixel(Coord_XLepton(TacticalCoord));
  1594. int starty = -Lepton_To_Pixel(Coord_YLepton(TacticalCoord));
  1595. oldw -= 24;
  1596. oldh -= 24;
  1597. if (abs(oldx) < 0x25 && abs(oldy) < 0x25) {
  1598. /*
  1599. ** The width of the area we redraw depends on the scroll speed
  1600. */
  1601. int extra_x = (abs(oldx)>=16) ? 2 : 1;
  1602. int extra_y = (abs(oldy)>=16) ? 2 : 1;
  1603. /*
  1604. ** Flag the cells across the top of the visible area if required
  1605. */
  1606. if (redraw_top) {
  1607. for (y = starty; y <= starty+CELL_PIXEL_H*extra_y; y += CELL_PIXEL_H) {
  1608. for (x = startx; x <= Lepton_To_Pixel(TacLeptonWidth)+((CELL_PIXEL_W*2)); x += CELL_PIXEL_W) {
  1609. CELL c = Click_Cell_Calc(Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1) + TacPixelX,
  1610. Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1) + TacPixelY);
  1611. if (c > 0) (*this)[c].Redraw_Objects(true);
  1612. }
  1613. }
  1614. }
  1615. /*
  1616. ** Flag the cells across the bottom of the visible area if required
  1617. */
  1618. if (redraw_bottom) {
  1619. for (y = Lepton_To_Pixel(TacLeptonHeight)-CELL_PIXEL_H*(1+extra_y); y <= Lepton_To_Pixel(TacLeptonHeight)+CELL_PIXEL_H*3; y += CELL_PIXEL_H) {
  1620. for (x = startx; x <= Lepton_To_Pixel(TacLeptonWidth)+((CELL_PIXEL_W*2)); x += CELL_PIXEL_W) {
  1621. CELL c = Click_Cell_Calc(Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1) + TacPixelX,
  1622. Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1) + TacPixelY);
  1623. if (c > 0) (*this)[c].Redraw_Objects(true);
  1624. }
  1625. }
  1626. }
  1627. /*
  1628. ** Flag the cells down the left of the visible area if required
  1629. */
  1630. if (redraw_left) {
  1631. for (x = startx; x <= startx + CELL_PIXEL_W*extra_x; x += CELL_PIXEL_W) {
  1632. for (y = starty; y <= Lepton_To_Pixel(TacLeptonHeight)+((CELL_PIXEL_H*2)); y += CELL_PIXEL_H) {
  1633. CELL c = Click_Cell_Calc(Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1) + TacPixelX,
  1634. Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1) + TacPixelY);
  1635. if (c > 0) (*this)[c].Redraw_Objects(true);
  1636. }
  1637. }
  1638. }
  1639. /*
  1640. ** Flag the cells down the right of the visible area if required
  1641. */
  1642. if (redraw_right) {
  1643. for (x = Lepton_To_Pixel(TacLeptonWidth)-CELL_PIXEL_W*(extra_x+1); x <= Lepton_To_Pixel(TacLeptonWidth)+CELL_PIXEL_W*3; x += CELL_PIXEL_W) {
  1644. for (y = starty; y <= Lepton_To_Pixel(TacLeptonHeight)+((CELL_PIXEL_H*2)); y += CELL_PIXEL_H) {
  1645. CELL c = Click_Cell_Calc(Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1) + TacPixelX,
  1646. Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1) + TacPixelY);
  1647. if (c > 0) (*this)[c].Redraw_Objects(true);
  1648. }
  1649. }
  1650. }
  1651. } else {
  1652. /*
  1653. ** Set the 'redraw stamp' bit for any cells that could not be copied.
  1654. */
  1655. int startx = -Lepton_To_Pixel(Coord_XLepton(TacticalCoord));
  1656. int starty = -Lepton_To_Pixel(Coord_YLepton(TacticalCoord));
  1657. oldw -= 24;
  1658. oldh -= 24;
  1659. for (y = starty; y <= Lepton_To_Pixel(TacLeptonHeight)+((CELL_PIXEL_H*2)); y += CELL_PIXEL_H) {
  1660. for (x = startx; x <= Lepton_To_Pixel(TacLeptonWidth)+((CELL_PIXEL_W*2)); x += CELL_PIXEL_W) {
  1661. if (x <= oldx || x >= oldx+oldw || y <= oldy || y >= oldy+oldh) {
  1662. CELL c = Click_Cell_Calc(Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1) + TacPixelX,
  1663. Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1) + TacPixelY);
  1664. if (c > 0) {
  1665. (*this)[c].Redraw_Objects(true);
  1666. }
  1667. }
  1668. }
  1669. }
  1670. }
  1671. }
  1672. } else {
  1673. /*
  1674. ** Set the tactical coordinate just in case the desired tactical has changed but
  1675. ** not enough to result in any visible map change. This is likely to occur with very
  1676. ** slow scroll rates.
  1677. */
  1678. ScenarioInit++;
  1679. if (DesiredTacticalCoord != TacticalCoord) {
  1680. Set_Tactical_Position(DesiredTacticalCoord);
  1681. }
  1682. ScenarioInit--;
  1683. }
  1684. #else //WIN32
  1685. /*
  1686. ** Blit any replicable block to avoid having to drawstamp.
  1687. */
  1688. if (!forced && (oldw != Lepton_To_Pixel(TacLeptonWidth) || oldh != Lepton_To_Pixel(TacLeptonHeight))) {
  1689. Set_Cursor_Pos(-1);
  1690. HidPage.Blit(HidPage,
  1691. ((oldx < 0) ? -oldx : 0) +TacPixelX,
  1692. ((oldy < 0) ? -oldy : 0) +TacPixelY,
  1693. ((oldx < 0) ? 0 : oldx) +TacPixelX,
  1694. ((oldy < 0) ? 0 : oldy) +TacPixelY,
  1695. oldw,
  1696. oldh);
  1697. } else {
  1698. forced = true;
  1699. }
  1700. if (oldx < 0) oldx = 0;
  1701. if (oldy < 0) oldy = 0;
  1702. /*
  1703. ** Record new map position for future reference.
  1704. */
  1705. ScenarioInit++;
  1706. Set_Tactical_Position(DesiredTacticalCoord);
  1707. ScenarioInit--;
  1708. if (!forced) {
  1709. /*
  1710. ** Set the 'redraw stamp' bit for any cells that could not be copied.
  1711. */
  1712. int startx = -Lepton_To_Pixel(Coord_XLepton(TacticalCoord));
  1713. int starty = -Lepton_To_Pixel(Coord_YLepton(TacticalCoord));
  1714. oldw -= 24;
  1715. oldh -= 24;
  1716. for (y = starty; y <= Lepton_To_Pixel(TacLeptonHeight)+((CELL_PIXEL_H*2)); y += CELL_PIXEL_H) {
  1717. for (x = startx; x <= Lepton_To_Pixel(TacLeptonWidth)+((CELL_PIXEL_W*2)); x += CELL_PIXEL_W) {
  1718. if (x <= oldx || x >= oldx+oldw || y <= oldy || y >= oldy+oldh) {
  1719. CELL c = Click_Cell_Calc(Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1) + TacPixelX,
  1720. Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1) + TacPixelY);
  1721. if (c > 0) {
  1722. (*this)[c].Redraw_Objects(true);
  1723. }
  1724. }
  1725. }
  1726. }
  1727. }
  1728. } else {
  1729. /*
  1730. ** Set the tactical coordinate just in case the desired tactical has changed but
  1731. ** not enough to result in any visible map change. This is likely to occur with very
  1732. ** slow scroll rates.
  1733. */
  1734. ScenarioInit++;
  1735. if (DesiredTacticalCoord != TacticalCoord) {
  1736. Set_Tactical_Position(DesiredTacticalCoord);
  1737. }
  1738. ScenarioInit--;
  1739. }
  1740. #endif
  1741. /*
  1742. ** If the entire tactical map is forced to be redrawn, then set all the redraw flags
  1743. ** and let the normal processing take care of the rest.
  1744. */
  1745. if (forced) {
  1746. CellRedraw.Set();
  1747. }
  1748. /*
  1749. ** The first order of business is to redraw all the underlying icons that are
  1750. ** flagged to be redrawn.
  1751. */
  1752. if (HidPage.Lock()) {
  1753. Redraw_Icons();
  1754. /*
  1755. ** Draw the infantry bodies in this special layer.
  1756. */
  1757. // for (int index = 0; index < Anims.Count(); index++) {
  1758. // AnimClass * anim = Anims.Ptr(index);
  1759. // if (*anim >= ANIM_CORPSE1 && *anim <= ANIM_CORPSE3) {
  1760. // anim->Render(forced);
  1761. // }
  1762. // }
  1763. #ifdef SORTDRAW
  1764. Redraw_OIcons();
  1765. #endif
  1766. HidPage.Unlock();
  1767. }
  1768. #ifndef WIN32
  1769. /*
  1770. ** Once the icons are drawn, duplicate the bottom line of the screen into the phantom
  1771. ** area one line below the screen. This causes the predator effect to work on any
  1772. ** shape drawn at the bottom of the screen.
  1773. */
  1774. HidPage.Blit(HidPage, 0, HidPage.Get_Height()-1, 0, HidPage.Get_Height(), HidPage.Get_Width(), 1, false);
  1775. #endif
  1776. if (HidPage.Lock()) {
  1777. /*
  1778. ** Draw the vortex effect over the terrain
  1779. */
  1780. ChronalVortex.Render();
  1781. /*
  1782. ** Redraw the game objects layer by layer. The layer drawing occurs on the ground layer
  1783. ** first and then followed by all the layers in increasing altitude.
  1784. */
  1785. BStart(BENCH_OBJECTS);
  1786. for (LayerType layer = LAYER_FIRST; layer < LAYER_COUNT; layer++) {
  1787. for (int index = 0; index < Layer[layer].Count(); index++) {
  1788. ObjectClass * ptr = Layer[layer][index];
  1789. #ifdef SORTDRAW
  1790. /*
  1791. ** Techno objects are drawn as part of the cell redraw process since techno
  1792. ** objects in the ground layer are handled by the Occupier and Overlapper
  1793. ** pointer lists.
  1794. */
  1795. if (!Debug_Map && ptr->Is_Techno() && layer == LAYER_GROUND && ((TechnoClass*)ptr)->Visual_Character() == VISUAL_NORMAL) continue;
  1796. #endif
  1797. // if (ptr->What_Am_I() == RTTI_ANIM && *((AnimClass*)ptr) >= ANIM_CORPSE1 && *((AnimClass*)ptr) <= ANIM_CORPSE3) {
  1798. // continue;
  1799. // }
  1800. assert(ptr->IsActive);
  1801. ptr->Render(forced);
  1802. }
  1803. }
  1804. BEnd(BENCH_OBJECTS);
  1805. //ChronalVortex.Render();
  1806. /*
  1807. ** Finally, redraw the shadow overlay as necessary.
  1808. */
  1809. BStart(BENCH_SHROUD);
  1810. Redraw_Shadow();
  1811. BEnd(BENCH_SHROUD);
  1812. }
  1813. HidPage.Unlock();
  1814. #ifdef SORTDRAW
  1815. for (int index = 0; index < Layer[LAYER_GROUND].Count(); index++) {
  1816. Layer[LAYER_GROUND][index]->IsToDisplay = false;
  1817. }
  1818. #endif
  1819. /*
  1820. ** Draw the rubber band over the top of it all.
  1821. */
  1822. if (IsRubberBand) {
  1823. LogicPage->Draw_Rect(BandX+TacPixelX, BandY+TacPixelY, NewX+TacPixelX, NewY+TacPixelY, WHITE);
  1824. }
  1825. /*
  1826. ** Clear the redraw flags so that normal redraw flag setting can resume.
  1827. */
  1828. CellRedraw.Reset();
  1829. #ifdef SCENARIO_EDITOR
  1830. /*
  1831. ** If we're placing an object (PendingObject is non-NULL), and that object
  1832. ** is NOT an icon, smudge, or overlay, draw it here.
  1833. ** Terrain, Buildings & Aircraft aren't drawn at the cell's center coord;
  1834. ** they're drawn at the upper left coord, so I have to AND the coord value
  1835. ** with 0xFF00FF00 to strip off the lepton coordinates, but leave the
  1836. ** cell coordinates.
  1837. */
  1838. if (Debug_Map && PendingObjectPtr) {
  1839. PendingObjectPtr->Coord = PendingObjectPtr->Class_Of().Coord_Fixup(Cell_Coord(ZoneCell + ZoneOffset));
  1840. PendingObjectPtr->Render(true);
  1841. }
  1842. #endif
  1843. BEnd(BENCH_TACTICAL);
  1844. }
  1845. }
  1846. /***********************************************************************************************
  1847. * DisplayClass::Redraw_Icons -- Draws all terrain icons necessary. *
  1848. * *
  1849. * This routine will redraw all of the terrain icons that are flagged *
  1850. * to be redrawn. *
  1851. * *
  1852. * INPUT: none *
  1853. * *
  1854. * OUTPUT: none *
  1855. * *
  1856. * WARNINGS: none. *
  1857. * *
  1858. * HISTORY: *
  1859. * 02/14/1994 JLB : Created. *
  1860. * 05/01/1994 JLB : Converted to member function. *
  1861. * 06/20/1994 JLB : Uses cell drawing support function. *
  1862. * 12/06/1994 JLB : Scans tactical view in separate row/column loops *
  1863. * 12/24/1994 JLB : Uses the cell bit flag array to determine what to redraw. *
  1864. *=============================================================================================*/
  1865. void DisplayClass::Redraw_Icons(void)
  1866. {
  1867. IsShadowPresent = false;
  1868. for (int y = -Coord_YLepton(TacticalCoord); y <= TacLeptonHeight; y += CELL_LEPTON_H) {
  1869. for (int x = -Coord_XLepton(TacticalCoord); x <= TacLeptonWidth; x += CELL_LEPTON_W) {
  1870. COORDINATE coord = Coord_Add(TacticalCoord, XY_Coord(x, y));
  1871. CELL cell = Coord_Cell(coord);
  1872. coord = Coord_Whole(Cell_Coord(cell));
  1873. /*
  1874. ** Only cells flagged to be redraw are examined.
  1875. */
  1876. if (In_View(cell) && Is_Cell_Flagged(cell)) {
  1877. int xpixel;
  1878. int ypixel;
  1879. if (Coord_To_Pixel(coord, xpixel, ypixel)) {
  1880. CellClass * cellptr = &(*this)[coord];
  1881. /*
  1882. ** If there is a portion of the underlying icon that could be visible,
  1883. ** then draw it. Also draw the cell if the shroud is off.
  1884. */
  1885. if (cellptr->IsMapped || Debug_Unshroud) {
  1886. cellptr->Draw_It(xpixel, ypixel);
  1887. }
  1888. /*
  1889. ** If any cell is not fully mapped, then flag it so that the shadow drawing
  1890. ** process will occur. Only draw the shadow if Debug_Unshroud is false.
  1891. */
  1892. if (!cellptr->IsVisible && !Debug_Unshroud) {
  1893. IsShadowPresent = true;
  1894. }
  1895. }
  1896. }
  1897. }
  1898. }
  1899. }
  1900. #ifdef SORTDRAW
  1901. void DisplayClass::Redraw_OIcons(void)
  1902. {
  1903. for (int y = -Coord_YLepton(TacticalCoord); y <= TacLeptonHeight; y += CELL_LEPTON_H) {
  1904. for (int x = -Coord_XLepton(TacticalCoord); x <= TacLeptonWidth; x += CELL_LEPTON_W) {
  1905. COORDINATE coord = Coord_Add(TacticalCoord, XY_Coord(x, y));
  1906. CELL cell = Coord_Cell(coord);
  1907. coord = Coord_Whole(Cell_Coord(cell));
  1908. /*
  1909. ** Only cells flagged to be redraw are examined.
  1910. */
  1911. if (In_View(cell) && Is_Cell_Flagged(cell)) {
  1912. int xpixel;
  1913. int ypixel;
  1914. if (Coord_To_Pixel(coord, xpixel, ypixel)) {
  1915. CellClass * cellptr = &(*this)[coord];
  1916. /*
  1917. ** If there is a portion of the underlying icon that could be visible,
  1918. ** then draw it. Also draw the cell if the shroud is off.
  1919. */
  1920. if (cellptr->IsMapped || Debug_Unshroud) {
  1921. cellptr->Draw_It(xpixel, ypixel, true);
  1922. }
  1923. }
  1924. }
  1925. }
  1926. }
  1927. }
  1928. #endif
  1929. /***********************************************************************************************
  1930. * DisplayClass::Redraw_Shadow -- Draw the shadow overlay. *
  1931. * *
  1932. * This routine is called after all other tactical map rendering takes place. It draws *
  1933. * the shadow map over the tactical map. *
  1934. * *
  1935. * INPUT: none *
  1936. * *
  1937. * OUTPUT: none *
  1938. * *
  1939. * WARNINGS: none *
  1940. * *
  1941. * HISTORY: *
  1942. * 01/01/1995 JLB : Created. *
  1943. * 08/06/1995 JLB : Clips the fill rect if necessary. *
  1944. *=============================================================================================*/
  1945. void DisplayClass::Redraw_Shadow(void)
  1946. {
  1947. if (IsShadowPresent) {
  1948. for (int y = -Coord_YLepton(TacticalCoord); y <= TacLeptonHeight; y += CELL_LEPTON_H) {
  1949. for (int x = -Coord_XLepton(TacticalCoord); x <= TacLeptonWidth; x += CELL_LEPTON_W) {
  1950. COORDINATE coord = Coord_Add(TacticalCoord, XY_Coord(x, y));
  1951. CELL cell = Coord_Cell(coord);
  1952. coord = Coord_Whole(Cell_Coord(cell));
  1953. /*
  1954. ** Only cells flagged to be redrawn are examined.
  1955. */
  1956. if (In_View(cell) && Is_Cell_Flagged(cell)) {
  1957. int xpixel;
  1958. int ypixel;
  1959. if (Coord_To_Pixel(coord, xpixel, ypixel)) {
  1960. CellClass * cellptr = &(*this)[coord];
  1961. if (cellptr->IsVisible) continue;
  1962. int shadow = -2;
  1963. if (cellptr->IsMapped) {
  1964. shadow = Cell_Shadow(cell);
  1965. }
  1966. if (shadow >= 0) {
  1967. CC_Draw_Shape(ShadowShapes, shadow, xpixel, ypixel, WINDOW_TACTICAL, SHAPE_GHOST, NULL, ShadowTrans);
  1968. } else {
  1969. if (shadow != -1) {
  1970. int ww = CELL_PIXEL_W;
  1971. int hh = CELL_PIXEL_H;
  1972. if (Clip_Rect(&xpixel, &ypixel, &ww, &hh, Lepton_To_Pixel(TacLeptonWidth), Lepton_To_Pixel(TacLeptonHeight)) >= 0) {
  1973. LogicPage->Fill_Rect(TacPixelX+xpixel, TacPixelY+ypixel, TacPixelX+xpixel+ww-1, TacPixelY+ypixel+hh-1, BLACK);
  1974. }
  1975. }
  1976. }
  1977. }
  1978. }
  1979. }
  1980. }
  1981. }
  1982. }
  1983. /***********************************************************************************************
  1984. * DisplayClass::Next_Object -- Searches for next object on display. *
  1985. * *
  1986. * This utility routine is used to find the "next" object from the object specified. This *
  1987. * is typically used when <TAB> is pressed and the current object shifts. *
  1988. * *
  1989. * INPUT: object -- The current object to base the "next" calculation off of. *
  1990. * *
  1991. * OUTPUT: Returns with a pointer to the next object. If there is no objects available, *
  1992. * then NULL is returned. *
  1993. * *
  1994. * WARNINGS: none *
  1995. * *
  1996. * HISTORY: *
  1997. * 06/20/1994 JLB : Created. *
  1998. *=============================================================================================*/
  1999. ObjectClass * DisplayClass::Next_Object(ObjectClass * object) const
  2000. {
  2001. ObjectClass * firstobj = NULL;
  2002. bool foundmatch = false;
  2003. if (object == NULL) {
  2004. foundmatch = true;
  2005. }
  2006. for (unsigned uindex = 0; uindex < Layer[LAYER_GROUND].Count(); uindex++) {
  2007. ObjectClass * obj = Layer[LAYER_GROUND][uindex];
  2008. /*
  2009. ** Verify that the object can be selected by and is owned by the player.
  2010. */
  2011. if (obj != NULL && obj->Is_Players_Army()) {
  2012. if (firstobj == NULL) firstobj = obj;
  2013. if (foundmatch) return(obj);
  2014. if (object == obj) foundmatch = true;
  2015. }
  2016. }
  2017. return(firstobj);
  2018. }
  2019. /***********************************************************************************************
  2020. * DisplayClass::Prev_Object -- Searches for the previous object on the map. *
  2021. * *
  2022. * This routine will search for the previous object. Previous is defined as the one listed *
  2023. * before the specified object in the ground layer. If there is no specified object, then *
  2024. * the last object in the ground layer is returned. *
  2025. * *
  2026. * INPUT: object -- Pointer to the object that "previous" is to be defined from. *
  2027. * *
  2028. * OUTPUT: Returns with a pointer to the object previous to the specified one. *
  2029. * *
  2030. * WARNINGS: none *
  2031. * *
  2032. * HISTORY: *
  2033. * 08/24/1995 JLB : Created. *
  2034. *=============================================================================================*/
  2035. ObjectClass * DisplayClass::Prev_Object(ObjectClass * object) const
  2036. {
  2037. ObjectClass * firstobj = NULL;
  2038. bool foundmatch = false;
  2039. if (object == NULL) {
  2040. foundmatch = true;
  2041. }
  2042. for (int uindex = Layer[LAYER_GROUND].Count()-1; uindex >= 0; uindex--) {
  2043. ObjectClass * obj = Layer[LAYER_GROUND][uindex];
  2044. /*
  2045. ** Verify that the object can be selected by and is owned by the player.
  2046. */
  2047. if (obj != NULL && obj->Is_Players_Army()) {
  2048. if (firstobj == NULL) firstobj = obj;
  2049. if (foundmatch) return(obj);
  2050. if (object == obj) foundmatch = true;
  2051. }
  2052. }
  2053. return(firstobj);
  2054. }
  2055. /***********************************************************************************************
  2056. * DisplayClass::Pixel_To_Coord -- converts screen coord to COORDINATE *
  2057. * *
  2058. * INPUT: *
  2059. * x,y pixel coordinates to convert *
  2060. * *
  2061. * OUTPUT: *
  2062. * COORDINATE of pixel *
  2063. * *
  2064. * WARNINGS: *
  2065. * none. *
  2066. * *
  2067. * HISTORY: *
  2068. * 11/09/1994 BR : Created. *
  2069. * 12/06/1994 JLB : Uses map dimension variables in display class. *
  2070. * 12/10/1994 JLB : Uses union to speed building coordinate value. *
  2071. *=============================================================================================*/
  2072. COORDINATE DisplayClass::Pixel_To_Coord(int x, int y) const
  2073. {
  2074. /*
  2075. ** Normalize the pixel coordinates to be relative to the upper left corner
  2076. ** of the tactical map. The coordinates are expressed in leptons.
  2077. */
  2078. x -= TacPixelX;
  2079. x = Pixel_To_Lepton(x);
  2080. y -= TacPixelY;
  2081. y = Pixel_To_Lepton(y);
  2082. /*
  2083. ** If pixel coordinate is over the tactical map, then translate it into a coordinate
  2084. ** value. If not, then just return with NULL.
  2085. */
  2086. if ((unsigned)x < TacLeptonWidth && (unsigned)y < TacLeptonHeight) {
  2087. return(Coord_Add(TacticalCoord, XY_Coord(x, y)));
  2088. }
  2089. return(0);
  2090. }
  2091. /***********************************************************************************************
  2092. * DisplayClass::Calculated_Cell -- Fetch a map cell based on specified method. *
  2093. * *
  2094. * Find a cell meeting the specified requirements. This function is *
  2095. * used for scenario reinforcements. *
  2096. * *
  2097. * INPUT: dir -- Method of picking a map cell. *
  2098. * *
  2099. * waypoint -- Closest waypoint to use for finding appropriate map edge. *
  2100. * *
  2101. * cell -- Cell to find closest edge to if waypoint not specified. *
  2102. * *
  2103. * loco -- The locomotion of the reinforcements that are trying to enter. *
  2104. * *
  2105. * zonecheck -- Is zone checking required? *
  2106. * *
  2107. * mzone -- The movement zone type to check against (only if zone checking). *
  2108. * *
  2109. * OUTPUT: Returns with the calculated cell. If 0, then this indicates *
  2110. * that no legal cell was found. *
  2111. * *
  2112. * WARNINGS: none *
  2113. * *
  2114. * HISTORY: *
  2115. * 10/07/1992 JLB : Created. *
  2116. * 04/11/1994 JLB : Revamped. *
  2117. * 05/18/1994 JLB : Converted to member function. *
  2118. * 12/18/1995 JLB : Handles edge preference scan. *
  2119. * 06/24/1996 JLB : Removed Dune II legacy code. *
  2120. * 06/25/1996 JLB : Rewrote and greatly simplified. *
  2121. * 10/05/1996 JLB : Checks for zone and crushable status. *
  2122. *=============================================================================================*/
  2123. CELL DisplayClass::Calculated_Cell(SourceType dir, WAYPOINT waypoint, CELL cell, SpeedType loco, bool zonecheck, MZoneType mzone) const
  2124. {
  2125. bool vert = false;
  2126. bool horz = false;
  2127. int x = 0;
  2128. int y = 0;
  2129. CELL punt = 0; // If all else fails, return this cell location.
  2130. int zone = -1; // Tentative zone for legality checking.
  2131. /*
  2132. ** Waypoint edge detection for ground based reinforcements that have a waypoint origin are
  2133. ** determined by finding the closest map edge to the waypoint. Reinforcement location
  2134. ** scanning starts from that position.
  2135. */
  2136. CELL trycell = -1;
  2137. if (waypoint != -1) {
  2138. trycell = Scen.Waypoint[waypoint];
  2139. }
  2140. if (trycell == -1) {
  2141. trycell = cell;
  2142. }
  2143. /*
  2144. ** If zone checking is requested, then find the correct zone to use.
  2145. */
  2146. if (zonecheck && trycell != -1) {
  2147. zone = (*this)[trycell].Zones[mzone];
  2148. }
  2149. /*
  2150. ** If the cell or waypoint specified as been detected as legal, then set up the map edge
  2151. ** scanning values accordingly.
  2152. */
  2153. if (trycell != -1) {
  2154. x = Cell_X(trycell) - MapCellX;
  2155. x = min(x, (-Cell_X(trycell) + (MapCellX+MapCellWidth)));
  2156. y = Cell_Y(trycell) - MapCellY;
  2157. y = min(y, (-Cell_Y(trycell) + (MapCellY+MapCellHeight)));
  2158. if (x < y) {
  2159. vert = true;
  2160. horz = false;
  2161. if ((Cell_X(trycell)-MapCellX) < MapCellWidth/2) {
  2162. x = -1;
  2163. } else {
  2164. x = MapCellWidth;
  2165. }
  2166. y = Cell_Y(trycell) - MapCellY;
  2167. } else {
  2168. vert = false;
  2169. horz = true;
  2170. if ((Cell_Y(trycell)-MapCellY) < MapCellHeight/2) {
  2171. y = -1;
  2172. } else {
  2173. y = MapCellHeight;
  2174. }
  2175. x = Cell_X(trycell) - MapCellX;
  2176. }
  2177. }
  2178. /*
  2179. ** If no map edge can be inferred from the waypoint, then go with the
  2180. ** map edge specified by the edge parameter.
  2181. */
  2182. if (!vert && !horz) {
  2183. switch (dir) {
  2184. default:
  2185. case SOURCE_NORTH:
  2186. horz = true;
  2187. y = -1;
  2188. x = Random_Pick(0, MapCellWidth-1);
  2189. break;
  2190. case SOURCE_SOUTH:
  2191. horz = true;
  2192. y = MapCellHeight;
  2193. x = Random_Pick(0, MapCellWidth-1);
  2194. break;
  2195. case SOURCE_EAST:
  2196. vert = true;
  2197. x = MapCellWidth;
  2198. y = Random_Pick(0, MapCellHeight-1);
  2199. break;
  2200. case SOURCE_WEST:
  2201. vert = true;
  2202. x = -1;
  2203. y = Random_Pick(0, MapCellHeight-1);
  2204. break;
  2205. }
  2206. }
  2207. /*
  2208. ** Determine the default reinforcement cell if all else fails.
  2209. */
  2210. punt = XY_Cell(x + MapCellX, y + MapCellY);
  2211. /*
  2212. ** Scan through the vertical and horizontal edges of the map looking for
  2213. ** a relatively clear cell for object placement. The cell scanned is
  2214. ** from the edge position specified by the X and Y variables.
  2215. */
  2216. if (vert) {
  2217. int modifier = (x > MapCellX) ? -1 : 1;
  2218. for (int index = 0; index < MapCellHeight; index++) {
  2219. CELL trycell = XY_Cell(x + MapCellX, ((y + index) % MapCellHeight) + MapCellY);
  2220. if (Good_Reinforcement_Cell(trycell, trycell+modifier, loco, zone, mzone)) {
  2221. return(trycell);
  2222. }
  2223. }
  2224. }
  2225. if (horz) {
  2226. int modifier = (y > MapCellY) ? -MAP_CELL_W : MAP_CELL_W;
  2227. for (int index = 0; index < MapCellWidth; index++) {
  2228. CELL trycell = XY_Cell(((x + index) % MapCellWidth) + MapCellX, y + MapCellY);
  2229. if (Good_Reinforcement_Cell(trycell, trycell+modifier, loco, zone, mzone)) {
  2230. return(trycell);
  2231. }
  2232. }
  2233. }
  2234. /*
  2235. ** If there was no success in finding a suitable reinforcement edge cell, then return
  2236. ** with the default 'punt' cell location.
  2237. */
  2238. return(punt);
  2239. }
  2240. /***********************************************************************************************
  2241. * DisplayClass::Good_Reinforcement_Cell -- Checks cell for renforcement legality. *
  2242. * *
  2243. * This routine will check the secified cell (given the specified conditions) and determine *
  2244. * if that is a good cell for reinforcement purposes. It checks for passability of the cell *
  2245. * as well as zone and whether blocking walls can be crushed. *
  2246. * *
  2247. * INPUT: outcell -- The cell that is just outside the edge of the map. *
  2248. * *
  2249. * incell -- The cell that is just inside the edge of the map. *
  2250. * *
  2251. * loco -- The locomotion type of the reinforcement. *
  2252. * *
  2253. * zone -- The zone that the eventual movement destination lies. A reinforcement *
  2254. * edge must fall within the same zone. *
  2255. * *
  2256. * mzone -- The zone check type to check against (if zone checking required) *
  2257. * *
  2258. * OUTPUT: bool; Is the specified cell good for reinforcement purposes? *
  2259. * *
  2260. * WARNINGS: none *
  2261. * *
  2262. * HISTORY: *
  2263. * 10/05/1996 JLB : Created. *
  2264. *=============================================================================================*/
  2265. bool DisplayClass::Good_Reinforcement_Cell(CELL outcell, CELL incell, SpeedType loco, int zone, MZoneType mzone) const
  2266. {
  2267. /*
  2268. ** If the map edge location is not clear for object placement, then this is not
  2269. ** a good cell for reinforcement purposes.
  2270. */
  2271. if (!(*this)[outcell].Is_Clear_To_Move(loco, false, false)) {
  2272. return(false);
  2273. }
  2274. /*
  2275. ** If it looks like the on-map cell cannot be driven on to, then return with
  2276. ** the failure code.
  2277. */
  2278. if (!(*this)[incell].Is_Clear_To_Move(loco, false, false, zone, mzone)) {
  2279. return(false);
  2280. }
  2281. /*
  2282. ** If the reinforcement cell is already occupied, then return a failure code.
  2283. */
  2284. if ((*this)[outcell].Cell_Techno() != NULL) {
  2285. return(false);
  2286. }
  2287. if ((*this)[incell].Cell_Techno() != NULL) return(false);
  2288. /*
  2289. ** All tests have passed, return with success code.
  2290. */
  2291. //Mono_Printf("<%04X>\n", incell);Keyboard->Get();
  2292. return(true);
  2293. }
  2294. /***********************************************************************************************
  2295. * DisplayClass::Select_These -- All selectable objects in region are selected. *
  2296. * *
  2297. * Use this routine to simultaneously select all objects within the coordinate region *
  2298. * specified. This routine is used by the multi-select rubber band handler. *
  2299. * *
  2300. * INPUT: coord1 -- Coordinate of one corner of the selection region. *
  2301. * *
  2302. * coord2 -- The opposite corner of the selection region. *
  2303. * *
  2304. * OUTPUT: none *
  2305. * *
  2306. * WARNINGS: none *
  2307. * *
  2308. * HISTORY: *
  2309. * 01/19/1995 JLB : Created. *
  2310. * 04/25/1995 JLB : Limited to non-building type. *
  2311. * 03/06/1996 JLB : Allows selection of aircraft with bounding box. *
  2312. *=============================================================================================*/
  2313. void DisplayClass::Select_These(COORDINATE coord1, COORDINATE coord2)
  2314. {
  2315. COORDINATE tcoord = TacticalCoord; //Cell_Coord(TacticalCell) & 0xFF00FF00L;
  2316. coord1 = Coord_Add(tcoord, coord1);
  2317. coord2 = Coord_Add(tcoord, coord2);
  2318. int x1 = Coord_X(coord1);
  2319. int x2 = Coord_X(coord2);
  2320. int y1 = Coord_Y(coord1);
  2321. int y2 = Coord_Y(coord2);
  2322. /*
  2323. ** Ensure that coordinate number one represents the upper left corner
  2324. ** and coordinate number two represents the lower right corner.
  2325. */
  2326. if (x1 > x2) {
  2327. int temp = x1;
  2328. x1 = x2;
  2329. x2 = temp;
  2330. }
  2331. if (y1 > y2) {
  2332. int temp = y1;
  2333. y1 = y2;
  2334. y2 = temp;
  2335. }
  2336. /*
  2337. ** Sweep through all ground layer objects and select the ones within the
  2338. ** bounding box.
  2339. */
  2340. Unselect_All();
  2341. AllowVoice = true;
  2342. for (int index = 0; index < Layer[LAYER_GROUND].Count(); index++) {
  2343. ObjectClass * obj = Layer[LAYER_GROUND][index];
  2344. COORDINATE ocoord = obj->Center_Coord();
  2345. int x = Coord_X(ocoord);
  2346. int y = Coord_Y(ocoord);
  2347. /*
  2348. ** Only try to select objects that are owned by the player, are allowed to be
  2349. ** selected, and are within the bounding box.
  2350. */
  2351. HouseClass * hptr = HouseClass::As_Pointer(obj->Owner());
  2352. if ( (hptr != NULL && hptr->IsPlayerControl) &&
  2353. obj->Class_Of().IsSelectable &&
  2354. obj->What_Am_I() != RTTI_BUILDING &&
  2355. x >= x1 && x <= x2 && y >= y1 && y <= y2) {
  2356. if (obj->Select()) {
  2357. AllowVoice = false;
  2358. }
  2359. }
  2360. }
  2361. /*
  2362. ** Select any aircraft with the bounding box.
  2363. */
  2364. for (int air_index = 0; air_index < Aircraft.Count(); air_index++) {
  2365. AircraftClass * aircraft = Aircraft.Ptr(air_index);
  2366. COORDINATE ocoord = aircraft->Center_Coord();
  2367. int x = Coord_X(ocoord);
  2368. int y = Coord_Y(ocoord);
  2369. /*
  2370. ** Only try to select objects that are owned by the player, are allowed to be
  2371. ** selected, and are within the bounding box.
  2372. */
  2373. if ( aircraft->House->IsPlayerControl &&
  2374. aircraft->Class->IsSelectable &&
  2375. !aircraft->IsSelected &&
  2376. x >= x1 && x <= x2 && y >= y1 && y <= y2) {
  2377. if (aircraft->Select()) {
  2378. AllowVoice = false;
  2379. }
  2380. }
  2381. }
  2382. AllowVoice = true;
  2383. }
  2384. /***********************************************************************************************
  2385. * DisplayClass::Refresh_Band -- Causes all cells under the rubber band to be redrawn. *
  2386. * *
  2387. * Use this routine to flag all cells that are covered in some fashion by the multi-unit *
  2388. * select "rubber band" to be redrawn. This is necessary whenever the rubber band changes *
  2389. * size or is being removed. *
  2390. * *
  2391. * INPUT: none *
  2392. * *
  2393. * OUTPUT: none *
  2394. * *
  2395. * WARNINGS: none *
  2396. * *
  2397. * HISTORY: *
  2398. * 01/19/1995 JLB : Created. *
  2399. *=============================================================================================*/
  2400. void DisplayClass::Refresh_Band(void)
  2401. {
  2402. if (IsRubberBand) {
  2403. /*
  2404. ** In rubber band mode, mark all cells under the "rubber band" to be
  2405. ** redrawn.
  2406. */
  2407. int x1 = BandX+TacPixelX;
  2408. int y1 = BandY+TacPixelY;
  2409. int x2 = NewX+TacPixelX;
  2410. int y2 = NewY+TacPixelY;
  2411. if (x1 > x2) {
  2412. int temp = x1;
  2413. x1 = x2;
  2414. x2 = temp;
  2415. }
  2416. if (y1 > y2) {
  2417. int temp = y1;
  2418. y1 = y2;
  2419. y2 = temp;
  2420. }
  2421. CELL cell;
  2422. for (int y = y1; y <= y2+CELL_PIXEL_H; y += CELL_PIXEL_H) {
  2423. cell = Click_Cell_Calc(x1, Bound(y, 0, TacPixelY+Lepton_To_Pixel(TacLeptonHeight)));
  2424. if (cell != -1) (*this)[cell].Redraw_Objects();
  2425. cell = Click_Cell_Calc(x2, Bound(y, 0, TacPixelY+Lepton_To_Pixel(TacLeptonHeight)));
  2426. if (cell != -1) (*this)[cell].Redraw_Objects();
  2427. }
  2428. for (int x = x1; x <= x2+CELL_PIXEL_W; x += CELL_PIXEL_W) {
  2429. cell = Click_Cell_Calc(Bound(x, 0, TacPixelX+Lepton_To_Pixel(TacLeptonWidth)), y1);
  2430. if (cell != -1) (*this)[cell].Redraw_Objects();
  2431. cell = Click_Cell_Calc(Bound(x, 0, TacPixelX+Lepton_To_Pixel(TacLeptonWidth)), y2);
  2432. if (cell != -1) (*this)[cell].Redraw_Objects();
  2433. }
  2434. /*
  2435. ** Stretching the rubber band requires all objects to be redrawn.
  2436. */
  2437. for (int index = 0; index < Layer[LAYER_TOP].Count(); index++) {
  2438. Layer[LAYER_TOP][index]->Mark(MARK_CHANGE);
  2439. }
  2440. for (index = 0; index < Layer[LAYER_AIR].Count(); index++) {
  2441. Layer[LAYER_AIR][index]->Mark(MARK_CHANGE);
  2442. }
  2443. }
  2444. }
  2445. /***********************************************************************************************
  2446. * DisplayClass::TacticalClass::Action -- Processes input for the tactical map. *
  2447. * *
  2448. * This routine handles the input directed at the tactical map. Since input, in this *
  2449. * regard, includes even the presence of the mouse over the tactical map, this routine *
  2450. * is called nearly every game frame. It handles adjusting the mouse shape as well as *
  2451. * giving orders to units. *
  2452. * *
  2453. * INPUT: flags -- The gadget event flags that triggered the call to this function. *
  2454. * *
  2455. * key -- A reference to the keyboard event (if any). *
  2456. * *
  2457. * OUTPUT: bool; Should processing be aborted on any succeeding buttons in the chain? *
  2458. * *
  2459. * WARNINGS: none *
  2460. * *
  2461. * HISTORY: *
  2462. * 02/17/1995 JLB : Created. *
  2463. *=============================================================================================*/
  2464. int DisplayClass::TacticalClass::Action(unsigned flags, KeyNumType & key)
  2465. {
  2466. int x,y; // Sub cell pixel coordinates.
  2467. bool shadow;
  2468. ObjectClass * object = 0;
  2469. ActionType action = ACTION_NONE; // Action possible with currently selected object.
  2470. /*
  2471. ** Set some working variables that depend on the mouse position. For the press
  2472. ** or release event, special mouse queuing storage variables are used. Other
  2473. ** events must use the current mouse position globals.
  2474. */
  2475. if (flags & (LEFTPRESS|LEFTRELEASE|RIGHTPRESS|RIGHTRELEASE)) {
  2476. x = Keyboard->MouseQX;
  2477. y = Keyboard->MouseQY;
  2478. } else {
  2479. x = Get_Mouse_X();
  2480. y = Get_Mouse_Y();
  2481. }
  2482. bool edge = (y == 0 || x == 0 || x == SeenBuff.Get_Width()-1 || y == SeenBuff.Get_Height()-1);
  2483. COORDINATE coord = Map.Pixel_To_Coord(x, y);
  2484. CELL cell = Coord_Cell(coord);
  2485. if (coord) {
  2486. shadow = (!Map[cell].IsMapped && !Debug_Unshroud);
  2487. x -= Map.TacPixelX;
  2488. y -= Map.TacPixelY;
  2489. /*
  2490. ** Cause any displayed cursor to move along with the mouse cursor.
  2491. */
  2492. if (cell != Map.ZoneCell) {
  2493. Map.Set_Cursor_Pos(cell);
  2494. }
  2495. /*
  2496. ** Determine the object that the mouse is currently over.
  2497. */
  2498. if (!shadow) {
  2499. object = Map.Close_Object(coord);
  2500. /*
  2501. ** Special case check to ignore cloaked object if not owned by the player.
  2502. */
  2503. if (object != NULL && object->Is_Techno() && !((TechnoClass *)object)->IsOwnedByPlayer && (((TechnoClass *)object)->Cloak == CLOAKED || ((TechnoClass *)object)->Techno_Type_Class()->IsInvisible)) {
  2504. object = NULL;
  2505. }
  2506. }
  2507. /*
  2508. ** If there is a currently selected object, then the action to perform if
  2509. ** the left mouse button were clicked must be determined.
  2510. */
  2511. if (CurrentObject.Count()) {
  2512. if (object != NULL) {
  2513. action = CurrentObject[0]->What_Action(object);
  2514. } else {
  2515. action = CurrentObject[0]->What_Action(cell);
  2516. }
  2517. } else {
  2518. if (object && object->Class_Of().IsSelectable) {
  2519. action = ACTION_SELECT;
  2520. }
  2521. if (Map.IsRepairMode) {
  2522. if (object && object->Owner() == PlayerPtr->Class->House && object->Can_Repair()) {
  2523. action = ACTION_REPAIR;
  2524. } else {
  2525. action = ACTION_NO_REPAIR;
  2526. }
  2527. }
  2528. if (Map.IsSellMode) {
  2529. if (object && object->Owner() == PlayerPtr->Class->House && object->Can_Demolish()) {
  2530. if (object->What_Am_I() == RTTI_BUILDING) {
  2531. action = ACTION_SELL;
  2532. } else {
  2533. action = ACTION_SELL_UNIT;
  2534. }
  2535. } else {
  2536. /*
  2537. ** Check to see if the cursor is over an owned wall.
  2538. */
  2539. if (Map[cell].Overlay != OVERLAY_NONE &&
  2540. OverlayTypeClass::As_Reference(Map[cell].Overlay).IsWall &&
  2541. Map[cell].Owner == PlayerPtr->Class->House) {
  2542. action = ACTION_SELL;
  2543. } else {
  2544. action = ACTION_NO_SELL;
  2545. }
  2546. }
  2547. }
  2548. if (Map.IsTargettingMode == SPC_NUCLEAR_BOMB) {
  2549. action = ACTION_NUKE_BOMB;
  2550. }
  2551. if (Map.IsTargettingMode == SPC_PARA_BOMB) {
  2552. action = ACTION_PARA_BOMB;
  2553. }
  2554. if (Map.IsTargettingMode == SPC_PARA_INFANTRY) {
  2555. action = ACTION_PARA_INFANTRY;
  2556. }
  2557. if (Map.IsTargettingMode == SPC_SPY_MISSION) {
  2558. action = ACTION_SPY_MISSION;
  2559. }
  2560. if (Map.IsTargettingMode == SPC_IRON_CURTAIN) {
  2561. action = ACTION_IRON_CURTAIN;
  2562. }
  2563. if (Map.IsTargettingMode == SPC_CHRONOSPHERE) {
  2564. action = ACTION_CHRONOSPHERE;
  2565. }
  2566. if (Map.IsTargettingMode == SPC_CHRONO2) {
  2567. action = ACTION_CHRONO2;
  2568. if (shadow) action = ACTION_NOMOVE;
  2569. ObjectClass const * tobject = As_Object(PlayerPtr->UnitToTeleport);
  2570. /*
  2571. ** Determine if the object can be teleported to the destination cell.
  2572. */
  2573. if (tobject != NULL && tobject->Is_Techno()) {
  2574. TechnoClass const * uobject = (TechnoClass const *)tobject;
  2575. if (!uobject->Can_Teleport_Here(cell)) {
  2576. // if (((UnitClass *)As_Object(PlayerPtr->UnitToTeleport))->Can_Enter_Cell(cell, FACING_NONE) != MOVE_OK) {
  2577. action = ACTION_NOMOVE;
  2578. }
  2579. }
  2580. #ifdef FIXIT_CSII // checked - ajw 9/28/98
  2581. else { // If the object is no longer valid, cancel targetting mode.
  2582. action = ACTION_NOMOVE;
  2583. Map.IsTargettingMode = SPC_NONE;
  2584. }
  2585. #endif
  2586. }
  2587. if (Map.PendingObject) {
  2588. action = ACTION_NONE;
  2589. }
  2590. }
  2591. /*
  2592. ** Move any cursor displayed.
  2593. */
  2594. if (cell != Map.ZoneCell) {
  2595. Map.Set_Cursor_Pos(cell);
  2596. }
  2597. /*
  2598. ** A right mouse button press cancels the current action or selection.
  2599. */
  2600. if (flags & RIGHTPRESS) {
  2601. Map.Mouse_Right_Press();
  2602. }
  2603. /*
  2604. ** Make sure that if the mouse button has been released and the map doesn't know about it,
  2605. ** then it must be informed. Do this by faking a mouse release event.
  2606. */
  2607. if ((flags & LEFTUP) && Map.IsRubberBand) {
  2608. flags |= LEFTRELEASE;
  2609. }
  2610. /*
  2611. ** When the mouse buttons aren't pressed, only the mouse cursor shape is processed.
  2612. ** The shape changes depending on what object the mouse is currently over and what
  2613. ** object is currently selected.
  2614. */
  2615. if (!edge) {
  2616. if (flags & LEFTUP) {
  2617. Map.Mouse_Left_Up(cell, shadow, object, action);
  2618. }
  2619. }
  2620. /*
  2621. ** Normal actions occur when the mouse button is released. The press event is
  2622. ** intercepted and possible rubber-band mode is flagged.
  2623. */
  2624. if (flags & LEFTRELEASE) {
  2625. Map.Mouse_Left_Release(cell, x, y, object, action);
  2626. }
  2627. /*
  2628. ** When the mouse is first pressed on the map, then record the mouse
  2629. ** position so that a proper check before going into rubber band
  2630. ** mode can be made. Rubber band mode starts when the mouse is
  2631. ** held down and moved a certain minimum distance.
  2632. */
  2633. if (!edge && (flags & LEFTPRESS)) {
  2634. Map.Mouse_Left_Up(cell, shadow, object, action);
  2635. Map.Mouse_Left_Press(x, y);
  2636. }
  2637. /*
  2638. ** While the mouse is being held down, determine if rubber band mode should
  2639. ** start. If rubber band mode is already active, then update the size
  2640. ** and flag the map to redraw it.
  2641. */
  2642. if (flags & LEFTHELD) {
  2643. Map.Mouse_Left_Held(x, y);
  2644. }
  2645. }
  2646. return(GadgetClass::Action(0, key));
  2647. }
  2648. /***********************************************************************************************
  2649. * DisplayClass::Mouse_Right_Press -- Handles the right mouse button press. *
  2650. * *
  2651. * This routine is called when the right mouse button is pressed. This action is supposed *
  2652. * to cancel whatever mode or process is active. If there is nothing to cancel, then it *
  2653. * will default to unselecting any units that might be currently selected. *
  2654. * *
  2655. * INPUT: none *
  2656. * *
  2657. * OUTPUT: none *
  2658. * *
  2659. * WARNINGS: none *
  2660. * *
  2661. * HISTORY: *
  2662. * 02/24/1995 JLB : Created. *
  2663. *=============================================================================================*/
  2664. void DisplayClass::Mouse_Right_Press(void)
  2665. {
  2666. if (PendingObjectPtr && PendingObjectPtr->Is_Techno()) {
  2667. //PendingObjectPtr->Transmit_Message(RADIO_OVER_OUT);
  2668. PendingObjectPtr = 0;
  2669. PendingObject = 0;
  2670. PendingHouse = HOUSE_NONE;
  2671. Set_Cursor_Shape(0);
  2672. } else {
  2673. if (IsRepairMode) {
  2674. IsRepairMode = false;
  2675. } else {
  2676. if (IsSellMode) {
  2677. IsSellMode = false;
  2678. } else {
  2679. if (IsTargettingMode != SPC_NONE) {
  2680. IsTargettingMode = SPC_NONE;
  2681. } else {
  2682. Unselect_All();
  2683. }
  2684. }
  2685. }
  2686. }
  2687. // If it breaks... call 228.
  2688. Set_Default_Mouse(MOUSE_NORMAL, Map.IsSmall);
  2689. }
  2690. /***********************************************************************************************
  2691. * DisplayClass::Mouse_Left_Up -- Handles the left mouse "cruising" over the map. *
  2692. * *
  2693. * This routine is called continuously while the mouse is over the tactical map but there *
  2694. * are no mouse buttons pressed. Typically, this adjusts the mouse shape and the pop-up *
  2695. * help text. *
  2696. * *
  2697. * INPUT: shadow -- Is the mouse hovering over shadowed terrain? *
  2698. * *
  2699. * object -- Pointer to the object that the mouse is currently over (may be NULL). *
  2700. * *
  2701. * action -- This is the action that the currently selected object (if any) will *
  2702. * perform if the left mouse button were clicked at this location. *
  2703. * *
  2704. * OUTPUT: none *
  2705. * *
  2706. * WARNINGS: none *
  2707. * *
  2708. * HISTORY: *
  2709. * 02/24/1995 JLB : Created. *
  2710. * 07/05/1995 JLB : Removed pop up help text for shadow and terrain after #3. *
  2711. *=============================================================================================*/
  2712. void DisplayClass::Mouse_Left_Up(CELL cell, bool shadow, ObjectClass * object, ActionType action, bool wsmall)
  2713. {
  2714. IsTentative = false;
  2715. TARGET target = TARGET_NONE;
  2716. if (object != NULL) {
  2717. target = object->As_Target();
  2718. } else {
  2719. if (cell != -1) {
  2720. target = As_Target(cell);
  2721. }
  2722. }
  2723. /*
  2724. ** Don't allow selection of an object that is located in shadowed terrain.
  2725. ** In fact, just show the normal move cursor in order to keep the shadowed
  2726. ** terrain a mystery.
  2727. */
  2728. if (shadow) {
  2729. switch (action) {
  2730. case ACTION_NO_DEPLOY:
  2731. Set_Default_Mouse(MOUSE_NO_DEPLOY, wsmall);
  2732. break;
  2733. case ACTION_NO_ENTER:
  2734. Set_Default_Mouse(MOUSE_NO_ENTER, wsmall);
  2735. break;
  2736. case ACTION_NO_GREPAIR:
  2737. Set_Default_Mouse(MOUSE_NO_GREPAIR, wsmall);
  2738. break;
  2739. case ACTION_DAMAGE:
  2740. Set_Default_Mouse(MOUSE_NORMAL, wsmall);
  2741. break;
  2742. case ACTION_GREPAIR:
  2743. Set_Default_Mouse(MOUSE_NORMAL, wsmall);
  2744. break;
  2745. case ACTION_GUARD_AREA:
  2746. Set_Default_Mouse(MOUSE_AREA_GUARD, wsmall);
  2747. break;
  2748. case ACTION_NONE:
  2749. Set_Default_Mouse(MOUSE_NORMAL, wsmall);
  2750. break;
  2751. case ACTION_NO_SELL:
  2752. case ACTION_SELL:
  2753. case ACTION_SELL_UNIT:
  2754. Set_Default_Mouse(MOUSE_NO_SELL_BACK, wsmall);
  2755. break;
  2756. case ACTION_NO_REPAIR:
  2757. case ACTION_REPAIR:
  2758. Set_Default_Mouse(MOUSE_NO_REPAIR, wsmall);
  2759. break;
  2760. case ACTION_NUKE_BOMB:
  2761. Set_Default_Mouse(MOUSE_NUCLEAR_BOMB, wsmall);
  2762. break;
  2763. case ACTION_AIR_STRIKE:
  2764. case ACTION_PARA_BOMB:
  2765. case ACTION_PARA_INFANTRY:
  2766. case ACTION_SPY_MISSION:
  2767. case ACTION_IRON_CURTAIN:
  2768. Set_Default_Mouse(MOUSE_AIR_STRIKE, wsmall);
  2769. break;
  2770. case ACTION_CHRONOSPHERE:
  2771. Set_Default_Mouse(MOUSE_CHRONO_SELECT, wsmall);
  2772. break;
  2773. case ACTION_CHRONO2:
  2774. Set_Default_Mouse(MOUSE_CHRONO_DEST, wsmall);
  2775. break;
  2776. case ACTION_HEAL:
  2777. Set_Default_Mouse(MOUSE_HEAL, wsmall);
  2778. break;
  2779. case ACTION_NOMOVE:
  2780. if (CurrentObject.Count() && CurrentObject[0]->What_Am_I() == RTTI_AIRCRAFT) {
  2781. Set_Default_Mouse(MOUSE_NO_MOVE, wsmall);
  2782. break;
  2783. }
  2784. // Fall into next case for non aircraft object types.
  2785. default:
  2786. Set_Default_Mouse(MOUSE_CAN_MOVE, wsmall);
  2787. break;
  2788. }
  2789. } else {
  2790. /*
  2791. ** Change the mouse shape according to the default action that will occur
  2792. ** if the mouse button were clicked at this location.
  2793. */
  2794. switch (action) {
  2795. case ACTION_NO_DEPLOY:
  2796. Set_Default_Mouse(MOUSE_NO_DEPLOY, wsmall);
  2797. break;
  2798. case ACTION_NO_ENTER:
  2799. Set_Default_Mouse(MOUSE_NO_ENTER, wsmall);
  2800. break;
  2801. case ACTION_NO_GREPAIR:
  2802. Set_Default_Mouse(MOUSE_NO_GREPAIR, wsmall);
  2803. break;
  2804. case ACTION_DAMAGE:
  2805. Set_Default_Mouse(MOUSE_DAMAGE, wsmall);
  2806. break;
  2807. case ACTION_GREPAIR:
  2808. Set_Default_Mouse(MOUSE_GREPAIR, wsmall);
  2809. break;
  2810. case ACTION_TOGGLE_SELECT:
  2811. case ACTION_SELECT:
  2812. Set_Default_Mouse(MOUSE_CAN_SELECT, wsmall);
  2813. break;
  2814. case ACTION_MOVE:
  2815. Set_Default_Mouse(MOUSE_CAN_MOVE, wsmall);
  2816. break;
  2817. case ACTION_GUARD_AREA:
  2818. Set_Default_Mouse(MOUSE_AREA_GUARD, wsmall);
  2819. break;
  2820. case ACTION_ATTACK:
  2821. if (Target_Legal(target) && CurrentObject.Count() == 1 && CurrentObject[0]->Is_Techno() && ((TechnoClass *)CurrentObject[0])->In_Range(target, 0)) {
  2822. Set_Default_Mouse(MOUSE_STAY_ATTACK, wsmall);
  2823. break;
  2824. }
  2825. // fall into next case.
  2826. case ACTION_HARVEST:
  2827. Set_Default_Mouse(MOUSE_CAN_ATTACK, wsmall);
  2828. break;
  2829. case ACTION_SABOTAGE:
  2830. Set_Default_Mouse(MOUSE_DEMOLITIONS, wsmall);
  2831. break;
  2832. case ACTION_ENTER:
  2833. case ACTION_CAPTURE:
  2834. Set_Default_Mouse(MOUSE_ENTER, wsmall);
  2835. break;
  2836. case ACTION_NOMOVE:
  2837. Set_Default_Mouse(MOUSE_NO_MOVE, wsmall);
  2838. break;
  2839. case ACTION_NO_SELL:
  2840. Set_Default_Mouse(MOUSE_NO_SELL_BACK, wsmall);
  2841. break;
  2842. case ACTION_NO_REPAIR:
  2843. Set_Default_Mouse(MOUSE_NO_REPAIR, wsmall);
  2844. break;
  2845. case ACTION_SELF:
  2846. Set_Default_Mouse(MOUSE_DEPLOY, wsmall);
  2847. break;
  2848. case ACTION_REPAIR:
  2849. Set_Default_Mouse(MOUSE_REPAIR, wsmall);
  2850. break;
  2851. case ACTION_SELL_UNIT:
  2852. Set_Default_Mouse(MOUSE_SELL_UNIT, wsmall);
  2853. break;
  2854. case ACTION_SELL:
  2855. Set_Default_Mouse(MOUSE_SELL_BACK, wsmall);
  2856. break;
  2857. case ACTION_NUKE_BOMB:
  2858. Set_Default_Mouse(MOUSE_NUCLEAR_BOMB, wsmall);
  2859. break;
  2860. case ACTION_AIR_STRIKE:
  2861. case ACTION_PARA_BOMB:
  2862. case ACTION_PARA_INFANTRY:
  2863. case ACTION_SPY_MISSION:
  2864. case ACTION_IRON_CURTAIN:
  2865. Set_Default_Mouse(MOUSE_AIR_STRIKE, wsmall);
  2866. break;
  2867. case ACTION_CHRONOSPHERE:
  2868. Set_Default_Mouse(MOUSE_CHRONO_SELECT, wsmall);
  2869. break;
  2870. case ACTION_CHRONO2:
  2871. Set_Default_Mouse(MOUSE_CHRONO_DEST, wsmall);
  2872. break;
  2873. case ACTION_HEAL:
  2874. Set_Default_Mouse(MOUSE_HEAL, wsmall);
  2875. break;
  2876. default:
  2877. Set_Default_Mouse(MOUSE_NORMAL, wsmall);
  2878. break;
  2879. }
  2880. }
  2881. /*
  2882. ** Never display help text if the mouse is held over the radar map.
  2883. */
  2884. if (wsmall) {
  2885. return;
  2886. }
  2887. /*
  2888. ** Give a generic help message when over shadow terrain.
  2889. */
  2890. if (shadow) {
  2891. // if (Scen.Scenario < 4) {
  2892. Help_Text(TXT_SHADOW);
  2893. // } else {
  2894. // Help_Text(TXT_NONE);
  2895. // }
  2896. } else {
  2897. /*
  2898. ** If the mouse is held over objects on the map, then help text may
  2899. ** pop up that tells what the object is. This call informs the help
  2900. ** system of the text name for the object under the mouse.
  2901. */
  2902. if (object != NULL) {
  2903. int text;
  2904. int color = LTGREY;
  2905. /*
  2906. ** Fetch the appropriate background color for help text.
  2907. */
  2908. if (PlayerPtr->Is_Ally(object)) {
  2909. color = GREEN;
  2910. } else {
  2911. if (object->Owner() == HOUSE_NONE || object->Owner() == HOUSE_NEUTRAL) {
  2912. color = LTGREY;
  2913. } else {
  2914. color = PINK;
  2915. }
  2916. }
  2917. /*
  2918. ** Fetch the name of the object. If it is an enemy object, then
  2919. ** the exact identity is glossed over with a generic text.
  2920. */
  2921. text = object->Full_Name();
  2922. if (object->Is_Techno() && !((TechnoTypeClass const &)object->Class_Of()).IsNominal) {
  2923. if (!((TechnoClass *)object)->House->Is_Ally(PlayerPtr)) {
  2924. // if (!PlayerPtr->Is_Ally(object)) {
  2925. switch (object->What_Am_I()) {
  2926. case RTTI_INFANTRY:
  2927. text = TXT_ENEMY_SOLDIER;
  2928. break;
  2929. case RTTI_UNIT:
  2930. text = TXT_ENEMY_VEHICLE;
  2931. break;
  2932. case RTTI_BUILDING:
  2933. text = TXT_ENEMY_STRUCTURE;
  2934. break;
  2935. }
  2936. }
  2937. }
  2938. if (/*Scen.Scenario > 3 ||*/ object->What_Am_I() != RTTI_TERRAIN) {
  2939. Help_Text(text, -1, -1, color);
  2940. } else {
  2941. Help_Text(TXT_NONE);
  2942. }
  2943. } else {
  2944. if ((*this)[cell].Land_Type() == LAND_TIBERIUM) {
  2945. Help_Text(TXT_MINERALS);
  2946. } else {
  2947. Help_Text(TXT_NONE);
  2948. }
  2949. }
  2950. }
  2951. }
  2952. /***********************************************************************************************
  2953. * DisplayClass::Mouse_Left_Release -- Handles the left mouse button release. *
  2954. * *
  2955. * This routine is called when the left mouse button is released over the tactical map. *
  2956. * The release event is the workhorse of the game. Most actions occur at the moment of *
  2957. * mouse release. *
  2958. * *
  2959. * INPUT: cell -- The cell that the mouse is over. *
  2960. * *
  2961. * x,y -- The mouse pixel coordinate. *
  2962. * *
  2963. * object -- Pointer to the object that the mouse is over. *
  2964. * *
  2965. * action -- The action that the currently selected object (if any) will *
  2966. * perform. *
  2967. * *
  2968. * OUTPUT: none *
  2969. * *
  2970. * WARNINGS: none *
  2971. * *
  2972. * HISTORY: *
  2973. * 02/24/1995 JLB : Created. *
  2974. * 03/27/1995 JLB : Handles sell and repair actions. *
  2975. *=============================================================================================*/
  2976. void DisplayClass::Mouse_Left_Release(CELL cell, int x, int y, ObjectClass * object, ActionType action, bool wsmall)
  2977. {
  2978. if (PendingObjectPtr) {
  2979. /*
  2980. ** Try to place the pending object onto the map.
  2981. */
  2982. if (ProximityCheck) {
  2983. OutList.Add(EventClass(EventClass::PLACE, PendingObjectPtr->What_Am_I(), cell + ZoneOffset));
  2984. } else {
  2985. Speak(VOX_DEPLOY);
  2986. }
  2987. } else {
  2988. if (IsRubberBand) {
  2989. Refresh_Band();
  2990. Select_These(XYP_Coord(BandX, BandY), XYP_Coord(x, y));
  2991. Set_Default_Mouse(MOUSE_NORMAL, wsmall);
  2992. IsRubberBand = false;
  2993. IsTentative = false;
  2994. Map.DisplayClass::IsToRedraw = true;
  2995. Map.Flag_To_Redraw(false);
  2996. } else {
  2997. /*
  2998. ** Toggle the select state of the object.
  2999. */
  3000. if (action == ACTION_TOGGLE_SELECT) {
  3001. if (!object || !CurrentObject.Count() || CurrentObject[0]->Owner() != PlayerPtr->Class->House) {
  3002. action = ACTION_SELECT;
  3003. } else {
  3004. if (object->IsSelected) {
  3005. object->Unselect();
  3006. } else {
  3007. object->Select();
  3008. }
  3009. }
  3010. }
  3011. /*
  3012. ** Selection of other object action.
  3013. */
  3014. if (action == ACTION_SELECT || (action == ACTION_NONE && object && object->Class_Of().IsSelectable && !object->IsSelected)) {
  3015. Unselect_All();
  3016. object->Select();
  3017. Set_Default_Mouse(MOUSE_NORMAL, wsmall);
  3018. }
  3019. /*
  3020. ** If an action was detected as possible, then pass this action event
  3021. ** to all selected objects.
  3022. */
  3023. if (action != ACTION_NONE && action != ACTION_SELECT) {
  3024. /*
  3025. ** Pass the action to all the selected objects. But first, redetermine
  3026. ** what action that object should perform. This, seemingly redundant
  3027. ** process, is necessary since multiple objects could be selected and each
  3028. ** might perform a different action when the click occurs.
  3029. */
  3030. bool doflash = true;
  3031. AllowVoice = true;
  3032. FormMove = false;
  3033. FormSpeed = SPEED_WHEEL;
  3034. FormMaxSpeed = MPH_LIGHT_SPEED;
  3035. if ( (action == ACTION_MOVE || action == ACTION_NOMOVE) && CurrentObject.Count()) {
  3036. /*
  3037. ** Scan all units. If any are selected that shouldn't be, or aren't
  3038. ** selected but should be, then this is not a formation move.
  3039. */
  3040. int group = 254; // init to invalid group #
  3041. if (CurrentObject[0]->Is_Foot()) {
  3042. group = ((FootClass *)CurrentObject[0])->Group;
  3043. }
  3044. /*
  3045. ** Presume this is a formation move unless something is detected
  3046. ** that will prevent it.
  3047. */
  3048. FormMove = true;
  3049. /*
  3050. ** First scan through all the selected units to make sure that they
  3051. ** are all of the same team and have been assigned a particular formation
  3052. */
  3053. for (int index = 0; index < CurrentObject.Count(); index++) {
  3054. ObjectClass const * tobject = CurrentObject[index];
  3055. /*
  3056. ** Only moveable (i.e., FootClass) objects can ever be in a formation
  3057. ** so if a selected object isn't of a FootClass type then it can't be
  3058. ** a formation move.
  3059. */
  3060. if (tobject->Is_Foot() == false) {
  3061. FormMove = false;
  3062. break;
  3063. }
  3064. /*
  3065. ** If the object is not part of the same team as the rest of the
  3066. ** selected group, or it just plain has never been assigned a
  3067. ** formation offset, then it can't be a formation move.
  3068. */
  3069. FootClass const * foot = (FootClass *)tobject;
  3070. if (foot->Group != group || foot->XFormOffset == 0x80000000) {
  3071. FormMove = false;
  3072. break;
  3073. }
  3074. /*
  3075. ** Determine the formation speed on the presumption that this
  3076. ** will turn out to be a formation move.
  3077. */
  3078. FormMaxSpeed = foot->Techno_Type_Class()->MaxSpeed;
  3079. FormSpeed = foot->Techno_Type_Class()->Speed;
  3080. }
  3081. /*
  3082. ** Loop through all objects (that can theoretically be part of a team) and
  3083. ** if there are any that are part of the currently selected team, but
  3084. ** are not currently selected themselves, then this will force this move
  3085. ** to NOT be a formation move.
  3086. */
  3087. if (FormMove) {
  3088. for (index = 0; index < ::Logic.Count(); index++) {
  3089. ObjectClass const * obj = ::Logic[index];
  3090. /*
  3091. ** If the object is selected, then it has already been scanned
  3092. ** by the previous loop.
  3093. */
  3094. if (obj->IsSelected) continue;
  3095. /*
  3096. ** Only consider footclass objects.
  3097. */
  3098. if (!obj->Is_Foot()) continue;
  3099. FootClass const * foot = (FootClass *)obj;
  3100. /*
  3101. ** Only consider objects that are owned by the player.
  3102. */
  3103. if (!foot->IsOwnedByPlayer) continue;
  3104. /*
  3105. ** If another member of this team has been discovered and
  3106. ** it isn't selected, then the formation move cannot take
  3107. ** place.
  3108. */
  3109. if (foot->Group == group) {
  3110. FormMove = false;
  3111. break;
  3112. }
  3113. }
  3114. }
  3115. }
  3116. for (int index = 0; index < CurrentObject.Count(); index++) {
  3117. ObjectClass * tobject = CurrentObject[index];
  3118. if (object != NULL) {
  3119. tobject->Active_Click_With(tobject->What_Action(object), object);
  3120. } else {
  3121. /*
  3122. ** Trap for formation moves: if this unit is part of a
  3123. ** formation (being part of a team qualifies) and they're
  3124. ** told to move, adjust the target destination so they stay
  3125. ** in formation when they arrive.
  3126. */
  3127. CELL newmove = cell;
  3128. int whatami = tobject->What_Am_I();
  3129. if (action == ACTION_MOVE && tobject->Is_Foot()) {
  3130. int oldisform;
  3131. FootClass * foot = (FootClass *)tobject;
  3132. oldisform = foot->IsFormationMove;
  3133. foot->IsFormationMove = FormMove;
  3134. if (FormMove && foot->Group != 255 ) {
  3135. newmove = foot->Adjust_Dest(cell);
  3136. }
  3137. foot->IsFormationMove = oldisform;
  3138. }
  3139. tobject->Active_Click_With(tobject->What_Action(cell), newmove);
  3140. }
  3141. AllowVoice = false;
  3142. }
  3143. AllowVoice = true;
  3144. FormMove = false;
  3145. if (action == ACTION_REPAIR && object->What_Am_I() == RTTI_BUILDING) {
  3146. OutList.Add(EventClass(EventClass::REPAIR, TargetClass(object)));
  3147. }
  3148. if (action == ACTION_SELL_UNIT && object) {
  3149. switch (object->What_Am_I()) {
  3150. case RTTI_AIRCRAFT:
  3151. case RTTI_UNIT:
  3152. OutList.Add(EventClass(EventClass::SELL, TargetClass(object)));
  3153. break;
  3154. default:
  3155. break;
  3156. }
  3157. }
  3158. if (action == ACTION_SELL) {
  3159. if (object) {
  3160. OutList.Add(EventClass(EventClass::SELL, TargetClass(object)));
  3161. } else {
  3162. OutList.Add(EventClass(EventClass::SELLCELL, cell));
  3163. // OutList.Add(EventClass(EventClass::SELL, ::As_Target(cell)));
  3164. }
  3165. }
  3166. if (action == ACTION_NUKE_BOMB) {
  3167. OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_NUCLEAR_BOMB, cell));
  3168. }
  3169. if (action == ACTION_PARA_BOMB) {
  3170. OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_PARA_BOMB, cell));
  3171. }
  3172. if (action == ACTION_PARA_INFANTRY) {
  3173. OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_PARA_INFANTRY, cell));
  3174. }
  3175. if (action == ACTION_SPY_MISSION) {
  3176. OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_SPY_MISSION, cell));
  3177. }
  3178. if (action == ACTION_IRON_CURTAIN) {
  3179. OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_IRON_CURTAIN, cell));
  3180. }
  3181. if (action == ACTION_CHRONOSPHERE) {
  3182. OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_CHRONOSPHERE, cell));
  3183. }
  3184. if (action == ACTION_CHRONO2) {
  3185. OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_CHRONO2, cell));
  3186. }
  3187. }
  3188. IsTentative = false;
  3189. }
  3190. }
  3191. }
  3192. /***********************************************************************************************
  3193. * DisplayClass::Mouse_Left_Press -- Handles the left mouse button press. *
  3194. * *
  3195. * Handle the left mouse button press while over the tactical map. If it isn't is *
  3196. * repair or sell mode, then a tentative transition to rubber band mode is flagged. If the *
  3197. * mouse moves a sufficient distance from this recorded position, then rubber band mode *
  3198. * is officially started. *
  3199. * *
  3200. * INPUT: x,y -- The mouse coordinates at the time of the press. *
  3201. * *
  3202. * OUTPUT: none *
  3203. * *
  3204. * WARNINGS: none *
  3205. * *
  3206. * HISTORY: *
  3207. * 02/24/1995 JLB : Created. *
  3208. *=============================================================================================*/
  3209. void DisplayClass::Mouse_Left_Press(int x, int y)
  3210. {
  3211. if (!IsRepairMode && !IsSellMode && IsTargettingMode == SPC_NONE && !PendingObject) {
  3212. IsTentative = true;
  3213. BandX = x;
  3214. BandY = y;
  3215. NewX = x;
  3216. NewY = y;
  3217. }
  3218. }
  3219. /***********************************************************************************************
  3220. * DisplayClass::Mouse_Left_Held -- Handles the left button held down. *
  3221. * *
  3222. * This routine is called continuously while the left mouse button is held down over *
  3223. * the tactical map. This handles the rubber band mode detection and dragging. *
  3224. * *
  3225. * INPUT: x,y -- The mouse coordinate. *
  3226. * *
  3227. * OUTPUT: none *
  3228. * *
  3229. * WARNINGS: none *
  3230. * *
  3231. * HISTORY: *
  3232. * 02/24/1995 JLB : Created. *
  3233. *=============================================================================================*/
  3234. void DisplayClass::Mouse_Left_Held(int x, int y)
  3235. {
  3236. if (IsRubberBand) {
  3237. if (x != NewX || y != NewY) {
  3238. x = Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1);
  3239. y = Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1);
  3240. Refresh_Band();
  3241. NewX = x;
  3242. NewY = y;
  3243. IsToRedraw = true;
  3244. Flag_To_Redraw(false);
  3245. }
  3246. } else {
  3247. /*
  3248. ** If the mouse is still held down while a tentative extended select is possible, then
  3249. ** check to see if the mouse has moved a sufficient distance in order to activate
  3250. ** extended select mode.
  3251. */
  3252. if (IsTentative) {
  3253. /*
  3254. ** The mouse must have moved a minimum distance before rubber band mode can be
  3255. ** initiated.
  3256. */
  3257. if (ABS(x - BandX) > 4 || ABS(y - BandY) > 4) {
  3258. IsRubberBand = true;
  3259. x = Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1);
  3260. y = Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1);
  3261. NewX = x;
  3262. NewY = y;
  3263. IsToRedraw = true;
  3264. Flag_To_Redraw(false);
  3265. /*
  3266. ** Stretching the rubber band requires all objects to be redrawn.
  3267. */
  3268. for (int index = 0; index < Layer[LAYER_TOP].Count(); index++) {
  3269. Layer[LAYER_TOP][index]->Mark(MARK_CHANGE);
  3270. }
  3271. for (index = 0; index < Layer[LAYER_AIR].Count(); index++) {
  3272. Layer[LAYER_AIR][index]->Mark(MARK_CHANGE);
  3273. }
  3274. }
  3275. }
  3276. }
  3277. }
  3278. /***********************************************************************************************
  3279. * DisplayClass::Set_Tactical_Position -- Sets the tactical view position. *
  3280. * *
  3281. * This routine is used to set the tactical view position. The requested position is *
  3282. * clipped to the map dimensions as necessary. *
  3283. * *
  3284. * INPUT: coord -- The coordinate desired for the upper left corner. *
  3285. * *
  3286. * OUTPUT: none *
  3287. * *
  3288. * WARNINGS: none *
  3289. * *
  3290. * HISTORY: *
  3291. * 08/13/1995 JLB : Created. *
  3292. *=============================================================================================*/
  3293. void DisplayClass::Set_Tactical_Position(COORDINATE coord)
  3294. {
  3295. /*
  3296. ** Bound the desired location to fit the legal map edges.
  3297. */
  3298. int xx = (int)Coord_X(coord) - (int)Cell_To_Lepton(MapCellX);
  3299. int yy = (int)Coord_Y(coord) - (int)Cell_To_Lepton(MapCellY);
  3300. Confine_Rect(&xx, &yy, TacLeptonWidth, TacLeptonHeight, Cell_To_Lepton(MapCellWidth), Cell_To_Lepton(MapCellHeight));
  3301. coord = XY_Coord(xx + Cell_To_Lepton(MapCellX), yy + Cell_To_Lepton(MapCellY));
  3302. if (ScenarioInit) {
  3303. TacticalCoord = coord;
  3304. }
  3305. DesiredTacticalCoord = coord;
  3306. IsToRedraw = true;
  3307. Flag_To_Redraw(false);
  3308. }
  3309. /***********************************************************************************************
  3310. * DisplayClass::Compute_Start_Pos -- Computes player's start pos from unit coords. *
  3311. * *
  3312. * Use this function in multiplayer games, to compute the scenario starting Tactical Pos. *
  3313. * *
  3314. * INPUT: none *
  3315. * *
  3316. * OUTPUT: none *
  3317. * *
  3318. * WARNINGS: none *
  3319. * *
  3320. * HISTORY: *
  3321. * 02/28/1995 JLB : Commented. *
  3322. * 06/26/1995 JLB : Fixed building loop. *
  3323. * 10/20/1996 JLB : Doesn't wrap. *
  3324. *=============================================================================================*/
  3325. void DisplayClass::Compute_Start_Pos(void)
  3326. {
  3327. /*
  3328. ** Find the summation cell-x & cell-y for all the player's units, infantry,
  3329. ** and buildings. Buildings are weighted so that they count 16 times more
  3330. ** than units or infantry.
  3331. */
  3332. long x = 0;
  3333. long y = 0;
  3334. long num = 0;
  3335. for (int i = 0; i < Infantry.Count(); i++) {
  3336. InfantryClass * infp = Infantry.Ptr(i);
  3337. if (!infp->IsInLimbo && infp->IsOwnedByPlayer) {
  3338. x += (long)Coord_XCell(infp->Coord);
  3339. y += (long)Coord_YCell(infp->Coord);
  3340. num++;
  3341. }
  3342. }
  3343. for (i = 0; i < Units.Count(); i++) {
  3344. UnitClass * unitp = Units.Ptr(i);
  3345. if (!unitp->IsInLimbo && unitp->IsOwnedByPlayer) {
  3346. x += (long)Coord_XCell(unitp->Coord);
  3347. y += (long)Coord_YCell(unitp->Coord);
  3348. num++;
  3349. }
  3350. }
  3351. for (i = 0; i < Buildings.Count(); i++) {
  3352. BuildingClass * bldgp = Buildings.Ptr(i);
  3353. if (!bldgp->IsInLimbo && bldgp->IsOwnedByPlayer) {
  3354. x += (((long)Coord_XCell(bldgp->Coord)) * 16);
  3355. y += (((long)Coord_YCell(bldgp->Coord)) * 16);
  3356. num += 16;
  3357. }
  3358. }
  3359. for (i = 0; i < Vessels.Count(); i++) {
  3360. VesselClass * bldgp = Vessels.Ptr(i);
  3361. if (!bldgp->IsInLimbo && bldgp->IsOwnedByPlayer) {
  3362. x += (((long)Coord_XCell(bldgp->Coord)));
  3363. y += (((long)Coord_YCell(bldgp->Coord)));
  3364. num++;
  3365. }
  3366. }
  3367. /*
  3368. ** Divide each coord by 'num' to compute the average value
  3369. */
  3370. if (num > 0) {
  3371. x /= num;
  3372. } else {
  3373. x = 0;
  3374. }
  3375. if (num > 0) {
  3376. y /= num;
  3377. } else {
  3378. y = 0;
  3379. }
  3380. /*
  3381. ** Tactical position is based on the cell of the upper left corner. Make adjustments
  3382. ** and bound the calculated location to the map dimensions.
  3383. */
  3384. // x -= 5 * RESFACTOR;
  3385. // y -= 4 * RESFACTOR;
  3386. if (x < MapCellX + 5*RESFACTOR) x = MapCellX + 5*RESFACTOR;
  3387. if (y < MapCellY + 4*RESFACTOR) y = MapCellY + 4*RESFACTOR;
  3388. if (x > MapCellX+MapCellWidth - 5*RESFACTOR) x = MapCellX+MapCellWidth - 5*RESFACTOR;
  3389. if (y > MapCellY+MapCellHeight - 4*RESFACTOR) y = MapCellY+MapCellHeight - 4*RESFACTOR;
  3390. Scen.Waypoint[WAYPT_HOME] = Scen.Views[0] = Scen.Views[1] = Scen.Views[2] = Scen.Views[3] = XY_Cell(x, y);
  3391. Map.Set_Tactical_Position(Coord_Whole(Cell_Coord((Scen.Views[0] - (MAP_CELL_W * 4 * RESFACTOR)) - (5*RESFACTOR))));
  3392. // Set_Tactical_Position(Cell_Coord(XY_Cell(x, y)));
  3393. }
  3394. /***********************************************************************************************
  3395. * DisplayClass::Sell_Mode_Control -- Controls the sell mode. *
  3396. * *
  3397. * This routine will control the sell mode for the player. *
  3398. * *
  3399. * INPUT: control -- The mode to set the sell state to. *
  3400. * 0 = Turn sell mode off. *
  3401. * 1 = Turn sell mode on. *
  3402. * -1 = Toggle sell mode. *
  3403. * *
  3404. * OUTPUT: none *
  3405. * *
  3406. * WARNINGS: none *
  3407. * *
  3408. * HISTORY: *
  3409. * 07/08/1995 JLB : Created. *
  3410. *=============================================================================================*/
  3411. void DisplayClass::Sell_Mode_Control(int control)
  3412. {
  3413. bool mode = IsSellMode;
  3414. switch (control) {
  3415. case 0:
  3416. mode = false;
  3417. break;
  3418. case -1:
  3419. mode = (IsSellMode == false);
  3420. break;
  3421. case 1:
  3422. mode = true;
  3423. break;
  3424. }
  3425. if (mode != IsSellMode && !PendingObject) {
  3426. IsRepairMode = false;
  3427. if (mode && PlayerPtr->BScan) {
  3428. IsSellMode = true;
  3429. Unselect_All();
  3430. } else {
  3431. IsSellMode = false;
  3432. Revert_Mouse_Shape();
  3433. }
  3434. }
  3435. }
  3436. /***********************************************************************************************
  3437. * DisplayClass::Repair_Mode_Control -- Controls the repair mode. *
  3438. * *
  3439. * This routine is used to control the repair mode for the player. *
  3440. * *
  3441. * INPUT: control -- The mode to set the repair to. *
  3442. * 0 = Turn repair off. *
  3443. * 1 = Turn repair on. *
  3444. * -1= Toggle repair state. *
  3445. * *
  3446. * OUTPUT: none *
  3447. * *
  3448. * WARNINGS: none *
  3449. * *
  3450. * HISTORY: *
  3451. * 07/08/1995 JLB : Created. *
  3452. *=============================================================================================*/
  3453. void DisplayClass::Repair_Mode_Control(int control)
  3454. {
  3455. bool mode = IsRepairMode;
  3456. switch (control) {
  3457. case 0:
  3458. mode = false;
  3459. break;
  3460. case -1:
  3461. mode = (IsRepairMode == false);
  3462. break;
  3463. case 1:
  3464. mode = true;
  3465. break;
  3466. }
  3467. if (mode != IsRepairMode && !PendingObject) {
  3468. IsSellMode = false;
  3469. if (mode && PlayerPtr->BScan) {
  3470. IsRepairMode = true;
  3471. Unselect_All();
  3472. } else {
  3473. IsRepairMode = false;
  3474. Revert_Mouse_Shape();
  3475. }
  3476. }
  3477. }
  3478. /***********************************************************************************************
  3479. * DisplayClass::In_View -- Determines if cell is visible on screen. *
  3480. * *
  3481. * Use this routine to determine if the specified cell is visible on *
  3482. * the display. This is a useful fact, since many display operations *
  3483. * can be skipped if the cell is not visible. *
  3484. * *
  3485. * INPUT: cell -- The cell number to check. *
  3486. * *
  3487. * OUTPUT: bool; Is this cell visible on the display? *
  3488. * *
  3489. * WARNINGS: none *
  3490. * *
  3491. * HISTORY: *
  3492. * 04/30/1994 JLB : Created. *
  3493. * 04/30/1994 JLB : Converted to member function. *
  3494. *=============================================================================================*/
  3495. bool DisplayClass::In_View(register CELL cell) const
  3496. {
  3497. if (cell & 0xC000) return(false);
  3498. COORDINATE coord = Coord_Whole(Cell_Coord(cell));
  3499. COORDINATE tcoord = Coord_Whole(TacticalCoord);
  3500. if ((unsigned)(Coord_X(coord) - Coord_X(tcoord)) > TacLeptonWidth+CELL_LEPTON_W-1) return(false);
  3501. if ((unsigned)(Coord_Y(coord) - Coord_Y(tcoord)) > TacLeptonHeight+CELL_LEPTON_H-1) return(false);
  3502. return(true);
  3503. }
  3504. /***********************************************************************************************
  3505. * DisplayClass::Closest_Free_Spot -- Finds the closest cell sub spot that is free. *
  3506. * *
  3507. * Use this routine to find the sub cell spot closest to the coordinate specified that is *
  3508. * free from occupation. Typical use of this is for infantry destination calculation. *
  3509. * *
  3510. * INPUT: coord -- The coordinate to use as the starting point when finding the closest *
  3511. * free spot. *
  3512. * *
  3513. * any -- Ignore occupation and just return the closest sub cell spot? *
  3514. * *
  3515. * OUTPUT: Returns with the coordinate of the closest free (possibly) sub cell location. *
  3516. * *
  3517. * WARNINGS: none *
  3518. * *
  3519. * HISTORY: *
  3520. * 09/22/1995 JLB : Created. *
  3521. *=============================================================================================*/
  3522. COORDINATE DisplayClass::Closest_Free_Spot(COORDINATE coord, bool any) const
  3523. {
  3524. if (coord & HIGH_COORD_MASK) {
  3525. return(0x00800080);
  3526. }
  3527. return Map[coord].Closest_Free_Spot(coord, any);
  3528. }
  3529. /***********************************************************************************************
  3530. * DisplayClass::Is_Spot_Free -- Determines if cell sub spot is free of occupation. *
  3531. * *
  3532. * Use this routine to determine if the coordinate (rounded to the nearest sub cell *
  3533. * position) is free for placement. Typical use of this would be for infantry placement. *
  3534. * *
  3535. * INPUT: coord -- The coordinate to examine for "freeness". The coordinate is rounded to *
  3536. * the nearest free sub cell spot. *
  3537. * *
  3538. * OUTPUT: Is the sub spot indicated by the coordinate free from previous occupation? *
  3539. * *
  3540. * WARNINGS: none *
  3541. * *
  3542. * HISTORY: *
  3543. * 09/22/1995 JLB : Created. *
  3544. *=============================================================================================*/
  3545. bool DisplayClass::Is_Spot_Free(COORDINATE coord) const
  3546. {
  3547. if (coord & HIGH_COORD_MASK) {
  3548. return(0x00800080);
  3549. }
  3550. return Map[coord].Is_Spot_Free(CellClass::Spot_Index(coord));
  3551. }
  3552. /***********************************************************************************************
  3553. * DisplayClass::Center_Map -- Centers the map about the currently selected objects *
  3554. * *
  3555. * This routine will average the position of all the selected objects and then center *
  3556. * the map about those objects. *
  3557. * *
  3558. * INPUT: center -- The is an optional center about override coordinate. If specified, *
  3559. * then the map will be centered about that coordinate. Otherwise it *
  3560. * will center about the average location of all selected objects. *
  3561. * *
  3562. * OUTPUT: none *
  3563. * *
  3564. * WARNINGS: The map position changes by this routine. *
  3565. * *
  3566. * HISTORY: *
  3567. * 08/22/1995 JLB : Created. *
  3568. * 09/16/1996 JLB : Takes coordinate to center about (as override). *
  3569. *=============================================================================================*/
  3570. void DisplayClass::Center_Map(COORDINATE center)
  3571. {
  3572. int x = 0;
  3573. // unsigned x = 0;
  3574. int y = 0;
  3575. // unsigned y = 0;
  3576. bool centerit = false;
  3577. if (CurrentObject.Count()) {
  3578. for (int index = 0; index < CurrentObject.Count(); index++) {
  3579. COORDINATE coord = CurrentObject[index]->Center_Coord();
  3580. x += Coord_X(coord);
  3581. y += Coord_Y(coord);
  3582. }
  3583. x /= CurrentObject.Count();
  3584. y /= CurrentObject.Count();
  3585. centerit = true;
  3586. }
  3587. if (center != 0L) {
  3588. x = Coord_X(center);
  3589. y = Coord_Y(center);
  3590. centerit = true;
  3591. }
  3592. if (centerit) {
  3593. x = x - (int)TacLeptonWidth/2;
  3594. if (x < Cell_To_Lepton(MapCellX)) x = Cell_To_Lepton(MapCellX);
  3595. y = y - (int)TacLeptonHeight/2;
  3596. if (y < Cell_To_Lepton(MapCellY)) y = Cell_To_Lepton(MapCellY);
  3597. Set_Tactical_Position(XY_Coord(x, y));
  3598. }
  3599. }
  3600. /***********************************************************************************************
  3601. * DisplayClass::Encroach_Shadow -- Causes the shadow to creep back by one cell. *
  3602. * *
  3603. * This routine will cause the shadow to creep back by one cell. Multiple calls to this *
  3604. * routine will result in the shadow becoming more and more invasive until only the sight *
  3605. * range of player controlled units will keep the shadow pushed back. *
  3606. * *
  3607. * INPUT: none *
  3608. * *
  3609. * OUTPUT: none *
  3610. * *
  3611. * WARNINGS: none *
  3612. * *
  3613. * HISTORY: *
  3614. * 10/16/1995 JLB : Created. *
  3615. *=============================================================================================*/
  3616. void DisplayClass::Encroach_Shadow(void)
  3617. {
  3618. for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) {
  3619. if (!In_Radar(cell)) continue;
  3620. CellClass * cellptr = &(*this)[cell];
  3621. if (cellptr->IsVisible || !cellptr->IsMapped) continue;
  3622. cellptr->IsToShroud = true;
  3623. }
  3624. /*
  3625. ** Mark all shadow edge cells to be fully shrouded. All adjacent mapped
  3626. ** cell should become partially shrouded.
  3627. */
  3628. for (cell = 0; cell < MAP_CELL_TOTAL; cell++) {
  3629. if (!In_Radar(cell)) continue;
  3630. if ((*this)[cell].IsToShroud) {
  3631. (*this)[cell].IsToShroud = false;
  3632. Shroud_Cell(cell);
  3633. }
  3634. }
  3635. All_To_Look();
  3636. Flag_To_Redraw(true);
  3637. }
  3638. /***********************************************************************************************
  3639. * DisplayClass::Shroud_Cell -- Returns the specified cell into the shrouded condition. *
  3640. * *
  3641. * This routine is called to add the shroud back to the cell specified. Typical of this *
  3642. * would be when the shroud is to regenerate. *
  3643. * *
  3644. * INPUT: cell -- The cell that the shroud is to be regenerated upon. *
  3645. * *
  3646. * OUTPUT: none *
  3647. * *
  3648. * WARNINGS: Adjacent cells might be affected by this routine. The affect is determined *
  3649. * according to the legality of the partial shadow artwork. In the illegal cases *
  3650. * the adjacent cell might become shrouded as well. *
  3651. * *
  3652. * HISTORY: *
  3653. * 10/17/1995 JLB : Created. *
  3654. * 06/17/1996 JLB : Modified to handle the new shadow pieces. *
  3655. *=============================================================================================*/
  3656. void DisplayClass::Shroud_Cell(CELL cell/*KO, bool shadeit*/)
  3657. {
  3658. if (PlayerPtr->IsGPSActive) {
  3659. if ( (*this)[cell].Jammed & (1 << PlayerPtr->Class->House) ) {
  3660. return;
  3661. }
  3662. }
  3663. if (!In_Radar(cell)) return;
  3664. CellClass * cellptr = &(*this)[cell];
  3665. if (cellptr->IsMapped) {
  3666. cellptr->IsMapped = false;
  3667. cellptr->IsVisible = false;
  3668. cellptr->Redraw_Objects();
  3669. /*
  3670. ** Check adjacent cells. There might be some weird combination of
  3671. ** shrouded cells such that more cells must be shrouded in order for
  3672. ** this to work.
  3673. */
  3674. for (FacingType dir = FACING_FIRST; dir < FACING_COUNT; dir++) {
  3675. CELL c = Adjacent_Cell(cell, dir);
  3676. CellClass * cptr = &(*this)[c];
  3677. /*
  3678. ** If this adjacent cell must be completely shrouded as a result
  3679. ** of the map change, yet it isn't already shrouded, then recursively
  3680. ** shroud that cell.
  3681. */
  3682. if (c != cell) {
  3683. cptr->IsVisible = false;
  3684. }
  3685. /*
  3686. ** Always redraw the cell because, more than likely, the shroud
  3687. ** edge will change shape because of the map change.
  3688. */
  3689. cptr->Redraw_Objects();
  3690. }
  3691. }
  3692. }
  3693. /***********************************************************************************************
  3694. * DisplayClass::Read_INI -- Reads map control data from INI file. *
  3695. * *
  3696. * This routine is used to read the map control data from the INI *
  3697. * file. *
  3698. * *
  3699. * INPUT: buffer -- Pointer to the loaded INI file data. *
  3700. * *
  3701. * OUTPUT: none *
  3702. * *
  3703. * WARNINGS: The TriggerClass INI data must have been read before calling this function. *
  3704. * *
  3705. * HISTORY: *
  3706. * 05/27/1994 JLB : Created. *
  3707. *=============================================================================================*/
  3708. void DisplayClass::Read_INI(CCINIClass & ini)
  3709. {
  3710. /*
  3711. ** Read the map dimensions.
  3712. */
  3713. char const * const name = "Map";
  3714. int x = ini.Get_Int(name, "X", 1);
  3715. int y = ini.Get_Int(name, "Y", 1);
  3716. int w = ini.Get_Int(name, "Width", MAP_CELL_W-2);
  3717. int h = ini.Get_Int(name, "Height", MAP_CELL_H-2);
  3718. #ifndef FIXIT_VERSION_3 // Map size no longer restricted.
  3719. #ifdef FIXIT_CSII // checked - ajw
  3720. if(Session.Type >= GAME_MODEM && Session.Type <= GAME_INTERNET && PlayingAgainstVersion < VERSION_AFTERMATH_CS) {
  3721. /*
  3722. ** HACK ALERT:
  3723. ** Force the map to be limited to the size that 96x96 would be. If the
  3724. ** size is greater (due to hacking?) then shrink it down to legal size.
  3725. ** BG Note: only do this for multiplayer games against non-AfterMath.
  3726. */
  3727. if (w * h > 96 * 96) {
  3728. h -= (((w*h) - (96*96)) / w) + 1;
  3729. }
  3730. }
  3731. #else
  3732. /*
  3733. ** HACK ALERT:
  3734. ** Force the map to be limited to the size that 96x96 would be. If the
  3735. ** size is greater (due to hacking?) then shrink it down to legal size.
  3736. */
  3737. if (w * h > 96 * 96) {
  3738. h -= (((w*h) - (96*96)) / w) + 1;
  3739. }
  3740. #endif
  3741. #endif // !FIXIT_VERSION_3
  3742. Set_Map_Dimensions( x, y, w, h );
  3743. /*
  3744. ** The theater is determined at this point. There is specific data that
  3745. ** is custom to this data. Load the custom data (as it related to terrain)
  3746. ** at this point.
  3747. */
  3748. Scen.Theater = ini.Get_TheaterType(name, "Theater", THEATER_TEMPERATE);
  3749. /*
  3750. ** Remove any old theater specific uncompressed shapes
  3751. */
  3752. #ifdef WIN32
  3753. if (Scen.Theater != LastTheater) {
  3754. Reset_Theater_Shapes();
  3755. }
  3756. #endif //WIN32
  3757. /*
  3758. ** Now that the theater is known, init the entire map hierarchy
  3759. */
  3760. Init(Scen.Theater);
  3761. /*
  3762. ** Special initializations occur when the theater is known.
  3763. */
  3764. TerrainTypeClass::Init(Scen.Theater);
  3765. TemplateTypeClass::Init(Scen.Theater);
  3766. OverlayTypeClass::Init(Scen.Theater);
  3767. UnitTypeClass::Init(Scen.Theater);
  3768. InfantryTypeClass::Init(Scen.Theater);
  3769. BuildingTypeClass::Init(Scen.Theater);
  3770. BulletTypeClass::Init(Scen.Theater);
  3771. AnimTypeClass::Init(Scen.Theater);
  3772. AircraftTypeClass::Init(Scen.Theater);
  3773. VesselTypeClass::Init(Scen.Theater);
  3774. SmudgeTypeClass::Init(Scen.Theater);
  3775. /*
  3776. ** Read the Waypoint entries.
  3777. */
  3778. for (int i = 0; i < WAYPT_COUNT; i++) {
  3779. char buf[20];
  3780. sprintf(buf, "%d", i);
  3781. Scen.Waypoint[i] = ini.Get_Int("Waypoints", buf, -1);
  3782. if (Scen.Waypoint[i] != -1) {
  3783. (*this)[Scen.Waypoint[i]].IsWaypoint = 1;
  3784. }
  3785. }
  3786. /*
  3787. ** Set the starting position (do this after Init(), which clears the cells'
  3788. ** IsWaypoint flags).
  3789. */
  3790. if (Scen.Waypoint[WAYPT_HOME] == -1) {
  3791. Scen.Waypoint[WAYPT_HOME] = XY_Cell(MapCellX + 5*RESFACTOR, MapCellY + 4*RESFACTOR);
  3792. }
  3793. Scen.Views[0] = Scen.Views[1] = Scen.Views[2] = Scen.Views[3] = Scen.Waypoint[WAYPT_HOME];
  3794. Set_Tactical_Position(Cell_Coord((Scen.Waypoint[WAYPT_HOME] - (MAP_CELL_W * 4 * RESFACTOR)) - (5*RESFACTOR)));
  3795. /*
  3796. ** Loop through all CellTrigger entries.
  3797. */
  3798. int len = ini.Entry_Count("CellTriggers");
  3799. for (int index = 0; index < len; index++) {
  3800. /*
  3801. ** Get a cell trigger and cell assignment.
  3802. */
  3803. char const * cellentry = ini.Get_Entry("CellTriggers", index);
  3804. TriggerTypeClass * tp = ini.Get_TriggerType("CellTriggers", cellentry);
  3805. CELL cell = atoi(cellentry);
  3806. if (tp != NULL && !(*this)[cell].Trigger.Is_Valid()) {
  3807. TriggerClass * tt = Find_Or_Make(tp);
  3808. if (tt) {
  3809. tt->AttachCount++;
  3810. tt->Cell = cell;
  3811. (*this)[cell].Trigger = tt;
  3812. }
  3813. }
  3814. }
  3815. /*
  3816. ** Read the map template data.
  3817. */
  3818. static char const * const MAPPACK = "MapPack";
  3819. len = ini.Get_UUBlock(MAPPACK, _staging_buffer, sizeof(_staging_buffer));
  3820. BufferStraw bstraw(_staging_buffer, len);
  3821. Map.Read_Binary(bstraw);
  3822. LastTheater = Scen.Theater;
  3823. }
  3824. /***********************************************************************************************
  3825. * DisplayClass::Write_INI -- Write the map data to the INI file specified. *
  3826. * *
  3827. * This routine will output all the data of this map to the INI database specified. *
  3828. * *
  3829. * INPUT: ini -- Reference to the INI handler to store the map data to. *
  3830. * *
  3831. * OUTPUT: none *
  3832. * *
  3833. * WARNINGS: Any existing map data in the INI database will be replaced by this function. *
  3834. * *
  3835. * HISTORY: *
  3836. * 07/03/1996 JLB : Created. *
  3837. *=============================================================================================*/
  3838. void DisplayClass::Write_INI(CCINIClass & ini)
  3839. {
  3840. char entry[20];
  3841. /*
  3842. ** Save the map parameters.
  3843. */
  3844. static char const * const NAME = "Map";
  3845. ini.Clear(NAME);
  3846. ini.Put_TheaterType(NAME, "Theater", Scen.Theater);
  3847. ini.Put_Int(NAME, "X", MapCellX);
  3848. ini.Put_Int(NAME, "Y", MapCellY);
  3849. ini.Put_Int(NAME, "Width", MapCellWidth);
  3850. ini.Put_Int(NAME, "Height", MapCellHeight);
  3851. /*
  3852. ** Save the Waypoint entries.
  3853. */
  3854. static char const * const WAYNAME = "Waypoints";
  3855. ini.Clear(WAYNAME);
  3856. for (int i = 0; i < WAYPT_COUNT; i++) {
  3857. if (Scen.Waypoint[i] != -1) {
  3858. sprintf(entry, "%d", i);
  3859. ini.Put_Int(WAYNAME, entry, Scen.Waypoint[i]);
  3860. }
  3861. }
  3862. /*
  3863. ** Save the cell's triggers.
  3864. */
  3865. static char const * const CELLTRIG = "CellTriggers";
  3866. ini.Clear(CELLTRIG);
  3867. for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) {
  3868. if ((*this)[cell].Trigger.Is_Valid()) {
  3869. TriggerClass * tp = (*this)[cell].Trigger;
  3870. if (tp != NULL) {
  3871. /*
  3872. ** Generate entry name.
  3873. */
  3874. sprintf(entry, "%d", cell);
  3875. /*
  3876. ** Save entry.
  3877. */
  3878. ini.Put_TriggerType(CELLTRIG, entry, tp->Class);
  3879. }
  3880. }
  3881. }
  3882. /*
  3883. ** Write the map template data out to the ini file.
  3884. */
  3885. static char const * const MAPPACK = "MapPack";
  3886. BufferPipe bpipe(_staging_buffer, sizeof(_staging_buffer));
  3887. int len = Map.Write_Binary(bpipe);
  3888. ini.Clear(MAPPACK);
  3889. if (len) {
  3890. ini.Put_UUBlock(MAPPACK, _staging_buffer, len);
  3891. }
  3892. }
  3893. /***********************************************************************************************
  3894. * DisplayClass::All_To_Look -- Direct all objects to look around for the player. *
  3895. * *
  3896. * This routine will scan through all objects and tell them to look if they are supposed *
  3897. * to be able to reveal the map for the player. This routine may be necessary in cases *
  3898. * of gap generator reshroud logic. *
  3899. * *
  3900. * INPUT: none *
  3901. * *
  3902. * OUTPUT: none *
  3903. * *
  3904. * WARNINGS: none *
  3905. * *
  3906. * HISTORY: *
  3907. * 09/23/1996 JLB : Created. *
  3908. *=============================================================================================*/
  3909. void DisplayClass::All_To_Look(bool units_only)
  3910. {
  3911. for (int index = 0; index < Layer[LAYER_GROUND].Count(); index++) {
  3912. ObjectClass * object = Layer[LAYER_GROUND][index];
  3913. if (object != NULL && object->Is_Techno()) {
  3914. TechnoClass * tech = ((TechnoClass *)object);
  3915. if (tech->What_Am_I() == RTTI_BUILDING && units_only) continue;
  3916. if (tech->House->IsPlayerControl) {
  3917. if (tech->IsDiscoveredByPlayer) {
  3918. object->Look();
  3919. }
  3920. } else {
  3921. if (tech->What_Am_I() == RTTI_BUILDING && Rule.IsAllyReveal && tech->House->Is_Ally(PlayerPtr)) {
  3922. tech->Look();
  3923. }
  3924. }
  3925. }
  3926. }
  3927. }
  3928. void DisplayClass::Constrained_Look(COORDINATE center, LEPTON distance)
  3929. {
  3930. for (int index = 0; index < Layer[LAYER_GROUND].Count(); index++) {
  3931. ObjectClass * object = Layer[LAYER_GROUND][index];
  3932. if (object != NULL && object->Is_Techno()) {
  3933. TechnoClass * tech = ((TechnoClass *)object);
  3934. // if (tech->What_Am_I() == RTTI_BUILDING && units_only) continue;
  3935. if (tech->House->IsPlayerControl) {
  3936. if (tech->IsDiscoveredByPlayer && Distance(tech->Center_Coord(), center) <= (tech->Techno_Type_Class()->SightRange * CELL_LEPTON_W) + distance) {
  3937. object->Look();
  3938. }
  3939. } else {
  3940. if (tech->What_Am_I() == RTTI_BUILDING && Rule.IsAllyReveal && tech->House->Is_Ally(PlayerPtr) &&
  3941. Distance(tech->Center_Coord(), center) <= (tech->Techno_Type_Class()->SightRange * CELL_LEPTON_W) + distance) {
  3942. tech->Look();
  3943. }
  3944. }
  3945. }
  3946. }
  3947. }
  3948. /***********************************************************************************************
  3949. * DisplayClass::Flag_Cell -- Flag the specified cell to be redrawn. *
  3950. * *
  3951. * This will flag the cell to be redrawn. *
  3952. * *
  3953. * INPUT: cell -- The cell to be flagged. *
  3954. * *
  3955. * OUTPUT: none *
  3956. * *
  3957. * WARNINGS: none *
  3958. * *
  3959. * HISTORY: *
  3960. * 10/20/1996 JLB : Created. *
  3961. *=============================================================================================*/
  3962. void DisplayClass::Flag_Cell(CELL cell)
  3963. {
  3964. Flag_To_Redraw(false);
  3965. IsToRedraw = true;
  3966. CellRedraw[cell] = true;
  3967. }