12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415 |
- //
- // Copyright 2020 Electronic Arts Inc.
- //
- // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
- // software: you can redistribute it and/or modify it under the terms of
- // the GNU General Public License as published by the Free Software Foundation,
- // either version 3 of the License, or (at your option) any later version.
- // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
- // in the hope that it will be useful, but with permitted additional restrictions
- // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
- // distributed with this program. You should have received a copy of the
- // GNU General Public License along with permitted additional restrictions
- // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
- /* $Header: F:\projects\c&c\vcs\code\display.cpv 2.16 16 Oct 1995 16:48:24 JOE_BOSTIC $ */
- /***********************************************************************************************
- *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
- ***********************************************************************************************
- * *
- * Project Name : Command & Conquer *
- * *
- * File Name : DISPLAY.CPP *
- * *
- * Programmer : Joe L. Bostic *
- * *
- * Start Date : September 10, 1993 *
- * *
- * Last Update : August 24, 1995 [JLB] *
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * DisplayClass::AI -- Handles the maintenance tasks for the map display. *
- * DisplayClass::Calculated_Cell -- Fetch a map cell based on specified method. *
- * DisplayClass::Cell_Object -- Determines what has been clicked on. *
- * DisplayClass::Cell_Shadow -- Determine what shadow icon to use for the cell. *
- * DisplayClass::Click_Cell_Calc -- Determines cell from screen X & Y. *
- * DisplayClass::Coord_To_Pixel -- Determines X and Y pixel coordinates. *
- * DisplayClass::Cursor_Mark -- Set or resets the cursor display flag bits. *
- * DisplayClass::DisplayClass -- Default constructor for display class. *
- * DisplayClass::Draw_It -- Draws the tactical map. *
- * DisplayClass::Flag_To_Redraw -- Flags the display so that it will be redrawn as soon as poss*
- * DisplayClass::Get_Occupy_Dimensions -- computes width & height of the given occupy list *
- * DisplayClass::Init_Clear -- Clears the display to a known state. *
- * DisplayClass::Init_IO -- Creates the map's button list *
- * DisplayClass::Init_Theater -- Theater-specific initialization *
- * DisplayClass::Map_Cell -- Mark specified cell as having been mapped. *
- * DisplayClass::Mouse_Left_Held -- Handles the left button held down. *
- * DisplayClass::Mouse_Left_Press -- Handles the left mouse button press. *
- * DisplayClass::Mouse_Left_Release -- Handles the left mouse button release. *
- * DisplayClass::Mouse_Left_Up -- Handles the left mouse "cruising" over the map. *
- * DisplayClass::Mouse_Right_Press -- Handles the right mouse button press. *
- * DisplayClass::Next_Object -- Searches for next object on display. *
- * DisplayClass::One_Time -- Performs any special one time initializations. *
- * DisplayClass::Passes_Proximity_Check -- Determines if building placement is near friendly sq*
- * DisplayClass::Pixel_To_Coord -- converts screen coord to COORDINATE *
- * DisplayClass::Read_INI -- Reads map control data from INI file. *
- * DisplayClass::Redraw_Icons -- Draws all terrain icons necessary. *
- * DisplayClass::Redraw_Shadow -- Draw the shadow overlay. *
- * DisplayClass::Refresh_Band -- Causes all cells under the rubber band to be redrawn. *
- * DisplayClass::Refresh_Cells -- Redraws all cells in list. *
- * DisplayClass::Remove -- Removes a game object from the rendering system. *
- * DisplayClass::Repair_Mode_Control -- Controls the repair mode. *
- * DisplayClass::Scroll_Map -- Scroll the tactical map in desired direction. *
- * DisplayClass::Select_These -- All selectable objects in region are selected. *
- * DisplayClass::Sell_Mode_Control -- Controls the sell mode. *
- * DisplayClass::Set_Cursor_Pos -- Controls the display and animation of the tac cursor. *
- * DisplayClass::Set_Cursor_Shape -- Changes the shape of the terrain square cursor. *
- * DisplayClass::Set_View_Dimensions -- Sets the tactical display screen coordinates. *
- * DisplayClass::Submit -- Adds a game object to the map rendering system. *
- * DisplayClass::TacticalClass::Action -- Processes input for the tactical map. *
- * DisplayClass::Text_Overlap_List -- Creates cell overlap list for specified text string. *
- * DisplayClass::Write_INI -- Writes map data into INI file. *
- * DisplayClass::Set_Tactical_Position -- Sets the tactical view position. *
- * DisplayClass::Center_Map -- Centers the map about the currently selected objects *
- * DisplayClass::Prev_Object -- Searches for the previous object on the map. *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "function.h"
- /*
- ** These layer control elements are used to group the displayable objects
- ** so that proper overlap can be obtained.
- */
- LayerClass DisplayClass::Layer[LAYER_COUNT];
- /*
- ** Fading tables
- */
- unsigned char DisplayClass::FadingBrighten[256];
- unsigned char DisplayClass::FadingShade[256];
- unsigned char DisplayClass::FadingLight[256];
- unsigned char DisplayClass::RemapTables[HOUSE_COUNT][3][256];
- unsigned char DisplayClass::FadingGreen[256];
- unsigned char DisplayClass::FadingYellow[256];
- unsigned char DisplayClass::FadingRed[256];
- unsigned char DisplayClass::TranslucentTable[(MAGIC_COL_COUNT+1)*256];
- unsigned char DisplayClass::WhiteTranslucentTable[(1+1)*256];
- unsigned char DisplayClass::MouseTranslucentTable[(4+1)*256];
- void const * DisplayClass::TransIconset;
- unsigned char DisplayClass::UnitShadow[(USHADOW_COL_COUNT+1)*256];
- unsigned char DisplayClass::SpecialGhost[2*256];
- void const * DisplayClass::ShadowShapes;
- unsigned char DisplayClass::ShadowTrans[(SHADOW_COL_COUNT+1)*256];
- /*
- ** Bit array of cell redraw flags
- */
- BooleanVectorClass DisplayClass::CellRedraw;
- /*
- ** The main button that intercepts user input to the map
- */
- DisplayClass::TacticalClass DisplayClass::TacButton;
- //
- // We need a way to bypass visible view checks when we are running in the context of GlyphX without using the
- // internal C&C renderer. We shouldn't know or care what the user is actually looking at
- // ST - 4/17/2019 9:01AM
- //
- bool DisplayClass::IgnoreViewConstraints = false;
- /*
- ** Define "_RETRIEVE" if the palette morphing tables are part of the loaded data. If this
- ** is undefined, then the files will be created.
- */
- #define _RETRIEVE
- static int const TEX_X = 0;
- static int const TEX_Y = 6;
- static int const TEX_W = 14;
- extern MixFileClass *TheaterIcons;
- //Added for getting the input for special character keys from the client
- // - 6/26/2019 JAS
- extern bool DLL_Export_Get_Input_Key_State(KeyNumType key);
- /***********************************************************************************************
- * DisplayClass::DisplayClass -- Default constructor for display class. *
- * *
- * This constructor for the display class just initializes some of the display settings. *
- * Most settings are initialized with the correct values at the time that the Init function *
- * is called. There are some cases where default values are wise and this routine fills *
- * those particular ones in. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/06/1994 JLB : Created. *
- *=============================================================================================*/
- DisplayClass::DisplayClass(void)
- {
- TacticalCoord = 0;
- ShadowShapes = 0;
- TransIconset = 0;
- ZoneCell = 0;
- ZoneOffset = 0;
- CursorSize = 0;
- ProximityCheck = false;
- PendingObjectPtr = 0;
- PendingObject = 0;
- PendingHouse = HOUSE_NONE;
- IsRepairMode = false;
- IsTargettingMode = false;
- IsToRedraw = true;
- IsRubberBand = false;
- IsTentative = false;
- IsSellMode = false;
- }
- /***********************************************************************************************
- * DisplayClass::One_Time -- Performs any special one time initializations. *
- * *
- * This routine is called from the game initialization process. It is to perform any one *
- * time initializations necessary for the map display system. It allocates the staging *
- * buffer needed for the radar map. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: This routine must be called ONCE and only once. *
- * *
- * HISTORY: *
- * 05/31/1994 JLB : Created. *
- * 05/31/1994 JLB : Handles layer system now. *
- * 06/02/1994 JLB : Takes care of misc display tables and data allocation. *
- *=============================================================================================*/
- void DisplayClass::One_Time(void)
- {
- Set_View_Dimensions(0, Map.Get_Tab_Height());
- MapClass::One_Time();
- /*
- ** Init the CellRedraw bit array. Do not do this in the constructor, since the
- ** BooleanVector may not have been constructed yet.
- */
- CellRedraw.Resize(MAP_CELL_TOTAL);
- for (LayerType layer = LAYER_FIRST; layer < LAYER_COUNT; layer++) {
- Layer[layer].One_Time();
- }
- /*
- ** Load the generic transparent icon set.
- */
- TransIconset = MixFileClass::Retrieve("TRANS.ICN");
- ShadowShapes = MixFileClass::Retrieve("SHADOW.SHP");
- Set_View_Dimensions(0, Map.Get_Tab_Height());
- /*
- ** Allocate and initialize the remap tables needed for each "house".
- */
- HousesType hindex;
- int fade;
- for (fade = 0; fade < 3; fade++) {
- for (hindex = HOUSE_FIRST; hindex < HOUSE_COUNT; hindex++) {
- int color;
- switch (fade) {
- case 0:
- for (color = 0; color < 256; color++) {
- RemapTables[hindex][fade][color] = color;
- }
- break;
- case 1:
- Mem_Copy(FadingLight, RemapTables[hindex][fade], 256);
- break;
- case 2:
- Mem_Copy(FadingShade, RemapTables[hindex][fade], 256);
- break;
- }
- Mem_Copy(&RemapTables[hindex][fade][((int)hindex+11)*16], &RemapTables[hindex][fade][(0+11)*16], 16);
- }
- }
- }
- /***********************************************************************************************
- * DisplayClass::Init_Clear -- clears the display to a known state *
- * *
- * INPUT: *
- * none. *
- * *
- * OUTPUT: *
- * none. *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 03/17/1995 BRR : Created. *
- *=============================================================================================*/
- void DisplayClass::Init_Clear(void)
- {
- MapClass::Init_Clear();
- /*
- ** Clear any object being placed
- */
- PendingObjectPtr = 0;
- PendingObject = 0;
- PendingHouse = HOUSE_NONE;
- CursorSize = 0;
- IsTargettingMode = false;
- IsRepairMode = false;
- IsRubberBand = false;
- IsTentative = false;
- IsSellMode = false;
- /*
- ** Empty all the display's layers
- */
- for (LayerType layer = LAYER_FIRST; layer < LAYER_COUNT; layer++) {
- Layer[layer].Init();
- }
- }
- /***********************************************************************************************
- * DisplayClass::Init_IO -- clears & re-builds the map's button list *
- * *
- * INPUT: *
- * none. *
- * *
- * OUTPUT: *
- * none. *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 03/17/1995 BRR : Created. *
- *=============================================================================================*/
- void DisplayClass::Init_IO(void)
- {
- MapClass::Init_IO();
- /*
- ** Re-attach our buttons to the main map button list, only in non-edit mode.
- */
- if (!Debug_Map) {
- TacButton.Zap();
- Add_A_Button(TacButton);
- }
- }
- /***********************************************************************************************
- * DisplayClass::Init_Theater -- Performs theater-specific initialization (mixfiles, etc) *
- * *
- * INPUT: *
- * theater new theater *
- * *
- * OUTPUT: *
- * none. *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 03/17/1995 BRR : Created. *
- *=============================================================================================*/
- void DisplayClass::Init_Theater(TheaterType theater)
- {
- char fullname[16];
- char iconname[16];
- #ifndef _RETRIEVE
- static TLucentType const MouseCols[4] = {
- {BLACK, BLACK, 110, 0},
- {WHITE, WHITE, 110, 0},
- {LTGREY, LTGREY, 110, 0},
- {DKGREY, DKGREY, 110, 0}
- };
- static TLucentType const MagicCols[MAGIC_COL_COUNT] = {
- {32,32,110,0},
- {33,33,110,0},
- {34,34,110,0},
- {35,35,110,0},
- {36,36,110,0},
- {37,37,110,0},
- {38,38,110,0},
- {39,39,110,0},
- {BLACK, BLACK, 200, 0},
- {WHITE, BLACK, 40, 0},
- {LTGREY, BLACK, 80, 0},
- {DKGREY, BLACK, 140, 0}
- };
- static TLucentType const WhiteCols[1] = {
- {1, WHITE, 80, 0}
- };
- static TLucentType const ShadowCols[SHADOW_COL_COUNT] = {
- {WHITE+1, BLACK,130,0},
- {WHITE, BLACK,170,0},
- {LTGRAY, BLACK,250,0},
- {DKGRAY, BLACK,250,0}
- };
- static TLucentType const UShadowCols[USHADOW_COL_COUNT] = {
- {LTGREEN, BLACK,130,0}
- };
- #endif
- /*
- ---------------------- Invoke parent's init routine ----------------------
- */
- MapClass::Init_Theater(theater);
- /*
- ** Save the new theater value
- */
- Theater = theater;
- #ifndef DEMO
- /*
- ** Unload old mixfiles, and cache the new ones
- */
- sprintf(fullname, "%s.MIX", Theaters[Theater].Root);
- if (Theater != LastTheater){
- if (TheaterData) {
- delete TheaterData;
- }
- TheaterData = new MixFileClass(fullname);
- TheaterData->Cache();
- }
- #endif
- /*
- ** Register the hi-res icons mix file now since it is theater specific
- */
- sprintf(fullname, "%s.MIX", Theaters[Theater].Root);
- strcpy (iconname, fullname);
- strcpy (&iconname[4], "ICNH.MIX");
- if (Theater != LastTheater){
- if (TheaterIcons) {
- delete TheaterIcons;
- }
- TheaterIcons = new MixFileClass(iconname);
- TheaterIcons->Cache();
- }
- /*
- ** Load the custom palette associated with this theater.
- ** The fading palettes will have to be generated as well.
- */
- sprintf(fullname, "%s.PAL", Theaters[theater].Root);
- void const * ptr = MixFileClass::Retrieve(fullname);
- Mem_Copy((void *)ptr, GamePalette, 768);
- Mem_Copy(GamePalette, OriginalPalette, 768);
- #ifndef _RETRIEVE
- /*
- ** Make sure that remapping doesn't occur on the colors that cycle.
- */
- memset(&GamePalette[CYCLE_COLOR_START*3], 0x3F, CYCLE_COLOR_COUNT*3);
- #endif
- #ifdef _RETRIEVE
- CCFileClass(Fading_Table_Name("GREEN", theater)).Read(FadingGreen, sizeof(FadingGreen));
- #else
- Build_Fading_Table(GamePalette, FadingGreen, GREEN, 110);
- CCFileClass(Fading_Table_Name("GREEN", theater)).Write(FadingGreen, sizeof(FadingGreen));
- #endif
- if (theater == THEATER_DESERT) {
- FadingGreen[196] = 160;
- }
- #ifdef _RETRIEVE
- CCFileClass(Fading_Table_Name("YELLOW", theater)).Read(FadingYellow, sizeof(FadingYellow));
- #else
- Build_Fading_Table(GamePalette, FadingYellow, YELLOW, 140);
- CCFileClass(Fading_Table_Name("YELLOW", theater)).Write(FadingYellow, sizeof(FadingYellow));
- #endif
- #ifdef _RETRIEVE
- CCFileClass(Fading_Table_Name("RED", theater)).Read(FadingRed, sizeof(FadingRed));
- #else
- Build_Fading_Table(GamePalette, FadingRed, RED, 140);
- CCFileClass(Fading_Table_Name("RED", theater)).Write(FadingRed, sizeof(FadingRed));
- #endif
- #ifdef _RETRIEVE
- CCFileClass(Fading_Table_Name("MOUSE", theater)).Read(MouseTranslucentTable, sizeof(MouseTranslucentTable));
- #else
- Build_Translucent_Table(GamePalette, &MouseCols[0], 4, MouseTranslucentTable);
- CCFileClass(Fading_Table_Name("MOUSE", theater)).Write(MouseTranslucentTable, sizeof(MouseTranslucentTable));
- #endif
- // MouseDrawPtr = MouseTranslucentTable;
- // MouseDrawPtr2 = Add_Long_To_Pointer(MouseTranslucentTable, 256L);
- // MouseDrawVal = 1;
- // MouseDrawFlags = (int)SHAPE_GHOST;
- #ifdef _RETRIEVE
- CCFileClass(Fading_Table_Name("TRANS", theater)).Read(TranslucentTable, sizeof(TranslucentTable));
- #else
- Build_Translucent_Table(GamePalette, &MagicCols[0], MAGIC_COL_COUNT, TranslucentTable);
- CCFileClass(Fading_Table_Name("TRANS", theater)).Write(TranslucentTable, sizeof(TranslucentTable));
- #endif
- #ifdef _RETRIEVE
- CCFileClass(Fading_Table_Name("WHITE", theater)).Read(WhiteTranslucentTable, sizeof(WhiteTranslucentTable));
- #else
- Build_Translucent_Table(GamePalette, &WhiteCols[0], 1, WhiteTranslucentTable);
- CCFileClass(Fading_Table_Name("WHITE", theater)).Write(WhiteTranslucentTable, sizeof(WhiteTranslucentTable));
- #endif
- #ifdef _RETRIEVE
- CCFileClass(Fading_Table_Name("SHADOW", theater)).Read(ShadowTrans, sizeof(ShadowTrans));
- #else
- Build_Translucent_Table(GamePalette, &ShadowCols[0], SHADOW_COL_COUNT, ShadowTrans);
- CCFileClass(Fading_Table_Name("SHADOW", theater)).Write(ShadowTrans, sizeof(ShadowTrans));
- #endif
- #ifdef _RETRIEVE
- CCFileClass(Fading_Table_Name("UNITS", theater)).Read(UnitShadow, sizeof(UnitShadow));
- #else
- Conquer_Build_Translucent_Table(GamePalette, &UShadowCols[0], USHADOW_COL_COUNT, UnitShadow);
- CCFileClass(Fading_Table_Name("UNITS", theater)).Write(UnitShadow, sizeof(UnitShadow));
- #endif
- #ifdef _RETRIEVE
- CCFileClass(Fading_Table_Name("SHADE", theater)).Read(FadingShade, sizeof(FadingShade));
- #else
- Conquer_Build_Fading_Table(GamePalette, FadingShade, BLACK, 150);
- CCFileClass(Fading_Table_Name("SHADE", theater)).Write(FadingShade, sizeof(FadingShade));
- #endif
- #ifdef _RETRIEVE
- CCFileClass(Fading_Table_Name("LIGHT", theater)).Read(FadingLight, sizeof(FadingLight));
- #else
- Conquer_Build_Fading_Table(GamePalette, FadingLight, WHITE, 85);
- CCFileClass(Fading_Table_Name("LIGHT", theater)).Write(FadingLight, sizeof(FadingLight));
- #endif
- /*
- ** Create the shadow color used by aircraft.
- */
- Conquer_Build_Fading_Table(GamePalette, &SpecialGhost[256], BLACK, 100);
- for (int index = 0; index < 256; index++) {
- SpecialGhost[index] = 0;
- }
- Build_Fading_Table(GamePalette, FadingBrighten, WHITE, 25);
- #ifndef _RETRIEVE
- /*
- ** Restore the palette since it was mangled while building the fading tables.
- */
- sprintf(fullname, "%s.PAL", Theaters[theater].Root);
- ptr = MixFileClass::Retrieve(fullname);
- Mem_Copy((void *)ptr, GamePalette, 768);
- Mem_Copy(GamePalette, OriginalPalette, 768);
- #endif
- /*
- ** Adjust the palette according to the visual control option settings.
- */
- Options.Fixup_Palette();
- }
- /***********************************************************************************************
- * DisplayClass::Text_Overlap_List -- Creates cell overlap list for specified text string. *
- * *
- * This routine is used to create an overlap list that specifies all the cells that are *
- * covered by the specified text string. This overlap list is used to handle map refresh *
- * logic. *
- * *
- * INPUT: text -- Pointer to the text that would appear on the map and must have an *
- * overlap list generated. *
- * *
- * x,y -- The coordinates that the text would appear (upper left corner). *
- * *
- * OUTPUT: Returns with a pointer to an overlap list that covers all cells "under" the text *
- * if were displayed at the coordinates specified. The list is actually a series of *
- * offsets from the display's upper left corner cell number. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/06/1994 JLB : Created. *
- * 12/07/1994 JLB : Sidebar fixup. *
- * 08/13/1995 JLB : Optimized for variable sized help text. *
- *=============================================================================================*/
- short const * DisplayClass::Text_Overlap_List(char const * text, int x, int y, int lines)
- {
- static short _list[30];
- if (text) {
- short * ptr = &_list[0];
- int len = String_Pixel_Width(text)+CELL_PIXEL_W;
- int right = TacPixelX + Lepton_To_Pixel(TacLeptonWidth);
- /*
- ** If the help text would spill into the sidebar, then flag this fact, but
- ** shorten the apparent length so that the icon list calculation will
- ** function correctly.
- */
- if (x+len >= TacPixelX+Lepton_To_Pixel(TacLeptonWidth)) {
- len = right-x;
- *ptr++ = REFRESH_SIDEBAR;
- }
- /*
- ** Build the list of overlap cell offset values according to the text
- ** coordinate and the length.
- */
- int height = (((FontHeight * lines) + 23) / 24) * 24;
- if (x <= right) {
- CELL ul = Click_Cell_Calc(x, y-1);
- CELL lr = Click_Cell_Calc(x+len-1, Bound(y+height, TacPixelY, SeenBuff.Get_Height() - 1));
- if (ul == -1) ul = Click_Cell_Calc(x, y);
- // if (lr == -1) lr = Click_Cell_Calc(x+len, y);
- if (ul != -1 && lr != -1) {
- for (int yy = Cell_Y(ul); yy <= Cell_Y(lr); yy++) {
- for (int xx = Cell_X(ul); xx <= Cell_X(lr); xx++) {
- *ptr++ = XY_Cell(xx, yy) - Coord_Cell(TacticalCoord);
- }
- }
- }
- }
- *ptr = REFRESH_EOL;
- }
- return(_list);
- }
- /***********************************************************************************************
- * DisplayClass::Set_View_Dimensions -- Sets the tactical display screen coordinates. *
- * *
- * Use this routine to set the tactical map screen coordinates and dimensions. This routine *
- * is typically used when the screen size or position changes as a result of the sidebar *
- * changing position or appearance. *
- * *
- * INPUT: x,y -- The X and Y pixel position on the screen for the tactical map upper left *
- * corner. *
- * *
- * width -- The width of the tactical display (in pixels). If this parameter is *
- * omitted, then the width will be as wide as the screen will allow. *
- * *
- * height-- The height of the tactial display (in pixels). If this parameter is *
- * omitted, then the width wil be as wide as the screen will allow. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/06/1994 JLB : Created. *
- * 06/27/1995 JLB : Adjusts tactical map position if necessary. *
- *=============================================================================================*/
- void DisplayClass::Set_View_Dimensions(int x, int y, int width, int height)
- {
- #if (1) // This code pulled in from RA1. ST - 1/9/2019 10:53AM
- if (width == -1) {
- TacLeptonWidth = Pixel_To_Lepton(SeenBuff.Get_Width()-x);
- } else {
- TacLeptonWidth = width * CELL_LEPTON_W;
- }
- // ST - 3/1/2019 12:05PM
- // Made the below code more consistent with the width calculation. This is needed if we aren't going to draw the tabs at the top of the screen
- //
- if (height == -1) {
- TacLeptonHeight = Pixel_To_Lepton(SeenBuff.Get_Height()-y);
- //height = (SeenBuff.Get_Height()-y) / CELL_PIXEL_H;
- } else {
- TacLeptonHeight = height * CELL_LEPTON_H;
- }
- //TacLeptonHeight = height * CELL_LEPTON_H;
- /*
- ** Adjust the tactical cell if it is now in an invalid position
- ** because of the changed dimensions.
- */
- int xx = 0;// Coord_X(TacticalCoord) - (MapCellX * CELL_LEPTON_W);
- int yy = 0;// Coord_Y(TacticalCoord) - (MapCellY * CELL_LEPTON_H);
- Confine_Rect(&xx, &yy, TacLeptonWidth, TacLeptonHeight, MapCellWidth * CELL_LEPTON_W, MapCellHeight * CELL_LEPTON_H);
- Set_Tactical_Position(XY_Coord(xx + (MapCellX * CELL_LEPTON_W), yy + (MapCellY * CELL_LEPTON_H)));
- TacPixelX = x;
- TacPixelY = y;
- WindowList[WINDOW_TACTICAL][WINDOWX] = x;
- WindowList[WINDOW_TACTICAL][WINDOWY] = y;
- WindowList[WINDOW_TACTICAL][WINDOWWIDTH] = Lepton_To_Pixel(TacLeptonWidth);
- WindowList[WINDOW_TACTICAL][WINDOWHEIGHT] = Lepton_To_Pixel(TacLeptonHeight);
- if (Window == WINDOW_TACTICAL) {
- Change_Window(0);
- Change_Window(Window);
- }
- IsToRedraw = true;
- Flag_To_Redraw(false);
- TacButton.X = TacPixelX;
- TacButton.Y = TacPixelY;
- TacButton.Width = Lepton_To_Pixel(TacLeptonWidth);
- TacButton.Height = Lepton_To_Pixel(TacLeptonHeight);
- #else //CNC code
- if (width == -1) {
- width = SeenBuff.Get_Width() - x;
- }
- TacLeptonWidth = Pixel_To_Lepton(width);
- if (height == -1) {
- height = SeenBuff.Get_Height() - y;
- }
- TacLeptonHeight = Pixel_To_Lepton(height);
- /*
- ** Adjust the tactical cell if it is now in an invalid position
- ** because of the changed dimensions.
- */
- int xx = Coord_X(TacticalCoord) - (MapCellX * CELL_LEPTON_W);
- int yy = Coord_Y(TacticalCoord) - (MapCellY * CELL_LEPTON_H);
- Confine_Rect(&xx, &yy, TacLeptonWidth, TacLeptonHeight, MapCellWidth * CELL_LEPTON_W, MapCellHeight * CELL_LEPTON_H);
- Set_Tactical_Position(XY_Coord(xx + (MapCellX * CELL_LEPTON_W), yy + (MapCellY * CELL_LEPTON_H)));
- TacPixelX = x;
- TacPixelY = y;
- WindowList[WINDOW_TACTICAL][WINDOWX] = x >> 3;
- WindowList[WINDOW_TACTICAL][WINDOWY] = y;
- WindowList[WINDOW_TACTICAL][WINDOWWIDTH] = width >> 3;
- WindowList[WINDOW_TACTICAL][WINDOWHEIGHT] = height;
- if (Window == WINDOW_TACTICAL) {
- Change_Window(0);
- Change_Window(Window);
- }
- IsToRedraw = true;
- Flag_To_Redraw(false);
- TacButton.X = TacPixelX;
- TacButton.Y = TacPixelY;
- TacButton.Width = Lepton_To_Pixel(TacLeptonWidth);
- TacButton.Height = Lepton_To_Pixel(TacLeptonHeight);
- #endif
- }
- /***********************************************************************************************
- * DisplayClass::Set_Cursor_Shape -- Changes the shape of the terrain square cursor. *
- * *
- * This routine is used to set up the terrain cursor according to the size of the object *
- * that is to be placed down. The terrain cursor looks like an arbitrary collection of *
- * hatched square overlays. Typical use is when placing buildings. *
- * *
- * INPUT: list -- A pointer to the list that contains offsets to the cells that are to *
- * be marked. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 06/03/1994 JLB : Created. *
- * 06/26/1995 JLB : Puts placement cursor into static buffer. *
- *=============================================================================================*/
- void DisplayClass::Set_Cursor_Shape(short const * list)
- {
- if (CursorSize) {
- Cursor_Mark(ZoneCell+ZoneOffset, false);
- }
- ZoneOffset = 0;
- if (list) {
- int w,h;
- static short _list[50];
- memcpy(_list, list, sizeof(_list));
- CursorSize = _list;
- Get_Occupy_Dimensions (w, h, CursorSize);
- ZoneOffset = -(((h/2)*MAP_CELL_W)+(w/2));
- Cursor_Mark(ZoneCell+ZoneOffset, true);
- } else {
- CursorSize = 0;
- }
- }
- /***********************************************************************************************
- * DisplayClass::Passes_Proximity_Check -- Determines if building placement is near friendly sq*
- * *
- * This routine is used by the building placement cursor logic to determine whether the *
- * at the current cursor position if the building would be adjacent to another friendly *
- * building. In cases where this is not true, then the building cannot be placed at all. *
- * This determination is returned by the function. *
- * *
- * INPUT: object -- The building object that the current placement system is examining. *
- * *
- * OUTPUT: bool; Can the pending building object be placed at the present cursor location *
- * checking only for proximity to friendly buildings? If this isn't for a *
- * building type object, then this routine always returns true. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 06/06/1994 JLB : Created. *
- * 06/07/1994 JLB : Handles concrete check. *
- *=============================================================================================*/
- bool DisplayClass::Passes_Proximity_Check(ObjectTypeClass const *object)
- {
- #ifdef USE_RA_AI
-
- return Passes_Proximity_Check(object, PendingHouse, CursorSize, ZoneCell + ZoneOffset);
- #else //USE_RA_AI // Replaced by more generic function from RA, for RA AI. ST - 7/24/2019 5:46PM
- short const *ptr;
- /*
- ** In editor mode, the proximity check always passes.
- */
- if (Debug_Map) {
- return(true);
- }
- if (!object || !CursorSize || object->What_Am_I() != RTTI_BUILDINGTYPE) {
- return(true);
- }
- /*
- ** Scan through all cells that the building foundation would cover. If any adjacent
- ** cells to these are of friendly persuasion, then consider the proximity check to
- ** have been a success.
- */
- ptr = CursorSize;
- while (*ptr != REFRESH_EOL) {
- CELL cell = ZoneCell + ZoneOffset + *ptr++;
- for (FacingType facing = FACING_N; facing < FACING_COUNT; facing++) {
- CELL newcell = Adjacent_Cell(cell, facing);
- if (!In_Radar(cell)) return(false);
- TechnoClass * base = (*this)[newcell].Cell_Techno();
- /*
- ** The special cell ownership flag allows building adjacent
- ** to friendly walls and bibs even though there is no official
- ** building located there.
- */
- if ((*this)[newcell].Owner == PendingHouse) {
- return(true);
- }
- if (base && base->What_Am_I() == RTTI_BUILDING && base->House->Class->House == PendingHouse) {
- return(true);
- }
- }
- }
- return(false);
- #endif
- }
- #ifdef USE_RA_AI
- /*
- ** Additional version of Passes_Proximity_Check, inspired by RA implementation. Needed for RA AI. ST - 7/24/2019 5:42PM
- */
- /***********************************************************************************************
- * DisplayClass::Passes_Proximity_Check -- Determines if building placement is near friendly sq*
- * *
- * This routine is used by the building placement cursor logic to determine whether the *
- * at the current cursor position if the building would be adjacent to another friendly *
- * building. In cases where this is not true, then the building cannot be placed at all. *
- * This determination is returned by the function. *
- * *
- * INPUT: object -- The building object that the current placement system is examining. *
- * *
- * house -- The house to base the proximity check upon. Typically this is the *
- * player's house, but in multiplay, the computer needs to check for *
- * proximity as well. *
- * *
- * list -- Pointer to the building's offset list. *
- * *
- * trycell -- The cell to base the offset list on. *
- * *
- * OUTPUT: bool; Can the pending building object be placed at the present cursor location *
- * checking only for proximity to friendly buildings? If this isn't for a *
- * building type object, then this routine always returns true. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 06/06/1994 JLB : Created. *
- * 06/07/1994 JLB : Handles concrete check. *
- * 10/11/1994 BWG : Added IsProximate check for ore refineries *
- *=============================================================================================*/
- bool DisplayClass::Passes_Proximity_Check(ObjectTypeClass const * object, HousesType house, short const * list, CELL trycell) const
- {
- short const *ptr;
- /*
- ** In editor mode, the proximity check always passes.
- */
- if (Debug_Map) {
- return(true);
- }
- if (!object || object->What_Am_I() != RTTI_BUILDINGTYPE) {
- return(true);
- }
- /*
- ** Scan through all cells that the building foundation would cover. If any adjacent
- ** cells to these are of friendly persuasion, then consider the proximity check to
- ** have been a success.
- */
- ptr = list;
- while (*ptr != REFRESH_EOL) {
- CELL cell = trycell + *ptr++;
- for (FacingType facing = FACING_N; facing < FACING_COUNT; facing++) {
- CELL newcell = Adjacent_Cell(cell, facing);
- if (!In_Radar(cell)) return(false);
- TechnoClass * base = (*this)[newcell].Cell_Techno();
- /*
- ** The special cell ownership flag allows building adjacent
- ** to friendly walls and bibs even though there is no official
- ** building located there.
- */
- if ((*this)[newcell].Owner == house) {
- return(true);
- }
- if (base && base->What_Am_I() == RTTI_BUILDING && base->House->Class->House == house) {
- return(true);
- }
- }
- }
- return(false);
- }
- #endif //USE_RA_AI
- /***********************************************************************************************
- * DisplayClass::Set_Cursor_Pos -- Controls the display and animation of the tac cursor. *
- * *
- * This routine controls the location, display, and animation of the *
- * tactical map cursor. *
- * *
- * INPUT: pos -- Position to move the cursor do. If -1 is passed then *
- * the cursor will just be hidden. If the position *
- * passed is the same as the last position passed in, *
- * then animation could occur (based on timers). *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 05/22/1991 JLB : Created. *
- * 06/02/1994 JLB : Converted to member function. *
- * 06/08/1994 JLB : If position is -1, then follow mouse. *
- * 02/28/1995 JLB : Forces placement cursor to fit on map. *
- *=============================================================================================*/
- CELL DisplayClass::Set_Cursor_Pos(CELL pos)
- {
- CELL prevpos; // Last position of cursor (for jump-back reasons).
- /*
- ** Follow the mouse position if no cell number is provided.
- */
- if (pos == -1) {
- pos = Click_Cell_Calc(Get_Mouse_X(), Get_Mouse_Y());
- }
- if (!CursorSize) {
- prevpos = ZoneCell;
- ZoneCell = pos;
- return(prevpos);
- }
- /*
- ** Adjusts the position so that the placement cursor is never partway off the
- ** tactical map.
- */
- int w,h;
- Get_Occupy_Dimensions (w, h, CursorSize);
- int x = Cell_X(pos + ZoneOffset);
- int y = Cell_Y(pos + ZoneOffset);
- if (x < Coord_XCell(TacticalCoord)) x = Coord_XCell(TacticalCoord);
- // if (x < TacMapX) x = TacMapX;
- if (y < Coord_YCell(TacticalCoord)) y = Coord_YCell(TacticalCoord);
- // if (y < TacMapY) y = TacMapY;
- if (x+w >= Coord_XCell(TacticalCoord) + Lepton_To_Cell(TacLeptonWidth)) x = Coord_XCell(TacticalCoord)+Lepton_To_Cell(TacLeptonWidth)-w;
- // if (x+w >= TacMapX+TacWidth) x = TacMapX+TacWidth-w;
- if (y+h >= Coord_YCell(TacticalCoord) + Lepton_To_Cell(TacLeptonHeight)) x = Coord_YCell(TacticalCoord)+Lepton_To_Cell(TacLeptonHeight)-h;
- // if (y+h >= TacMapY+TacHeight) y = TacMapY+TacHeight-h;
- pos = XY_Cell(x, y) - ZoneOffset;
- /*
- ** This checks to see if NO animation or drawing is to occur and, if so,
- ** exits.
- */
- if (pos == ZoneCell) return(pos);
- prevpos = ZoneCell;
- /*
- ** If the cursor is visible, then handle the graphic update.
- ** Otherwise, just update the global position of the cursor.
- */
- if (CursorSize) {
- /*
- ** Erase the old cursor (if it exists) AND the cursor is moving.
- */
- if (pos != ZoneCell && ZoneCell != -1) {
- Cursor_Mark(ZoneCell+ZoneOffset, false);
- }
- /*
- ** Render the cursor (could just be animation).
- */
- if (pos != -1) {
- Cursor_Mark(pos+ZoneOffset, true);
- }
- }
- ZoneCell = pos;
- ProximityCheck = Passes_Proximity_Check(PendingObject);
- return(prevpos);
- }
- /***********************************************************************************************
- * DisplayClass::Get_Occupy_Dimensions -- computes width & height of the given occupy list *
- * *
- * INPUT: *
- * w ptr to fill in with height *
- * h ptr to fill in with width *
- * *
- * OUTPUT: *
- * none. *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 03/31/1995 BRR : Created. *
- *=============================================================================================*/
- void DisplayClass::Get_Occupy_Dimensions(int & w, int & h, short const *list)
- {
- int min_x = MAP_CELL_W;
- int max_x = -MAP_CELL_W;
- int min_y = MAP_CELL_H;
- int max_y = -MAP_CELL_H;
- int x,y;
- w = 0;
- h = 0;
- if (!list) {
- /*
- ** Loop through all cell offsets, accumulating max & min x- & y-coords
- */
- while (*list != REFRESH_EOL) {
- /*
- ** Compute x & y coords of the current cell offset. We can't use Cell_X()
- ** & Cell_Y(), because they use shifts to compute the values, and if the
- ** offset is negative we'll get a bogus coordinate!
- */
- x = (*list) % MAP_CELL_W;
- y = (*list) / MAP_CELL_H;
- max_x = MAX(max_x, x);
- min_x = MIN(min_x, x);
- max_y = MAX(max_y, y);
- min_y = MIN(min_y, y);
- list++;
- }
- w = MAX(1, max_x - min_x + 1);
- h = MAX(1, max_y - min_y + 1);
- }
- }
- /***********************************************************************************************
- * DisplayClass::Cursor_Mark -- Set or resets the cursor display flag bits. *
- * *
- * This routine will clear or set the cursor display bits on the map. *
- * If the bit is set, then the cursor will be rendered on that map *
- * icon. *
- * *
- * INPUT: pos -- Position of the upper left corner of the cursor. *
- * *
- * on -- Should the bit be turned on? *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: Be sure that every call to set the bits is matched by a *
- * corresponding call to clear the bits. *
- * *
- * HISTORY: *
- * 09/04/1991 JLB : Created. *
- * 06/02/1994 JLB : Converted to member function. *
- *=============================================================================================*/
- void DisplayClass::Cursor_Mark(CELL pos, bool on)
- {
- CELL const *ptr;
- CellClass *cellptr;
- if ((unsigned)pos >= MAP_CELL_TOTAL) return;
- /*
- ** For every cell in the CursorSize list, invoke its Redraw_Objects and
- ** toggle its IsCursorHere flag
- */
- ptr = CursorSize;
- while (*ptr != REFRESH_EOL) {
- CELL cell = pos + *ptr++;
- if (In_Radar(cell)) {
- cellptr = &(*this)[cell];
- cellptr->Redraw_Objects();
- if (on) {
- cellptr->IsCursorHere = true;
- } else {
- cellptr->IsCursorHere = false;
- }
- }
- }
- /*
- ** For every cell in the PendingObjectPtr's Overlap_List, invoke its
- ** Redraw_Objects routine.
- */
- if (PendingObjectPtr) {
- ptr = PendingObjectPtr->Overlap_List();
- while (*ptr != REFRESH_EOL) {
- CELL cell = pos + *ptr++;
- if (In_Radar(cell)) {
- cellptr = &(*this)[cell];
- cellptr->Redraw_Objects();
- }
- }
- }
- }
- /***********************************************************************************************
- * DisplayClass::AI -- Handles the maintenance tasks for the map display. *
- * *
- * This routine is called once per game display frame (15 times per second). It handles *
- * the mouse shape tracking and map scrolling as necessary. *
- * *
- * INPUT: input -- The next key just fetched from the input queue. *
- * *
- * x,y -- Mouse coordinates. *
- * *
- * OUTPUT: Modifies the input code if necessary. When the input code is consumed, it gets *
- * set to 0. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 06/01/1994 JLB : Created. *
- * 06/02/1994 JLB : Filters mouse click input. *
- * 06/07/1994 JLB : Fixed so template click will behave right. *
- * 10/14/1994 JLB : Changing cursor shape over target. *
- * 12/31/1994 JLB : Takes mouse coordinates as parameters. *
- * 06/27/1995 JLB : Breaks out of rubber band mode if mouse leaves map. *
- *=============================================================================================*/
- void DisplayClass::AI(KeyNumType & input, int x, int y)
- {
- if (
- IsRubberBand &&
- (Get_Mouse_X() < TacPixelX ||
- Get_Mouse_Y() < TacPixelY ||
- Get_Mouse_X() >= (TacPixelX + Lepton_To_Pixel(TacLeptonWidth)) ||
- Get_Mouse_Y() >= (TacPixelY + Lepton_To_Pixel(TacLeptonHeight)))) {
- Mouse_Left_Release(-1, Get_Mouse_X(), Get_Mouse_Y(), NULL, ACTION_NONE);
- }
- MapClass::AI(input, x, y);
- }
- /***********************************************************************************************
- * DisplayClass::Submit -- Adds a game object to the map rendering system. *
- * *
- * This routine is used to add an arbitrary (but tangible) game object to the map. It will *
- * be rendered (made visible) once it is submitted to this function. This function builds *
- * the list of game objects that get rendered each frame as necessary. It is possible to *
- * submit the game object to different rendering layers. All objects in a layer get drawn *
- * at the same time. Using this layer method it becomes possible to have objects "below" *
- * other objects. *
- * *
- * INPUT: object -- Pointer to the object to add. *
- * *
- * layer -- The layer to add the object to. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 05/31/1994 JLB : Created. *
- * 05/31/1994 JLB : Improved layer system. *
- * 05/31/1994 JLB : Sorts object position if this is for the ground layer. *
- *=============================================================================================*/
- void DisplayClass::Submit(ObjectClass const * object, LayerType layer)
- {
- if (object) {
- Layer[layer].Submit(object, (layer == LAYER_GROUND));
- }
- }
- /***********************************************************************************************
- * DisplayClass::Remove -- Removes a game object from the rendering system. *
- * *
- * Every object that is to disappear from the map must be removed from the rendering *
- * system. *
- * *
- * INPUT: object -- The object to remove. *
- * *
- * layer -- The layer to remove it from. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 05/31/1994 JLB : Created. *
- * 05/31/1994 JLB : Improved layer system. *
- *=============================================================================================*/
- void DisplayClass::Remove(ObjectClass const * object, LayerType layer)
- {
- if (object) {
- Layer[layer].Delete((ObjectClass *)object);
- }
- }
- /***********************************************************************************************
- * DisplayClass::Click_Cell_Calc -- Determines cell from screen X & Y. *
- * *
- * This routine is used to determine the cell that is located at the *
- * screen pixel coordinates given. Typical use is when the player *
- * clicks with the mouse on the tactical map. *
- * *
- * INPUT: x,y -- Screen pixel coordinates. *
- * *
- * OUTPUT: Returns with cell that is under the coordinates specified. *
- * If the coordinate specified is outside of the tactical *
- * map, then -1 is returned. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 05/27/1994 JLB : Created. *
- *=============================================================================================*/
- CELL DisplayClass::Click_Cell_Calc(int x, int y)
- {
- x -= TacPixelX;
- x = Pixel_To_Lepton(x);
- y -= TacPixelY;
- y = Pixel_To_Lepton(y);
- // Possibly ignore the view constraints if we aren't using the internal renderer. ST - 4/17/2019 9:06AM
- //if (x < TacLeptonWidth && y < TacLeptonHeight) {
- if (IgnoreViewConstraints || (x < TacLeptonWidth && y < TacLeptonHeight)) {
- COORDINATE tcoord = XY_Coord(Pixel_To_Lepton(Lepton_To_Pixel(Coord_X(TacticalCoord))), Pixel_To_Lepton(Lepton_To_Pixel(Coord_Y(TacticalCoord))));
- return(Coord_Cell(Coord_Add(tcoord, XY_Coord(x, y))));
- }
- return(-1);
- }
- /***********************************************************************************************
- * DisplayClass::Read_INI -- Reads map control data from INI file. *
- * *
- * This routine is used to read the map control data from the INI *
- * file. *
- * *
- * INPUT: buffer -- Pointer to the loaded INI file data. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: The TriggerClass INI data must have been read before calling this function. *
- * *
- * HISTORY: *
- * 05/27/1994 JLB : Created. *
- *=============================================================================================*/
- void DisplayClass::Read_INI(char *buffer)
- {
- char name[16];
- int len; // Length of data in buffer.
- char *tbuffer; // Accumulation buffer of Trigger names.
- char *trigsection = "CellTriggers";
- char buf[20]; // trigger name for a cell
- int cell;
- int i;
- /*
- ** Read the map dimensions.
- */
- Set_Map_Dimensions(WWGetPrivateProfileInt("MAP", "X", 1, buffer),
- WWGetPrivateProfileInt("MAP", "Y", 1, buffer),
- WWGetPrivateProfileInt("MAP", "Width", MAP_CELL_W-2, buffer),
- WWGetPrivateProfileInt("MAP", "Height", MAP_CELL_H-2, buffer));
- /*
- ** The theater is determined at this point. There is specific data that
- ** is custom to this data. Load the custom data (as it related to terrain)
- ** at this point.
- */
- WWGetPrivateProfileString("MAP", "Theater", Theaters[THEATER_DESERT].Name, name, 13, buffer);
- Theater = Theater_From_Name(name);
- if (Theater == THEATER_NONE) {
- Theater = THEATER_DESERT;
- }
- /*
- ** Remove any old theater specific uncompressed shapes
- */
- if (Theater != LastTheater){
- Reset_Theater_Shapes();
- }
- /*
- ** Now that the theater is known, init the entire map hierarchy
- */
- Init(Theater);
- /*
- ** Special initializations occur when the theater is known.
- */
- TerrainTypeClass::Init(Theater);
- TemplateTypeClass::Init(Theater);
- OverlayTypeClass::Init(Theater);
- UnitTypeClass::Init(Theater);
- InfantryTypeClass::Init(Theater);
- BuildingTypeClass::Init(Theater);
- BulletTypeClass::Init(Theater);
- AnimTypeClass::Init(Theater);
- AircraftTypeClass::Init(Theater);
- SmudgeTypeClass::Init(Theater);
- LastTheater = Theater;
- /*
- ** Read the Waypoint entries.
- */
- for (i = 0; i < WAYPT_COUNT; i++) {
- sprintf(buf,"%d",i);
- Waypoint[i] = WWGetPrivateProfileInt ("Waypoints",buf,-1,buffer);
- if (Waypoint[i] != -1) {
- (*this)[Waypoint[i]].IsWaypoint = 1;
- }
- }
- /*
- ** Set the starting position (do this after Init(), which clears the cells'
- ** IsWaypoint flags).
- */
- if (Waypoint[WAYPT_HOME] == -1) {
- Waypoint[WAYPT_HOME] = XY_Cell(MapCellX, MapCellY);
- }
- Set_Tactical_Position(Cell_Coord(Waypoint[WAYPT_HOME])&0xFF00FF00L);
- Views[0] = Views[1] = Views[2] = Views[3] = Waypoint[WAYPT_HOME];
- /*
- ** Read the cell trigger names, and assign TriggerClass pointers
- */
- len = strlen(buffer) + 2; // len is the length of the INI data
- tbuffer = buffer + len; // tbuffer is after the INI data
- /*
- ** Read all entry names into 'tbuffer'.
- */
- WWGetPrivateProfileString(trigsection, NULL, NULL, tbuffer, ShapeBufferSize-len, buffer);
- /*
- ** Loop through all CellTrigger entries.
- */
- while (*tbuffer != '\0') {
- /*
- ** Get a cell trigger assignment.
- */
- WWGetPrivateProfileString(trigsection, tbuffer, NULL, buf, sizeof(buf) - 1, buffer);
- /*
- ** Get cell # from entry name.
- */
- cell = atoi(tbuffer);
- if (cell > 0 && cell < MAP_CELL_TOTAL && !(*this)[cell].IsTrigger) {
- /*
- ** Assign trigger pointer using trigger name.
- */
- CellTriggers[cell] = TriggerClass::As_Pointer(buf);
- if (CellTriggers[cell]) {
- (*this)[cell].IsTrigger = 1;
- if (CellTriggers[cell]) {
- CellTriggers[cell]->AttachCount++;
- }
- }
- }
- /*
- ** Step to next entry name.
- */
- tbuffer += strlen(tbuffer) + 1;
- }
- }
- /***********************************************************************************************
- * DisplayClass::Write_INI -- Writes map data into INI file. *
- * *
- * This routine is used to write the map control data into the INI *
- * file. The scenario editor uses this when creating the scenario *
- * startup file. *
- * *
- * INPUT: buffer -- Pointer to INI file data. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 05/27/1994 JLB : Created. *
- *=============================================================================================*/
- void DisplayClass::Write_INI(char *buffer)
- {
- char entry[20];
- /*
- ** Save the map parameters.
- */
- WWWritePrivateProfileString("MAP", "Theater", Theaters[Theater].Name, buffer);
- WWWritePrivateProfileInt("MAP", "X", MapCellX, buffer);
- WWWritePrivateProfileInt("MAP", "Y", MapCellY, buffer);
- WWWritePrivateProfileInt("MAP", "Width", MapCellWidth, buffer);
- WWWritePrivateProfileInt("MAP", "Height", MapCellHeight, buffer);
- /*
- ** Save the Waypoint entries.
- */
- for (int i = 0; i < WAYPT_COUNT; i++) {
- sprintf(entry,"%d",i);
- WWWritePrivateProfileInt ("Waypoints",entry,Waypoint[i],buffer);
- }
- /*
- ** Erase the CellTriggers section.
- */
- WWWritePrivateProfileString("CellTriggers",NULL,NULL,buffer);
- /*
- ** Save the cell's triggers.
- */
- for (CELL cell = 0; cell < MAP_CELL_TOTAL; cell++) {
- if ((*this)[cell].IsTrigger) {
- /*
- ** Get cell trigger pointer.
- */
- TriggerClass const * trig = CellTriggers[cell];
- /*
- ** Generate entry name.
- */
- sprintf(entry,"%d",cell);
- /*
- ** Save entry.
- */
- WWWritePrivateProfileString("CellTriggers", entry, trig->Get_Name(), buffer);
- }
- }
- }
- /***********************************************************************************************
- * DisplayClass::Scroll_Map -- Scroll the tactical map in desired direction. *
- * *
- * This routine is used to scroll the tactical map view in the desired *
- * direction. It can also be used to determine if scrolling would be *
- * legal without actually performing any scrolling action. *
- * *
- * INPUT: facing -- The direction to scroll the tactical map. *
- * *
- * distance -- The distance in leptons to scroll the map. *
- * *
- * really -- Should the map actually be scrolled? If false, *
- * then only the legality of a scroll is checked. *
- * *
- * OUTPUT: bool; Would scrolling in the desired direction be possible? *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 10/07/1992 JLB : Created. *
- * 05/20/1994 JLB : Converted to member function. *
- * 08/09/1995 JLB : Added distance parameter. *
- * 08/10/1995 JLB : Any direction scrolling. *
- *=============================================================================================*/
- bool DisplayClass::Scroll_Map(DirType facing, int & distance, bool really)
- {
- /*
- ** If the distance is invalid then no further checking is required. Bail
- ** with a no-can-do flag.
- */
- if (distance == 0) return(false);
- FacingType crude = Dir_Facing(facing);
- if (Coord_X(TacticalCoord) == Cell_To_Lepton(MapCellX) && crude != FACING_W) {
- if (crude == FACING_SW) facing = DIR_S;
- if (crude == FACING_NW) facing = DIR_N;
- }
- if (Coord_Y(TacticalCoord) == Cell_To_Lepton(MapCellY) && crude != FACING_N) {
- if (crude == FACING_NW) facing = DIR_W;
- if (crude == FACING_NE) facing = DIR_E;
- }
- if (Coord_X(TacticalCoord) + TacLeptonWidth == Cell_To_Lepton(MapCellX+MapCellWidth) && crude != FACING_E) {
- if (crude == FACING_NE) facing = DIR_N;
- if (crude == FACING_SE) facing = DIR_S;
- }
- if (Coord_Y(TacticalCoord) + TacLeptonHeight == Cell_To_Lepton(MapCellY+MapCellHeight) && crude != FACING_S) {
- if (crude == FACING_SE) facing = DIR_E;
- if (crude == FACING_SW) facing = DIR_W;
- }
- /*
- ** Determine the coordinate that it wants to scroll to.
- */
- COORDINATE coord = Coord_Move(TacticalCoord, facing, distance);
- /*
- ** Clip the new coordinate to the edges of the game world.
- */
- int xx = Coord_X(coord) - Cell_To_Lepton(MapCellX);
- int yy = Coord_Y(coord) - Cell_To_Lepton(MapCellY);
- bool shifted = Confine_Rect(&xx, &yy, TacLeptonWidth, TacLeptonHeight, Cell_To_Lepton(MapCellWidth), Cell_To_Lepton(MapCellHeight));
- if (xx < 0) {
- xx = 0;
- shifted = true;
- }
- if (yy < 0) {
- yy = 0;
- shifted = true;
- }
- coord = XY_Coord(xx + Cell_To_Lepton(MapCellX), yy + Cell_To_Lepton(MapCellY));
- /*
- ** If the desired scroll was bound by the edge of the map, then adjust the distance to more accurately
- ** reflect the actual distance moved.
- */
- if (shifted) {
- distance = Distance(TacticalCoord, coord);
- }
- /*
- ** If the new coordinate is the same as the old, then no scrolling would occur.
- */
- if (!distance || coord == TacticalCoord) return(false);
- /*
- ** Since the new coordinate is different than the old one, possibly adjust the real
- ** tactical map accordingly.
- */
- if (really) {
- Set_Tactical_Position(coord);
- IsToRedraw = true;
- Flag_To_Redraw(false);
- }
- return(true);
- }
- /***********************************************************************************************
- * DisplayClass::Refresh_Cells -- Redraws all cells in list. *
- * *
- * This routine is used to flag all cells in the specified list for *
- * redrawing. *
- * *
- * INPUT: cell -- The origin cell that the list is offset from. *
- * *
- * list -- Pointer to a list of offsets from the origin cell. *
- * Each cell so specified is flagged for redraw. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: This routine is rather slow (by definition). *
- * *
- * HISTORY: *
- * 05/14/1994 JLB : Created. *
- * 08/01/1994 JLB : Simplified. *
- *=============================================================================================*/
- void DisplayClass::Refresh_Cells(CELL cell, short const *list)
- {
- if (*list == REFRESH_SIDEBAR) {
- list++;
- }
- while (*list != REFRESH_EOL) {
- CELL newcell = cell + *list++;
- if (In_Radar(newcell)) {
- (*this)[newcell].Redraw_Objects();
- }
- }
- }
- /***********************************************************************************************
- * DisplayClass::Cell_Shadow -- Determine what shadow icon to use for the cell. *
- * *
- * This routine will examine the specified cell and adjacent cells to *
- * determine what shadow icon to use. *
- * *
- * INPUT: cell -- The cell to examine. *
- * *
- * OUTPUT: Returns with the shadow icon to use. -2= all black. *
- * -1= map cell. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 03/01/1994 JLB : Created. *
- * 04/04/1994 JLB : Revamped for new shadow icon method. *
- * 04/30/1994 JLB : Converted to member function. *
- * 03/06/2019 ST : Added house parameter so we can do this per player *
- *=============================================================================================*/
- int DisplayClass::Cell_Shadow(CELL cell, HouseClass *house)
- {
- if (house == NULL) {
- return -1;
- }
- int index;
- int value = -1;
- CellClass *cellptr;
- static char const CardShadow[16] = {-2,0,1,2,3,-1,4,-1,5,6,-1,-1,7,-1,-1,-1};
- static char const DiagShadow[16] = {-2,8,9,-1,10,-1,-1,-1,11,-1,-1,-1,-1,-1,-1,-1};
- /*
- ** Don't map cells that are at the edges. This solves
- ** problem of accessing cells off the bounds of map and into
- ** who-knows-what memory.
- */
- if ((unsigned)(Cell_X(cell)-1) >= MAP_CELL_W-2) return(-2);
- if ((unsigned)(Cell_Y(cell)-1) >= MAP_CELL_H-2) return(-2); // Changed > to >= per Red Alert to fix out of bounds crash. ST - 3/25/2020 11:02PM
- cellptr = &(*this)[cell];
- if (!cellptr->Is_Mapped(house)) {
- /*
- ** Check the cardinal directions first. This will either result
- ** in a solution or the flag to check the diagonals.
- */
- index = 0;
- cellptr--;
- if (cellptr->Is_Mapped(house)) index |= 0x08;
- cellptr += MAP_CELL_W+1;
- if (cellptr->Is_Mapped(house)) index |= 0x04;
- cellptr -= MAP_CELL_W-1;
- if (cellptr->Is_Mapped(house)) index |= 0x02;
- cellptr -= MAP_CELL_W+1;
- if (cellptr->Is_Mapped(house)) index |= 0x01;
- value = CardShadow[index];
- /*
- ** The diagonals must be checked, since the cardinal directions
- ** did not yield a valid result.
- */
- if (value == -2) {
- index = 0;
- cellptr--;
- if (cellptr->Is_Mapped(house)) index |= 0x08;
- cellptr += MAP_CELL_W*2;
- if (cellptr->Is_Mapped(house)) index |= 0x04;
- cellptr += 2;
- if (cellptr->Is_Mapped(house)) index |= 0x02;
- cellptr -= MAP_CELL_W*2;
- if (cellptr->Is_Mapped(house)) index |= 0x01;
- value = DiagShadow[index];
- }
- /*
- ** Randomizer should go here. Add sets in multiples of 12.
- */
- }
- return(value);
- }
- #if (0)
- /***********************************************************************************************
- * DisplayClass::Cell_Shadow -- Determine what shadow icon to use for the cell. *
- * *
- * This routine will examine the specified cell and adjacent cells to *
- * determine what shadow icon to use. *
- * *
- * INPUT: cell -- The cell to examine. *
- * *
- * OUTPUT: Returns with the shadow icon to use. -2= all black. *
- * -1= map cell. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 03/01/1994 JLB : Created. *
- * 04/04/1994 JLB : Revamped for new shadow icon method. *
- * 04/30/1994 JLB : Converted to member function. *
- *=============================================================================================*/
- int DisplayClass::Cell_Shadow(CELL cell)
- {
- int index;
- int value = -1;
- CellClass *cellptr;
- static char const CardShadow[16] = {-2,0,1,2,3,-1,4,-1,5,6,-1,-1,7,-1,-1,-1};
- static char const DiagShadow[16] = {-2,8,9,-1,10,-1,-1,-1,11,-1,-1,-1,-1,-1,-1,-1};
- /*
- ** Don't map cells that are at the top or bottom edge. This solves
- ** problem of accessing cells off the top or bottom of the map and into
- ** who-knows-what memory.
- */
- if ((unsigned)(Cell_Y(cell)-1) > MAP_CELL_H-2) return(-2);
- cellptr = &(*this)[cell];
- if (!cellptr->IsMapped) {
- /*
- ** Check the cardinal directions first. This will either result
- ** in a solution or the flag to check the diagonals.
- */
- index = 0;
- cellptr--;
- if (cellptr->IsMapped) index |= 0x08;
- cellptr += MAP_CELL_W+1;
- if (cellptr->IsMapped) index |= 0x04;
- cellptr -= MAP_CELL_W-1;
- if (cellptr->IsMapped) index |= 0x02;
- cellptr -= MAP_CELL_W+1;
- if (cellptr->IsMapped) index |= 0x01;
- value = CardShadow[index];
- /*
- ** The diagonals must be checked, since the cardinal directions
- ** did not yield a valid result.
- */
- if (value == -2) {
- index = 0;
- cellptr--;
- if (cellptr->IsMapped) index |= 0x08;
- cellptr += MAP_CELL_W*2;
- if (cellptr->IsMapped) index |= 0x04;
- cellptr += 2;
- if (cellptr->IsMapped) index |= 0x02;
- cellptr -= MAP_CELL_W*2;
- if (cellptr->IsMapped) index |= 0x01;
- value = DiagShadow[index];
- }
- /*
- ** Randomizer should go here. Add sets in multiples of 12.
- */
- }
- return(value);
- }
- #endif
- /***********************************************************************************************
- * DisplayClass::Map_Cell -- Mark specified cell as having been mapped. *
- * *
- * This routine maps the specified cell. The cell must not already *
- * have been mapped and the mapping player must be the human. *
- * This routine will update any adjacent cell map icon as appropriate. *
- * *
- * INPUT: cell -- The cell to be mapped. *
- * *
- * house -- The player that is doing the mapping. *
- * *
- * OUTPUT: bool; Was action taken to map this cell? *
- * *
- * WARNINGS: none. *
- * *
- * HISTORY: *
- * 08/05/1992 JLB : Created. *
- * 04/30/1994 JLB : Converted to member function. *
- * 05/24/1994 JLB : Takes pointer to HouseClass. *
- * 03/06/2019 ST : Use per-player mapping so we can track the shroud for all players *
- *=============================================================================================*/
- bool DisplayClass::Map_Cell(CELL cell, HouseClass * house, bool and_for_allies)
- {
- // It's OK to do this if the house isn't the local player. ST - 3/6/2019 11:06AM
- //if (house != PlayerPtr || cell >= (CELL)Size) return(false);
- if (house == NULL || cell >= (CELL)Size) return(false);
- if (!house->IsHuman) {
- if (!ShareAllyVisibility || !and_for_allies) {
- return false;
- }
- }
- /*
- ** Maybe also recurse to map for allies
- */
- if (ShareAllyVisibility && and_for_allies) {
- HousesType first_house = (GameToPlay == GAME_NORMAL) ? HOUSE_FIRST : HOUSE_MULTI1;
- for (HousesType house_type = first_house; house_type < HOUSE_COUNT; house_type++) {
- HouseClass *hptr = HouseClass::As_Pointer(house_type);
- if (hptr && hptr->IsActive) {
- if (hptr != house && house->Is_Ally(hptr)) {
- Map_Cell(cell, hptr, false);
- }
- }
- }
- }
-
- /*
- ** Don't bother remapping this cell if it is already mapped.
- */
- //if ((*this)[cell].IsMapped) {
- if ((*this)[cell].Is_Mapped(house)) { // Check by player. ST - 3/6/2019 10:28AM
- return(false);
- }
- /*
- ** Mark the cell as being mapped.
- */
- //(*this)[cell].IsMapped = true;
- //(*this)[cell].IsVisible = true;
- // Set by player. ST - 3/6/2019 10:29AM
- (*this)[cell].Set_Mapped(house);
- (*this)[cell].Set_Visible(house);
- (*this)[cell].Redraw_Objects();
- /*
- ** Check out all adjacent cells to see if they need
- ** to be mapped as well. This is necessary because of the
- ** "unique" method of showing shadowed cells. Many combinations
- ** are not allowed, and to fix this, just map the cells until
- ** all is ok.
- */
- int xx = Cell_X(cell);
- for (FacingType dir = FACING_FIRST; dir < FACING_COUNT; dir++) {
- int shadow;
- CELL c;
- int xdiff;
- c = Adjacent_Cell(cell, dir);
- /*
- ** Determine if the map edge has been wrapped. If so,
- ** then don't process the cell.
- */
- if ((unsigned)c >= MAP_CELL_TOTAL) continue;
- xdiff = Cell_X(c) - xx;
- xdiff = ABS(xdiff);
- if (xdiff > 1) continue;
- if (c != cell && !(*this)[c].Is_Mapped(house)) { // Check by player. ST - 3/6/2019 10:28AM
- shadow = Cell_Shadow(c, house);
- /*
- ** Either map the cell or mark it to be refreshed. It
- ** will probably change form if it isn't actually mapped.
- */
- if (shadow == -1) {
- Map_Cell(c, house, false);
- } else {
- if (shadow != -2) {
- //(*this)[c].IsVisible = true;
- (*this)[c].Set_Visible(house); // Set by player. ST - 3/6/2019 11:07AM
- (*this)[c].Redraw_Objects();
- }
- }
- }
- }
- TechnoClass * tech = (*this)[cell].Cell_Techno();
- if (tech) {
- tech->Revealed(house);
- }
- return(true);
- }
- /***********************************************************************************************
- * DisplayClass::Coord_To_Pixel -- Determines X and Y pixel coordinates. *
- * *
- * This is the routine that figures out the location on the screen for *
- * a specified coordinate. It is one of the fundamental routines *
- * necessary for rendering the game objects. It performs some quick *
- * tests to see if the coordinate is in a visible region and returns *
- * this check as a boolean value. *
- * *
- * INPUT: coord -- The coordinate to check. *
- * *
- * x,y -- Reference to the pixel coordinates that this *
- * coordinate would be when rendered. *
- * *
- * OUTPUT: bool; Is this coordinate in a visible portion of the map? *
- * *
- * WARNINGS: If the coordinate is not in a visible portion of the *
- * map, then this X and Y parameters are not set. *
- * *
- * HISTORY: *
- * 05/14/1994 JLB : Created. *
- * 12/15/1994 JLB : Converted to member function. *
- * 01/07/1995 JLB : Uses inline functions to extract coord components. *
- * 08/09/1995 JLB : Uses new coordinate system. *
- *=============================================================================================*/
- #define EDGE_ZONE (CELL_LEPTON_W*2)
- bool DisplayClass::Coord_To_Pixel(COORDINATE coord, int &x, int &y)
- {
- int xtac = Pixel_To_Lepton(Lepton_To_Pixel(Coord_X(TacticalCoord)));
- int xoff = Pixel_To_Lepton(Lepton_To_Pixel(Coord_X(coord)));
- xoff = (xoff + EDGE_ZONE) - xtac;
- int ytac = Pixel_To_Lepton(Lepton_To_Pixel(Coord_Y(TacticalCoord)));
- int yoff = Pixel_To_Lepton(Lepton_To_Pixel(Coord_Y(coord)));
- yoff = (yoff + EDGE_ZONE) - ytac;
- x = Lepton_To_Pixel(xoff) - CELL_PIXEL_W * 2;
- y = Lepton_To_Pixel(yoff) - CELL_PIXEL_H * 2;
- // Possibly ignore the view constraints if we aren't using the internal renderer. ST - 4/17/2019 9:06AM
- return(coord && (IgnoreViewConstraints || ((xoff <= TacLeptonWidth + EDGE_ZONE * 2) && (yoff <= TacLeptonHeight + EDGE_ZONE * 2))));
- }
- #if (0) // reference. ST - 4/17/2019 9:07AM
- bool DisplayClass::Coord_To_Pixel(COORDINATE coord, int &x, int &y)
- {
- if (coord) {
- int xtac = Pixel_To_Lepton(Lepton_To_Pixel(Coord_X(TacticalCoord)));
- int xoff = Pixel_To_Lepton(Lepton_To_Pixel(Coord_X(coord)));
- xoff = (xoff+EDGE_ZONE) - xtac;
- if (xoff <= TacLeptonWidth + EDGE_ZONE*2) {
- int ytac = Pixel_To_Lepton(Lepton_To_Pixel(Coord_Y(TacticalCoord)));
- int yoff = Pixel_To_Lepton(Lepton_To_Pixel(Coord_Y(coord)));
- yoff = (yoff+EDGE_ZONE) - ytac;
- if (yoff <= TacLeptonHeight + EDGE_ZONE*2) {
- x = Lepton_To_Pixel(xoff)-CELL_PIXEL_W*2;
- y = Lepton_To_Pixel(yoff)-CELL_PIXEL_H*2;
- return(true);
- }
- }
- }
- return(false);
- }
- #endif
- /***********************************************************************************************
- * DisplayClass::Push_Onto_TacMap -- Moves x & y coords to being on tactical map *
- * *
- * This routine expects a line to be drawn between SOURCE & DEST, so it pushes the coords to *
- * be within the region bounded by TacMapX,Y - + TacMapW,H. *
- * *
- * INPUT: source, dest -- References to the coordinates to check. *
- * *
- * *
- * OUTPUT: bool; Are these coordinates in a visible portion of the map? *
- * Returns true if the pushed source & dest are visible, but if neither are *
- * within the map, then it returns false. *
- * *
- * *
- * HISTORY: *
- * 03/27/1995 BWG : Created. *
- *=============================================================================================*/
- bool DisplayClass::Push_Onto_TacMap(COORDINATE &source, COORDINATE &dest)
- {
- if (!source || !dest) return(false);
- int x1 = Coord_X(source);
- int y1 = Coord_Y(source);
- int x2 = Coord_X(dest);
- int y2 = Coord_Y(dest);
- int left = Coord_X(TacticalCoord);
- int right = Coord_X(TacticalCoord) + TacLeptonWidth;
- int top = Coord_Y(TacticalCoord);
- int bottom = Coord_Y(TacticalCoord) + TacLeptonHeight;
- if (x1 < left && x2 < left) return(false);
- if (x1 > right && x2 > right) return(false);
- if (y1 < top && y2 < top) return(false);
- if (y1 > bottom && y2 > bottom) return(false);
- x1 = Bound(x1, left, right);
- x2 = Bound(x2, left, right);
- y1 = Bound(y1, top, bottom);
- y2 = Bound(y2, top, bottom);
- source = XY_Coord(x1, y1);
- dest = XY_Coord(x2, y2);
- return(true);
- }
- /***********************************************************************************************
- * DisplayClass::Cell_Object -- Determines what has been clicked on. *
- * *
- * This routine is used to determine what the player has clicked on. *
- * It is passed the cell that the click was on and it then examines *
- * the cell and returns with a pointer to the object that is there. *
- * *
- * INPUT: cell -- The cell that has been clicked upon. *
- * *
- * x,y -- Optional offsets from the upper left corner of the cell to be used in *
- * determining exactly which object in the cell is desired. *
- * *
- * OUTPUT: Returns with a pointer to the object that is "clickable" in *
- * the specified cell. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 05/14/1994 JLB : Created. *
- *=============================================================================================*/
- ObjectClass * DisplayClass::Cell_Object(CELL cell, int x, int y)
- {
- return(*this)[cell].Cell_Object(x, y);
- }
- /***********************************************************************************************
- * DisplayClass::Draw_It -- Draws the tactical map. *
- * *
- * This will draw the tactical map at the recorded position. This *
- * routine is used whenever the tactical map moves or needs to be *
- * completely redrawn. It will handle making the necessary adjustments *
- * to accomodate a moving cursor. *
- * *
- * INPUT: forced -- bool; force redraw of the entire display? *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 04/15/1991 JLB : Created. (benchmark = 292) *
- * 04/15/1991 JLB : Added _cell2meta[] reference array (206) *
- * 04/15/1991 JLB : Added actual map reference for terrain (207) *
- * 04/16/1991 JLB : _cell2meta converted to int (194) *
- * 04/16/1991 JLB : References actual CellIcon[] array (204) *
- * 04/16/1991 JLB : Cell size increased to 16 x 16 (167) *
- * 04/17/1991 JLB : Cell based tactical map rendering (165) *
- * 04/22/1991 JLB : Uses Draw_Stamp() for icon rendering (426) *
- * 04/22/1991 JLB : Draw_Stamp uses LogicPage now (276) *
- * 04/23/1991 JLB : Map active location cursor (334) *
- * 05/02/1991 JLB : Added smoothing and 3 icons sets (431) *
- * 05/22/1991 JLB : Broken into Draw_Map() and Refresh_Map(). *
- * 09/14/1991 JLB : Uses Refresh_Cell when new cells scroll onto display. *
- * 05/12/1992 JLB : Destination page support. *
- * 02/14/1994 JLB : Revamped. *
- * 05/01/1994 JLB : Converted to member function. *
- * 12/15/1994 JLB : Updated to work with display heirarchy. *
- * 12/24/1994 JLB : Examines redraw bit intelligently. *
- * 12/24/1994 JLB : Combined with old Refresh_Map() function. *
- * 01/10/1995 JLB : Rubber band drawing. *
- *=============================================================================================*/
- void DisplayClass::Draw_It(bool forced)
- {
- int x,y; // Working cell index values.
- MapClass::Draw_It(forced);
- if (IsToRedraw || forced) {
- IsToRedraw = false;
- /*
- ** In rubber band mode, mark all cells under the "rubber band" to be
- ** redrawn.
- */
- Refresh_Band();
- /*
- ** If the multiplayer message system is displaying one or more messages,
- ** flag all cells covered by the messages to redraw. This will prevent
- ** messages from smearing the map if it scrolls.
- */
- int num = Messages.Num_Messages();
- if (num) {
- CELL cell;
- for (cell = Coord_Cell(TacticalCoord); cell < Coord_Cell(TacticalCoord) + Lepton_To_Cell(TacLeptonWidth)+1; cell++) {
- (*this)[cell].Redraw_Objects();
- }
- for (cell = Coord_Cell(TacticalCoord) + MAP_CELL_W;
- cell < Coord_Cell(TacticalCoord) + MAP_CELL_W + Lepton_To_Cell(TacLeptonWidth)+1; cell++) {
- (*this)[cell].Redraw_Objects();
- }
- if (num > 1) {
- for (cell = Coord_Cell(TacticalCoord) + MAP_CELL_W*2;
- cell < Coord_Cell(TacticalCoord) + MAP_CELL_W*2 + Lepton_To_Cell(TacLeptonWidth)+1; cell++) {
- (*this)[cell].Redraw_Objects();
- }
- }
- if (num > 3) {
- for (cell = Coord_Cell(TacticalCoord) + MAP_CELL_W*3;
- cell < Coord_Cell(TacticalCoord) + MAP_CELL_W*3 + Lepton_To_Cell(TacLeptonWidth)+1; cell++) {
- (*this)[cell].Redraw_Objects();
- }
- }
- if (num > 4) {
- for (cell = Coord_Cell(TacticalCoord) + MAP_CELL_W*4;
- cell < Coord_Cell(TacticalCoord) + MAP_CELL_W*4 + Lepton_To_Cell(TacLeptonWidth)+1; cell++) {
- (*this)[cell].Redraw_Objects();
- }
- }
- }
- /*
- ** Check for a movement of the tactical map. If there has been some
- ** movement, then part (or all) of the icons must be redrawn.
- */
- if (Lepton_To_Pixel(Coord_X(DesiredTacticalCoord)) != Lepton_To_Pixel(Coord_X(TacticalCoord)) ||
- Lepton_To_Pixel(Coord_Y(DesiredTacticalCoord)) != Lepton_To_Pixel(Coord_Y(TacticalCoord))) {
- int xmod = Lepton_To_Pixel(Coord_X(DesiredTacticalCoord));
- int ymod = Lepton_To_Pixel(Coord_Y(DesiredTacticalCoord));
- int oldx = Lepton_To_Pixel(Coord_X(TacticalCoord))-xmod; // Old relative offset.
- int oldy = Lepton_To_Pixel(Coord_Y(TacticalCoord))-ymod;
- int oldw = Lepton_To_Pixel(TacLeptonWidth)-ABS(oldx); // Replicable width.
- int oldh = Lepton_To_Pixel(TacLeptonHeight)-ABS(oldy); // Replicable height.
- if (oldw < 1) forced = true;
- if (oldh < 1) forced = true;
- /*
- ** Work out which map edges need to be redrawn
- */
- BOOL redraw_right = (oldx < 0) ? TRUE : FALSE; //Right hand edge
- BOOL redraw_left = (oldx > 0) ? TRUE : FALSE; //Left hand edge
- BOOL redraw_bottom= (oldy < 0) ? TRUE : FALSE; //Bottom edge
- BOOL redraw_top = (oldy > 0) ? TRUE : FALSE; //Top edge
- //Colour_Debug(2);
- /*
- ** Blit any replicable block to avoid having to drawstamp.
- */
- CachedIconsDrawn=0;
- UnCachedIconsDrawn=0;
- if (!forced && (oldw != Lepton_To_Pixel(TacLeptonWidth) || oldh != Lepton_To_Pixel(TacLeptonHeight))) {
- Set_Cursor_Pos(-1);
- /*
- ** If hid page is in video memory then we may nned to blit from the seen page to
- ** avoid blitting an overlapped region.
- */
- if (HidPage.Get_IsDirectDraw() && !OverlappedVideoBlits){
- Hide_Mouse();
- SeenBuff.Blit(HidPage,
- ((oldx < 0) ? -oldx : 0) +TacPixelX,
- ((oldy < 0) ? -oldy : 0) +TacPixelY,
- ((oldx < 0) ? 0 : oldx) +TacPixelX,
- ((oldy < 0) ? 0 : oldy) +TacPixelY,
- oldw,
- oldh);
- Show_Mouse();
- }else{
- HidPage.Blit(HidPage,
- ((oldx < 0) ? -oldx : 0) +TacPixelX,
- ((oldy < 0) ? -oldy : 0) +TacPixelY,
- ((oldx < 0) ? 0 : oldx) +TacPixelX,
- ((oldy < 0) ? 0 : oldy) +TacPixelY,
- oldw,
- oldh);
- }
- } else {
- forced = true;
- }
- if (oldx < 0) oldx = 0;
- if (oldy < 0) oldy = 0;
- /*
- ** Record new map position for future reference.
- */
- ScenarioInit++;
- Set_Tactical_Position(DesiredTacticalCoord);
- ScenarioInit--;
- if (!forced) {
- /*
- **
- ** Set the 'redraw stamp' bit for any cells that could not be copied.
- **
- */
- int startx = -Lepton_To_Pixel(Coord_XLepton(TacticalCoord));
- int starty = -Lepton_To_Pixel(Coord_YLepton(TacticalCoord));
- oldw -= 24;
- oldh -= 24;
- if (abs(oldx) < 0x25 && abs(oldy) < 0x25){
- /*
- ** The width of the area we redraw depends on the scroll speed
- */
- int extra_x = (abs(oldx)>=16) ? 2 : 1;
- int extra_y = (abs(oldy)>=16) ? 2 : 1;
- /*
- ** Flag the cells across the top of the visible area if required
- */
- if (redraw_top){
- for (y = starty; y <= starty+CELL_PIXEL_H*extra_y; y += CELL_PIXEL_H) {
- for (x = startx; x <= Lepton_To_Pixel(TacLeptonWidth)+((CELL_PIXEL_W*2)); x += CELL_PIXEL_W) {
- CELL c = Click_Cell_Calc(Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1) + TacPixelX,
- Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1) + TacPixelY);
- if (c > 0) (*this)[c].Redraw_Objects(true);
- }
- }
- }
- /*
- ** Flag the cells across the bottom of the visible area if required
- */
- if (redraw_bottom){
- 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) {
- for (x = startx; x <= Lepton_To_Pixel(TacLeptonWidth)+((CELL_PIXEL_W*2)); x += CELL_PIXEL_W) {
- CELL c = Click_Cell_Calc(Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1) + TacPixelX,
- Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1) + TacPixelY);
- if (c > 0) (*this)[c].Redraw_Objects(true);
- }
- }
- }
- /*
- ** Flag the cells down the left of the visible area if required
- */
- if (redraw_left){
- for (x = startx; x <= startx + CELL_PIXEL_W*extra_x; x += CELL_PIXEL_W) {
- for (y = starty; y <= Lepton_To_Pixel(TacLeptonHeight)+((CELL_PIXEL_H*2)); y += CELL_PIXEL_H) {
- CELL c = Click_Cell_Calc(Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1) + TacPixelX,
- Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1) + TacPixelY);
- if (c > 0) (*this)[c].Redraw_Objects(true);
- }
- }
- }
- /*
- ** Flag the cells down the right of the visible area if required
- */
- if (redraw_right){
- 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) {
- for (y = starty; y <= Lepton_To_Pixel(TacLeptonHeight)+((CELL_PIXEL_H*2)); y += CELL_PIXEL_H) {
- CELL c = Click_Cell_Calc(Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1) + TacPixelX,
- Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1) + TacPixelY);
- if (c > 0) (*this)[c].Redraw_Objects(true);
- }
- }
- }
- }else{
- /*
- ** Set the 'redraw stamp' bit for any cells that could not be copied.
- */
- int startx = -Lepton_To_Pixel(Coord_XLepton(TacticalCoord));
- int starty = -Lepton_To_Pixel(Coord_YLepton(TacticalCoord));
- oldw -= 24;
- oldh -= 24;
- for (y = starty; y <= Lepton_To_Pixel(TacLeptonHeight)+((CELL_PIXEL_H*2)); y += CELL_PIXEL_H) {
- for (x = startx; x <= Lepton_To_Pixel(TacLeptonWidth)+((CELL_PIXEL_W*2)); x += CELL_PIXEL_W) {
- if (x <= oldx || x >= oldx+oldw || y <= oldy || y >= oldy+oldh) {
- CELL c = Click_Cell_Calc(Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1) + TacPixelX,
- Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1) + TacPixelY);
- if (c > 0) {
- (*this)[c].Redraw_Objects(true);
- }
- }
- }
- }
- }
- }
- } else {
- /*
- ** Set the tactical coordinate just in case the desired tactical has changed but
- ** not enough to result in any visible map change. This is likely to occur with very
- ** slow scroll rates.
- */
- ScenarioInit++;
- if (DesiredTacticalCoord != TacticalCoord) {
- Set_Tactical_Position(DesiredTacticalCoord);
- }
- ScenarioInit--;
- }
- /*
- ** If the entire tactical map is forced to be redrawn, then set all the redraw flags
- ** and let the normal processing take care of the rest.
- */
- if (forced) {
- CellRedraw.Set();
- }
- //Colour_Debug(3);
- /*
- ** The first order of business is to redraw all the underlying icons that are
- ** flagged to be redrawn.
- */
- //Redraw_Icons(CELL_BLIT_ONLY);
- Redraw_Icons(0);
- /*
- ** Once the icons are drawn, duplicate the bottom line of the screen into the phantom
- ** area one line below the screen. This causes the predator effect to work on any
- ** shape drawn at the bottom of the screen.
- */
- //Colour_Debug(4);
- #ifdef FIX_ME_LATER
- // HidPage.Blit(HidPage, 0, HidPage.Get_Height()-1, 0, HidPage.Get_Height(), HidPage.Get_Width(), 1, false);
- #endif //FIX_ME_LATER
- if (HidPage.Lock()){
- //Redraw_Icons(CELL_DRAW_ONLY);
- /*
- ** Redraw the game objects layer by layer. The layer drawing occurs on the ground layer
- ** first and then followed by all the layers in increasing altituded.
- */
- for (LayerType layer = LAYER_GROUND; layer < LAYER_COUNT; layer++) {
- for (int index = 0; index < Layer[layer].Count(); index++) {
- Layer[layer][index]->Render(forced);
- }
- }
- /*
- ** Finally, redraw the shadow overlay as necessary.
- */
- //Colour_Debug(5);
- Redraw_Shadow();
- }
- Redraw_Shadow_Rects();
- HidPage.Unlock();
- //Colour_Debug(8);
- /*
- ** Draw the rubber band over the top of it all.
- */
- if (IsRubberBand) {
- LogicPage->Draw_Rect(BandX+TacPixelX, BandY+TacPixelY, NewX+TacPixelX, NewY+TacPixelY, WHITE);
- }
- /*
- ** Clear the redraw flags so that normal redraw flag setting can resume.
- */
- CellRedraw.Reset();
- //Colour_Debug(0);
- #ifdef SCENARIO_EDITOR
- /*
- ** If we're placing an object (PendingObject is non-NULL), and that object
- ** is NOT an icon, smudge, or overlay, draw it here.
- ** Terrain, Buildings & Aircraft aren't drawn at the cell's center coord;
- ** they're drawn at the upper left coord, so I have to AND the coord value
- ** with 0xFF00FF00 to strip off the lepton coordinates, but leave the
- ** cell coordinates.
- */
- if (Debug_Map && PendingObjectPtr) {
- PendingObjectPtr->Coord = PendingObjectPtr->Class_Of().Coord_Fixup(Cell_Coord(ZoneCell + ZoneOffset));
- PendingObjectPtr->Render(true);
- }
- #endif
- }
- }
- /***********************************************************************************************
- * DisplayClass::Redraw_Icons -- Draws all terrain icons necessary. *
- * *
- * This routine will redraw all of the terrain icons that are flagged *
- * to be redrawn. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none. *
- * *
- * HISTORY: *
- * 02/14/1994 JLB : Created. *
- * 05/01/1994 JLB : Converted to member function. *
- * 06/20/1994 JLB : Uses cell drawing support function. *
- * 12/06/1994 JLB : Scans tactical view in separate row/colum loops *
- * 12/24/1994 JLB : Uses the cell bit flag array to determine what to redraw. *
- *=============================================================================================*/
- void DisplayClass::Redraw_Icons(int draw_flags)
- {
- IsShadowPresent = false;
- for (int y = -Coord_YLepton(TacticalCoord); y <= TacLeptonHeight; y += CELL_LEPTON_H) {
- for (int x = -Coord_XLepton(TacticalCoord); x <= TacLeptonWidth; x += CELL_LEPTON_W) {
- COORDINATE coord = Coord_Add(TacticalCoord, XY_Coord(x, y));
- CELL cell = Coord_Cell(coord);
- coord = Cell_Coord(cell) & 0xFF00FF00L;
- /*
- ** Only cells flagged to be redraw are examined.
- */
- if (In_View(cell) && Is_Cell_Flagged(cell)) {
- int xpixel;
- int ypixel;
- if (Coord_To_Pixel(coord, xpixel, ypixel)) {
- CellClass * cellptr = &(*this)[Coord_Cell(coord)];
- /*
- ** If there is a portion of the underlying icon that could be visible,
- ** then draw it. Also draw the cell if the shroud is off.
- */
- if (cellptr->Is_Visible(PlayerPtr) || Debug_Unshroud) { // Use PlayerPtr since we won't be rendering in MP. ST - 3/6/2019 2:49PM
- cellptr->Draw_It(xpixel, ypixel, draw_flags);
- }
- /*
- ** If any cell is not fully mapped, then flag it so that the shadow drawing
- ** process will occur. Only draw the shadow if Debug_Unshroud is false.
- */
- if (!cellptr->Is_Mapped(PlayerPtr) && !Debug_Unshroud) { // Use PlayerPtr since we won't be rendering in MP. ST - 3/6/2019 2:49PM
- IsShadowPresent = true;
- }
- }
- }
- }
- }
- }
- /***********************************************************************************************
- * DisplayClass::Redraw_Shadow -- Draw the shadow overlay. *
- * *
- * This routine is called after all other tactical map rendering takes place. It draws *
- * the shadow map over the tactical map. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 01/01/1995 JLB : Created. *
- * 08/06/1995 JLB : Clips the fill rect if necessary. *
- *=============================================================================================*/
- void DisplayClass::Redraw_Shadow(void)
- {
- if (IsShadowPresent) {
- for (int y = -Coord_YLepton(TacticalCoord); y <= TacLeptonHeight; y += CELL_LEPTON_H) {
- for (int x = -Coord_XLepton(TacticalCoord); x <= TacLeptonWidth; x += CELL_LEPTON_W) {
- COORDINATE coord = Coord_Add(TacticalCoord, XY_Coord(x, y));
- CELL cell = Coord_Cell(coord);
- coord = Cell_Coord(cell) & 0xFF00FF00;
- /*
- ** Only cells flagged to be redraw are examined.
- */
- if (In_View(cell) && Is_Cell_Flagged(cell)) {
- int xpixel;
- int ypixel;
- if (Coord_To_Pixel(coord, xpixel, ypixel)) {
- CellClass * cellptr = &(*this)[Coord_Cell(coord)];
- if (!cellptr->Is_Mapped(PlayerPtr)) { // Pass player pointer since we will only be rendering in single player mode. ST - 3/6/2019 1:36PM
- if (cellptr->Is_Visible(PlayerPtr)) { // Pass player pointer since we will only be rendering in single player mode. ST - 3/6/2019 1:36PM
- int shadow = Cell_Shadow(cell, PlayerPtr); // Pass player pointer since we will only be rendering in single player mode. ST - 3/6/2019 1:36PM
- if (shadow >= 0) {
- CC_Draw_Shape(ShadowShapes, shadow, xpixel, ypixel, WINDOW_TACTICAL, SHAPE_GHOST, NULL, ShadowTrans);
- }
- }
- }
- }
- }
- }
- }
- }
- }
- /***********************************************************************************************
- * DisplayClass::Redraw_Shadow -- Draw the shadow overlay. *
- * *
- * This routine is called after all other tactical map rendering takes place. It draws *
- * the shadow map over the tactical map. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 01/01/1995 JLB : Created. *
- * 08/06/1995 JLB : Clips the fill rect if necessary. *
- *=============================================================================================*/
- void DisplayClass::Redraw_Shadow_Rects(void)
- {
- if (IsShadowPresent) {
- for (int y = -Coord_YLepton(TacticalCoord); y <= TacLeptonHeight; y += CELL_LEPTON_H) {
- for (int x = -Coord_XLepton(TacticalCoord); x <= TacLeptonWidth; x += CELL_LEPTON_W) {
- COORDINATE coord = Coord_Add(TacticalCoord, XY_Coord(x, y));
- CELL cell = Coord_Cell(coord);
- coord = Cell_Coord(cell) & 0xFF00FF00;
- /*
- ** Only cells flagged to be redraw are examined.
- */
- if (In_View(cell) && Is_Cell_Flagged(cell)) {
- int xpixel;
- int ypixel;
- if (Coord_To_Pixel(coord, xpixel, ypixel)) {
- CellClass * cellptr = &(*this)[Coord_Cell(coord)];
- if (!cellptr->Is_Mapped(PlayerPtr)) { // Use PlayerPtr since we won't be rendering in MP. ST - 3/6/2019 2:49PM
- if (!cellptr->Is_Visible(PlayerPtr)) { // Use PlayerPtr since we won't be rendering in MP. ST - 3/6/2019 2:49PM
- int ww = CELL_PIXEL_W;
- int hh = CELL_PIXEL_H;
- if (Clip_Rect(&xpixel, &ypixel, &ww, &hh, Lepton_To_Pixel(TacLeptonWidth), Lepton_To_Pixel(TacLeptonHeight)) >= 0) {
- LogicPage->Fill_Rect(TacPixelX+xpixel, TacPixelY+ypixel, TacPixelX+xpixel+ww-1, TacPixelY+ypixel+hh-1, BLACK);
- }
- }
- }
- }
- }
- }
- }
- }
- }
- /***********************************************************************************************
- * DisplayClass::Next_Object -- Searches for next object on display. *
- * *
- * This utility routine is used to find the "next" object from the object specified. This *
- * is typically used when <TAB> is pressed and the current object shifts. *
- * *
- * INPUT: object -- The current object to base the "next" calculation off of. *
- * *
- * OUTPUT: Returns with a pointer to the next object. If there is no objects available, *
- * then NULL is returned. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 06/20/1994 JLB : Created. *
- *=============================================================================================*/
- ObjectClass * DisplayClass::Next_Object(ObjectClass * object)
- {
- ObjectClass * firstobj = 0;
- bool foundmatch = false;
- if (!object) {
- foundmatch = true;
- }
- for (unsigned uindex = 0; uindex < (unsigned)Layer[LAYER_GROUND].Count(); uindex++) {
- ObjectClass * obj = Layer[LAYER_GROUND][uindex];
- /*
- ** Verify that the object can be selected by and is owned by the player.
- */
- if (obj && obj->Is_Techno() && ((TechnoClass *)obj)->Is_Discovered_By_Player() && obj->Class_Of().IsSelectable && obj->Owner() == PlayerPtr->Class->House) {
- if (!firstobj) firstobj = obj;
- if (foundmatch) return(obj);
- if (object == obj) foundmatch = true;
- }
- }
- return(firstobj);
- }
- /***********************************************************************************************
- * DisplayClass::Prev_Object -- Searches for the previous object on the map. *
- * *
- * This routine will search for the previous object. Previous is defined as the one listed *
- * before the specified object in the ground layer. If there is no specified object, then *
- * the last object in the ground layer is returned. *
- * *
- * INPUT: object -- Pointer to the object that "previous" is to be defined from. *
- * *
- * OUTPUT: Returns with a pointer to the object previous to the specified one. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 08/24/1995 JLB : Created. *
- *=============================================================================================*/
- ObjectClass * DisplayClass::Prev_Object(ObjectClass * object)
- {
- ObjectClass * firstobj = 0;
- bool foundmatch = false;
- if (!object) {
- foundmatch = true;
- }
- for (int uindex = Layer[LAYER_GROUND].Count()-1; uindex >= 0; uindex--) {
- ObjectClass * obj = Layer[LAYER_GROUND][uindex];
- /*
- ** Verify that the object can be selected by and is owned by the player.
- */
- if (obj && obj->Is_Techno() && ((TechnoClass *)obj)->Is_Discovered_By_Player() && obj->Class_Of().IsSelectable && obj->Owner() == PlayerPtr->Class->House) {
- if (!firstobj) firstobj = obj;
- if (foundmatch) return(obj);
- if (object == obj) foundmatch = true;
- }
- }
- return(firstobj);
- }
- /***********************************************************************************************
- * DisplayClass::Pixel_To_Coord -- converts screen coord to COORDINATE *
- * *
- * INPUT: *
- * x,y pixel coordinates to convert *
- * *
- * OUTPUT: *
- * COORDINATE of pixel *
- * *
- * WARNINGS: *
- * none. *
- * *
- * HISTORY: *
- * 11/09/1994 BR : Created. *
- * 12/06/1994 JLB : Uses map dimension variables in display class. *
- * 12/10/1994 JLB : Uses union to speed building coordinate value. *
- *=============================================================================================*/
- COORDINATE DisplayClass::Pixel_To_Coord(int x, int y)
- {
- /*
- ** Normalize the pixel coorindates to be relative to the upper left corner
- ** of the tactical map. The coordinates are expressed in leptons.
- */
- x -= TacPixelX;
- x = Pixel_To_Lepton(x);
- y -= TacPixelY;
- y = Pixel_To_Lepton(y);
- /*
- ** If pixel coordinate is over the tactical map, then translate it into a coordinate
- ** value. If not, then just return with NULL.
- */
- // Possibly ignore the view constraints if we aren't using the internal renderer. ST - 4/17/2019 9:06AM
- //if (x < TacLeptonWidth && y < TacLeptonHeight) {
- if (IgnoreViewConstraints || (x < TacLeptonWidth && y < TacLeptonHeight)) {
- return(Coord_Add(TacticalCoord, XY_Coord(x, y)));
- }
- return(0);
- }
- /***********************************************************************************************
- * DisplayClass::Calculated_Cell -- Fetch a map cell based on specified method. *
- * *
- * Find a cell meeting the specified requirements. This function is *
- * used for scenario reinforcements. *
- * *
- * INPUT: dir -- Method of picking a map cell. *
- * *
- * house -- The house to base calculation on. *
- * *
- * OUTPUT: Returns with the calculated cell. If 0, then this indicates *
- * that no legal cell was found. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 10/07/1992 JLB : Created. *
- * 04/11/1994 JLB : Revamped. *
- * 05/18/1994 JLB : Converted to member function. *
- *=============================================================================================*/
- CELL DisplayClass::Calculated_Cell(SourceType dir, HousesType house)
- {
- CELL cell = 0; // Working cell number.
- while (cell == 0) {
- int x,y;
- int index;
- /*
- ** Select a candidate cell based on the desired method.
- */
- switch (dir) {
- /*
- ** Looks for the northern most straight path shipping lane and returns
- ** the cell of one of the ends.
- */
- case SOURCE_SHIPPING:
- for (y = 0; y < MapCellHeight; y++) {
- for (x = 0; x < MapCellWidth; x++) {
- if ((*this)[XY_Cell(MapCellX+x, MapCellY+y)].Land_Type() != LAND_WATER) break;
- }
- if (x == MapCellWidth) {
- return(XY_Cell(MapCellX+MapCellWidth, MapCellY+y));
- }
- }
- return(0);
- /*
- ** Select a map edge.
- */
- case SOURCE_NORTH:
- index = Random_Pick(1, MapCellWidth);
- for (x = 0; x < MapCellWidth; x++) {
- cell = XY_Cell(MapCellX+((x+index)%MapCellWidth), MapCellY-1);
- if ((*this)[cell].Is_Generally_Clear() && (*this)[cell+MAP_CELL_W].Is_Generally_Clear()) break;
- }
- if (x == MapCellWidth) return(0);
- break;
- case SOURCE_EAST:
- index = Random_Pick(1, MapCellHeight);
- for (y = 0; y < MapCellHeight; y++) {
- cell = XY_Cell(MapCellX+MapCellWidth, MapCellY+((y+index)%MapCellHeight));
- if ((*this)[cell].Is_Generally_Clear() && (*this)[cell-1].Is_Generally_Clear()) break;
- }
- if (y == MapCellHeight) return(0);
- break;
- case SOURCE_SOUTH:
- index = Random_Pick(1, MapCellWidth);
- for (x = 0; x < MapCellWidth; x++) {
- cell = XY_Cell(MapCellX+((x+index)%MapCellWidth), MapCellY+MapCellHeight);
- if ((*this)[cell].Is_Generally_Clear() && (*this)[cell-MAP_CELL_W].Is_Generally_Clear()) break;
- }
- if (x == MapCellWidth) return(0);
- break;
- case SOURCE_WEST:
- index = Random_Pick(1, MapCellHeight);
- for (y = 0; y < MapCellHeight; y++) {
- cell = XY_Cell(MapCellX-1, MapCellY+((y+index)%MapCellHeight));
- if ((*this)[cell].Is_Generally_Clear() && (*this)[cell+1].Is_Generally_Clear()) break;
- }
- if (y == MapCellHeight) return(0);
- break;
- /*
- ** Drop in at a random location.
- */
- case SOURCE_AIR:
- cell = Waypoint[WAYPT_REINF];
- if (cell < 1) {
- cell = Coord_Cell(TacticalCoord);
- return(cell);
- } else {
- if ((*this)[cell].Cell_Techno()) {
- for (int radius = 1; radius < 7; radius++) {
- CELL newcell = Coord_Cell(Coord_Scatter(Cell_Coord(cell), radius << 8, true));
- if (In_Radar(newcell) && !(*this)[newcell].Cell_Techno()) {
- cell = newcell;
- break;
- }
- }
- }
- }
- break;
- /*
- ** Dramatic entry point is somewhere on the visible screen as defined
- ** by the current tactical map position.
- */
- case SOURCE_VISIBLE:
- cell = XY_Cell(Coord_XCell(TacticalCoord)+Random_Pick(0, Lepton_To_Cell(TacLeptonWidth)-1), Coord_YCell(TacticalCoord)+Random_Pick(0, Lepton_To_Cell(TacLeptonHeight)-1));
- if (house == PlayerPtr->Class->House && !In_Radar(cell)) {
- cell = 0;
- }
- break;
- /*
- ** Drop off near friendly base or near a friendly unit or
- ** just randomly if all else fails.
- */
- case SOURCE_ENEMYBASE:
- case SOURCE_HOMEBASE:
- return(0);
- /*
- ** Find an unoccupied beach cell.
- */
- case SOURCE_BEACH: {
- CELL cells[MAP_CELL_W];
- CELL alternate[MAP_CELL_W];
- unsigned counter=0;
- for (x = 0; x < MapCellWidth; x++) {
- CELL newcell = 0;
- if ((*this)[XY_Cell(x + MapCellX, MapCellHeight + MapCellY)].Land_Type() != LAND_WATER) continue;
- if ((*this)[XY_Cell(x + MapCellX, MapCellHeight + MapCellY-1)].Land_Type() != LAND_WATER) continue;
- for (y = MapCellHeight; y >= 0; y--) {
- newcell = XY_Cell(x + MapCellX, y + MapCellY);
- if ((*this)[newcell].Cell_Techno()) {
- break;
- }
- if ((*this)[newcell].Land_Type() != LAND_WATER) {
- break;
- }
- }
- LandType land = (*this)[newcell].Land_Type();
- if (( land == LAND_BEACH || land == LAND_CLEAR || land == LAND_ROAD) &&
- !(*this)[newcell].Cell_Techno() &&
- !(*this)[newcell].Cell_Terrain() &&
- !(*this)[newcell-MAP_CELL_W].Cell_Techno() &&
- !(*this)[newcell-MAP_CELL_W].Cell_Terrain() &&
- !(*this)[newcell-(MAP_CELL_W*2)].Cell_Terrain() &&
- !(*this)[newcell-(MAP_CELL_W*2)].Cell_Techno()) {
- cells[counter++] = newcell;
- if (counter >= (sizeof(cells) / sizeof(cells[0]))) {
- break;
- }
- }
- }
- /*
- ** Fixup entry list so that it doesn't come close to blocking terrain or other
- ** units.
- */
- int counter2 = 0;
- for (int index = 1; index < (int)counter-1; index++) {
- if (Cell_X(cells[index-1])+1 == Cell_X(cells[index]) && Cell_X(cells[index+1])-1 == Cell_X(cells[index])) {
- alternate[counter2++] = cells[index];
- }
- }
- CELL cell = 0;
- if (counter2) {
- if (counter2 < 4) {
- cell = alternate[counter2-1];
- } else {
- cell = alternate[counter2 - (counter2 / 4)];
- }
- } else {
- if (counter) {
- if (counter < 4) {
- cell = cells[counter-1];
- } else {
- cell = cells[counter - (counter / 4)];
- }
- }
- }
- if (cell) {
- if (Map.Theater == THEATER_DESERT) {
- cell += MAP_CELL_W;
- }
- }
- return(cell);
- }
- case SOURCE_OCEAN:
- cell = XY_Cell(Random_Pick(0, MapCellWidth-2)+MapCellX, MapCellHeight+MapCellY);
- break;
- default:
- return(0);
- }
- /*
- ** The selected edge cell must be unoccupied and if this is for
- ** the player, then it must be on an accessible map cell.
- */
- cell &= 0x0FFF;
- if (cell && (*this)[cell].Cell_Techno()) {
- cell = 0;
- }
- }
- return(cell);
- }
- /***********************************************************************************************
- * DisplayClass::Select_These -- All selectable objects in region are selected. *
- * *
- * Use this routine to simultaneously select all objects within the coordinate region *
- * specified. This routine is used by the multi-select rubber band handler. *
- * *
- * INPUT: coord1 -- Coordinate of one corner of the selection region. *
- * *
- * coord2 -- The opposite corner of the selection region. *
- * *
- * additive -- Does this add to the existing selection or replace it. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 01/19/1995 JLB : Created. *
- * 04/25/1995 JLB : Limited to non-building type. *
- *=============================================================================================*/
- static bool should_exclude_from_selection(ObjectClass* obj)
- {
- return (obj->What_Am_I() == RTTI_UNIT) &&
- (((UnitClass *)obj)->Class->IsToHarvest ||
- *((UnitClass *)obj) == UNIT_MCV);
- }
- void DisplayClass::Select_These(COORDINATE coord1, COORDINATE coord2, bool additive)
- {
- COORDINATE tcoord = TacticalCoord; //Cell_Coord(TacticalCell) & 0xFF00FF00L;
- coord1 = Coord_Add(tcoord, coord1);
- coord2 = Coord_Add(tcoord, coord2);
- int x1 = Coord_X(coord1);
- int x2 = Coord_X(coord2);
- int y1 = Coord_Y(coord1);
- int y2 = Coord_Y(coord2);
- /*
- ** Ensure that coordinate number one represents the upper left corner
- ** and coordinate number two represents the lower right corner.
- */
- if (x1 > x2) {
- int temp = x1;
- x1 = x2;
- x2 = temp;
- }
- if (y1 > y2) {
- int temp = y1;
- y1 = y2;
- y2 = temp;
- }
- /*
- ** Sweep through all ground layer objects and select the ones within the
- ** bounding box.
- */
- if (!additive) {
- Unselect_All();
- }
- AllowVoice = true;
- for (int index = 0; index < Layer[LAYER_GROUND].Count(); index++) {
- ObjectClass * obj = Layer[LAYER_GROUND][index];
- COORDINATE ocoord = obj->Center_Coord();
- int x = Coord_X(ocoord);
- int y = Coord_Y(ocoord);
- /*
- ** Only try to select objects that are owned by the player, are allowed to be
- ** selected, and are within the bouding box.
- */
- if ( obj->Class_Of().IsSelectable &&
- obj->What_Am_I() != RTTI_BUILDING &&
- (!obj->Is_Techno() || !((TechnoClass*)obj)->Is_Cloaked(PlayerPtr)) &&
- x >= x1 && x <= x2 && y >= y1 && y <= y2) {
- bool old_allow_voice = AllowVoice;
- bool is_player_controlled = obj->Owner() == PlayerPtr->Class->House;
- AllowVoice &= is_player_controlled;
- if (obj->Select(true)) {
- if (is_player_controlled) {
- old_allow_voice = false;
- }
- }
- AllowVoice = old_allow_voice;
- }
- }
- /*
- ** Select any aircraft with the bounding box.
- */
- for (int air_index = 0; air_index < Aircraft.Count(); air_index++) {
- AircraftClass * aircraft = Aircraft.Ptr(air_index);
- COORDINATE ocoord = Coord_Add(aircraft->Center_Coord(), XY_Coord(0, -Pixel_To_Lepton(aircraft->Altitude)));
- int x = Coord_X(ocoord);
- int y = Coord_Y(ocoord);
- /*
- ** Only try to select objects that are owned by the player, are allowed to be
- ** selected, and are within the bounding box.
- */
- if ( aircraft->Class_Of().IsSelectable &&
- !aircraft->Is_Cloaked(PlayerPtr) &&
- !aircraft->Is_Selected_By_Player() &&
- x >= x1 && x <= x2 && y >= y1 && y <= y2) {
- bool old_allow_voice = AllowVoice;
- bool is_player_controlled = aircraft->Owner() == PlayerPtr->Class->House;
- AllowVoice &= is_player_controlled;
- if (aircraft->Select(true)) {
- if (is_player_controlled) {
- old_allow_voice = false;
- }
- }
- AllowVoice = old_allow_voice;
- }
- }
- /*
- ** If a mix of player and non-player controlled units were selected, make sure non-player controlled units are de-selected
- */
- bool player_controlled_units = false, non_player_controlled_units = false;
- for (int i = 0; (i < CurrentObject.Count()) && (!player_controlled_units || !non_player_controlled_units); ++i) {
- HouseClass * hptr = HouseClass::As_Pointer(CurrentObject[i]->Owner());
- if (CurrentObject[i]->Owner() == PlayerPtr->Class->House) {
- player_controlled_units = true;
- }
- else {
- non_player_controlled_units = true;
- }
- }
- if (player_controlled_units && non_player_controlled_units) {
- for (int i = 0; i < CurrentObject.Count(); ++i) {
- HouseClass * hptr = HouseClass::As_Pointer(CurrentObject[i]->Owner());
- if (CurrentObject[i]->Owner() != PlayerPtr->Class->House) {
- int count_before = CurrentObject.Count();
- CurrentObject[i]->Unselect();
- if (count_before <= CurrentObject.Count()) {
- GlyphX_Debug_Print("Select_These failed to remove an object");
- CurrentObject.Delete(CurrentObject[i]);
- }
- --i;
- }
- }
- }
- /*
- ** If player-controlled units are non-additively selected, remove harvesters and MCVs if they aren't the only types of units selected
- */
- if (!additive && player_controlled_units) {
- bool any_to_exclude = false, all_to_exclude = true;
- for (int i = 0; i < CurrentObject.Count(); ++i) {
- bool exclude = should_exclude_from_selection(CurrentObject[i]);
- any_to_exclude |= exclude;
- all_to_exclude &= exclude;
- }
- if (any_to_exclude && !all_to_exclude) {
- for (int i = 0; i < CurrentObject.Count(); ++i) {
- if (should_exclude_from_selection(CurrentObject[i])) {
- int count_before = CurrentObject.Count();
- CurrentObject[i]->Unselect();
- if (count_before <= CurrentObject.Count()) {
- GlyphX_Debug_Print("Select_These failed to remove an object");
- CurrentObject.Delete(CurrentObject[i]);
- }
- --i;
- }
- }
- }
- }
- AllowVoice = true;
- }
- /***********************************************************************************************
- * DisplayClass::Refresh_Band -- Causes all cells under the rubber band to be redrawn. *
- * *
- * Use this routine to flag all cells that are covered in some fashion by the multi-unit *
- * select "rubber band" to be redrawn. This is necessary whenever the rubber band changes *
- * size or is being removed. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 01/19/1995 JLB : Created. *
- *=============================================================================================*/
- void DisplayClass::Refresh_Band(void)
- {
- if (IsRubberBand) {
- /*
- ** In rubber band mode, mark all cells under the "rubber band" to be
- ** redrawn.
- */
- int x1 = BandX+TacPixelX;
- int y1 = BandY+TacPixelY;
- int x2 = NewX+TacPixelX;
- int y2 = NewY+TacPixelY;
- if (x1 > x2) {
- int temp = x1;
- x1 = x2;
- x2 = temp;
- }
- if (y1 > y2) {
- int temp = y1;
- y1 = y2;
- y2 = temp;
- }
- CELL cell;
- for (int y = y1; y <= y2+CELL_PIXEL_H; y += CELL_PIXEL_H) {
- cell = Click_Cell_Calc(x1, Bound(y, 0, TacPixelY+Lepton_To_Pixel(TacLeptonHeight)));
- if (cell != -1) (*this)[cell].Redraw_Objects();
- cell = Click_Cell_Calc(x2, Bound(y, 0, TacPixelY+Lepton_To_Pixel(TacLeptonHeight)));
- if (cell != -1) (*this)[cell].Redraw_Objects();
- }
- for (int x = x1; x <= x2+CELL_PIXEL_W; x += CELL_PIXEL_W) {
- cell = Click_Cell_Calc(Bound(x, 0, TacPixelX+Lepton_To_Pixel(TacLeptonWidth)), y1);
- if (cell != -1) (*this)[cell].Redraw_Objects();
- cell = Click_Cell_Calc(Bound(x, 0, TacPixelX+Lepton_To_Pixel(TacLeptonWidth)), y2);
- if (cell != -1) (*this)[cell].Redraw_Objects();
- }
- }
- }
- /***********************************************************************************************
- * DisplayClass::TacticalClass::Action -- Processes input for the tactical map. *
- * *
- * This routine handles the input directed at the tactical map. Since input, in this *
- * regard, includes even the presence of the mouse over the tactical map, this routine *
- * is called nearly every game frame. It handles adjusting the mouse shape as well as *
- * giving orders to units. *
- * *
- * INPUT: flags -- The gadget event flags that triggered the call to this function. *
- * *
- * key -- A reference to the keyboard event (if any). *
- * *
- * OUTPUT: bool; Should processing be aborted on any succeeding buttons in the chain? *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 02/17/1995 JLB : Created. *
- *=============================================================================================*/
- int DisplayClass::TacticalClass::Action(unsigned flags, KeyNumType & key)
- {
- int x,y; // Sub cell pixel coordinates.
- bool shadow;
- ObjectClass *object = 0;
- ActionType action = ACTION_NONE; // Action possible with currently selected object.
- /*
- ** Set some working variables that depend on the mouse position. For the press
- ** or release event, special mouse queuing storage variables are used. Other
- ** events must use the current mouse position globals.
- */
- bool edge = false;
- if (flags & (LEFTPRESS|LEFTRELEASE|RIGHTPRESS|RIGHTRELEASE)) {
- x = _Kbd->MouseQX;
- y = _Kbd->MouseQY;
- } else {
- x = Get_Mouse_X();
- y = Get_Mouse_Y();
- if (x == 0 || y == 199 || x == 319) edge = true;
- }
- COORDINATE coord = Map.Pixel_To_Coord(x, y);
- CELL cell = Coord_Cell(coord);
- // CELL cell = Map.Click_Cell_Calc(x, y);
- if (coord) {
- shadow = (!Map[cell].Is_Visible(PlayerPtr) && !Debug_Unshroud); // Use PlayerPtr since we won't be rendering in MP. ST - 3/6/2019 2:49PM
- x -= Map.TacPixelX;
- y -= Map.TacPixelY;
- /*
- ** Cause any displayed cursor to move along with the mouse cursor.
- */
- if (cell != Map.ZoneCell) {
- Map.Set_Cursor_Pos(cell);
- }
- /*
- ** Determine the object that the mouse is currently over.
- */
- if (!shadow) {
- // int xxx = x + Lepton_To_Pixel(Coord_XLepton(Map.TacticalCoord));
- // int yyy = y + Lepton_To_Pixel(Coord_YLepton(Map.TacticalCoord));
- // object = Map.Cell_Object(cell, xxx % CELL_PIXEL_W, yyy % CELL_PIXEL_H);
- object = Map.Close_Object(coord);
- /*
- ** Special case check to ignore cloaked object if not owned by the player.
- */
- // if (object && object->Is_Techno() && !((TechnoClass *)object)->IsOwnedByPlayer && ((TechnoClass *)object)->Cloak == CLOAKED) {
- // object = NULL;
- // }
- }
- /*
- ** If there is a currently selected object, then the action to perform if
- ** the left mouse button were clicked must be determined.
- */
- if (CurrentObject.Count()) {
- if (object) {
- action = Best_Object_Action(object);
- } else {
- action = Best_Object_Action(cell);
- }
- } else {
- if (object && object->Class_Of().IsSelectable) {
- action = ACTION_SELECT;
- }
- if (Map.IsRepairMode) {
- if (object && object->Owner() == PlayerPtr->Class->House && object->Can_Repair()) {
- action = ACTION_REPAIR;
- } else {
- action = ACTION_NO_REPAIR;
- }
- }
- if (Map.IsSellMode) {
- if (object && object->Owner() == PlayerPtr->Class->House && object->Can_Demolish()) {
- if (object->What_Am_I() == RTTI_BUILDING) {
- action = ACTION_SELL;
- } else {
- action = ACTION_SELL_UNIT;
- }
- } else {
- /*
- ** Check to see if the cursor is over an owned wall.
- */
- if (Map[cell].Overlay != OVERLAY_NONE &&
- OverlayTypeClass::As_Reference(Map[cell].Overlay).IsWall &&
- Map[cell].Owner == PlayerPtr->Class->House) {
- action = ACTION_SELL;
- } else {
- action = ACTION_NO_SELL;
- }
- }
- }
- if (Map.IsTargettingMode == SPC_ION_CANNON) {
- action = ACTION_ION;
- }
- if (Map.IsTargettingMode == SPC_NUCLEAR_BOMB) {
- action = ACTION_NUKE_BOMB;
- }
- if (Map.IsTargettingMode == SPC_AIR_STRIKE) {
- action = ACTION_AIR_STRIKE;
- }
- if (Map.PendingObject) {
- action = ACTION_NONE;
- }
- }
- /*
- ** Move any cursor displayed.
- */
- if (cell != Map.ZoneCell) {
- Map.Set_Cursor_Pos(cell);
- }
- /*
- ** A right mouse button press cancels the current action or selection.
- */
- if (flags & RIGHTPRESS) {
- Map.Mouse_Right_Press();
- }
- /*
- ** Make sure that if the mouse button has been released and the map doesn't know about it,
- ** then it must be informed. Do this by faking a mouse release event.
- */
- if ((flags & LEFTUP) && Map.IsRubberBand) {
- flags |= LEFTRELEASE;
- }
- /*
- ** When the mouse buttons aren't pressed, only the mouse cursor shape is processed.
- ** The shape changes depending on what object the mouse is currently over and what
- ** object is currently selected.
- */
- if (!edge) {
- if (flags & LEFTUP) {
- Map.Mouse_Left_Up(shadow, object, action);
- }
- }
- /*
- ** Normal actions occur when the mouse button is released. The press event is
- ** intercepted and possible rubber-band mode is flagged.
- */
- if (flags & LEFTRELEASE) {
- Map.Mouse_Left_Release(cell, x, y, object, action);
- }
- /*
- ** When the mouse is first pressed on the map, then record the mouse
- ** position so that a proper check before going into rubber band
- ** mode can be made. Rubber band mode starts when the mouse is
- ** held down and moved a certain minimum distance.
- */
- if (!edge && (flags & LEFTPRESS)) {
- Map.Mouse_Left_Press(x, y);
- }
- /*
- ** While the mouse is being held down, determine if rubber band mode should
- ** start. If rubber band mode is already active, then update the size
- ** and flag the map to redraw it.
- */
- if (flags & LEFTHELD) {
- Map.Mouse_Left_Held(x, y);
- }
- }
- return(GadgetClass::Action(0, key));
- }
- /***********************************************************************************************
- * DisplayClass::TacticalClass::Selection_At_Mouse -- Object selection *
- * *
- * Selects any objects at the current mouse position. *
- * *
- * *
- * INPUT: flags -- The gadget event flags that triggered the call to this function. *
- * *
- * key -- A reference to the keyboard event (if any). *
- * *
- * OUTPUT: bool; Should processing be aborted on any succeeding buttons in the chain? *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 2019/09/17 JAS *
- *=============================================================================================*/
- int DisplayClass::TacticalClass::Selection_At_Mouse(unsigned flags, KeyNumType & key)
- {
- int x, y; // Sub cell pixel coordinates.
- bool edge = false;
- if (flags & (LEFTPRESS | LEFTRELEASE | RIGHTPRESS | RIGHTRELEASE)) {
- x = _Kbd->MouseQX;
- y = _Kbd->MouseQY;
- }
- else {
- x = Get_Mouse_X();
- y = Get_Mouse_Y();
- if (x == 0 || y == 199 || x == 319) edge = true;
- }
- COORDINATE coord = Map.Pixel_To_Coord(x, y);
- CELL cell = Coord_Cell(coord);
- if (coord) {
- bool shadow = (!Map[cell].Is_Visible(PlayerPtr) && !Debug_Unshroud); // Use PlayerPtr since we won't be rendering in MP. ST - 3/6/2019 2:49PM
- x -= Map.TacPixelX;
- y -= Map.TacPixelY;
- /*
- ** Cause any displayed cursor to move along with the mouse cursor.
- */
- if (cell != Map.ZoneCell) {
- Map.Set_Cursor_Pos(cell);
- }
- ObjectClass* object = nullptr;
- /*
- ** Determine the object that the mouse is currently over.
- */
- if (!shadow) {
- object = Map.Close_Object(coord);
- }
- if (object != nullptr)
- {
- bool shiftdown = DLL_Export_Get_Input_Key_State(KN_LSHIFT);
- if (shiftdown)
- {
- Map.Mouse_Left_Release(cell, x, y, object, ACTION_TOGGLE_SELECT);
- }
- else
- {
- Map.Mouse_Left_Release(cell, x, y, object, ACTION_SELECT);
- }
- }
- else
- {
- Unselect_All();
- }
- }
- return 0;
- }
- /***********************************************************************************************
- * DisplayClass::TacticalClass::Command_Object -- Commanding Units *
- * *
- * Issues a command to the currently selected unit. *
- * *
- * *
- * INPUT: flags -- The gadget event flags that triggered the call to this function. *
- * *
- * key -- A reference to the keyboard event (if any). *
- * *
- * OUTPUT: bool; Should processing be aborted on any succeeding buttons in the chain? *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 2019/09/17 JAS *
- *=============================================================================================*/
- int DisplayClass::TacticalClass::Command_Object(unsigned flags, KeyNumType & key)
- {
- int x, y; // Sub cell pixel coordinates.
- bool edge = false;
- if (flags & (LEFTPRESS | LEFTRELEASE | RIGHTPRESS | RIGHTRELEASE)) {
- x = _Kbd->MouseQX;
- y = _Kbd->MouseQY;
- }
- else {
- x = Get_Mouse_X();
- y = Get_Mouse_Y();
- if (x == 0 || y == 199 || x == 319) edge = true;
- }
- COORDINATE coord = Map.Pixel_To_Coord(x, y);
- CELL cell = Coord_Cell(coord);
- ActionType action = ACTION_NONE;
- if (coord) {
- bool shadow = (!Map[cell].Is_Visible(PlayerPtr) && !Debug_Unshroud); // Use PlayerPtr since we won't be rendering in MP. ST - 3/6/2019 2:49PM
- x -= Map.TacPixelX;
- y -= Map.TacPixelY;
- /*
- ** Cause any displayed cursor to move along with the mouse cursor.
- */
- if (cell != Map.ZoneCell) {
- Map.Set_Cursor_Pos(cell);
- }
- ObjectClass* object = nullptr;
- /*
- ** Determine the object that the mouse is currently over.
- */
- if (!shadow) {
- object = Map.Close_Object(coord);
- }
- if (CurrentObject.Count()) {
- if (object) {
- action = Best_Object_Action(object);
- }
- else {
- action = Best_Object_Action(cell);
- }
- }
- if (action != ACTION_SELECT)
- {
- Map.Mouse_Left_Release(cell, x, y, object, action);
- }
- }
- return 0;
- }
- /***********************************************************************************************
- * DisplayClass::Mouse_Right_Press -- Handles the right mouse button press. *
- * *
- * This routine is called when the right mouse button is pressed. This action is supposed *
- * to cancel whatever mode or process is active. If there is nothing to cancel, then it *
- * will default to unselecting any units that might be currently selected. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 02/24/1995 JLB : Created. *
- *=============================================================================================*/
- void DisplayClass::Mouse_Right_Press(void)
- {
- if (PendingObjectPtr && PendingObjectPtr->Is_Techno()) {
- //PendingObjectPtr->Transmit_Message(RADIO_OVER_OUT);
- PendingObjectPtr = 0;
- PendingObject = 0;
- PendingHouse = HOUSE_NONE;
- Set_Cursor_Shape(0);
- } else {
- if (IsRepairMode) {
- IsRepairMode = false;
- } else {
- if (IsSellMode) {
- IsSellMode = false;
- } else {
- if (IsTargettingMode) {
- IsTargettingMode = false;
- } else {
- Unselect_All();
- }
- }
- }
- }
- Set_Default_Mouse(MOUSE_NORMAL, false);
- }
- /***********************************************************************************************
- * DisplayClass::Mouse_Left_Up -- Handles the left mouse "cruising" over the map. *
- * *
- * This routine is called continuously while the mouse is over the tactical map but there *
- * are no mouse buttons pressed. Typically, this adjusts the mouse shape and the pop-up *
- * help text. *
- * *
- * INPUT: shadow -- Is the mouse hovering over shadowed terrain? *
- * *
- * object -- Pointer to the object that the mouse is currently over (may be NULL). *
- * *
- * action -- This is the action that the currently selected object (if any) will *
- * perform if the left mouse button were clicked at this location. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 02/24/1995 JLB : Created. *
- * 07/05/1995 JLB : Removed pop up help text for shadow and terrain after #3. *
- *=============================================================================================*/
- void DisplayClass::Mouse_Left_Up(bool shadow, ObjectClass * object, ActionType action, bool wwsmall)
- {
- IsTentative = false;
- /*
- ** Don't allow selection of an object that is located in shadowed terrain.
- ** In fact, just show the normal move cursor in order to keep the shadowed
- ** terrain a mystery.
- */
- if (shadow) {
- switch (action) {
- case ACTION_GUARD_AREA:
- Set_Default_Mouse(MOUSE_AREA_GUARD, wwsmall);
- break;
- case ACTION_NONE:
- Set_Default_Mouse(MOUSE_NORMAL, wwsmall);
- break;
- case ACTION_NO_SELL:
- case ACTION_SELL:
- case ACTION_SELL_UNIT:
- Set_Default_Mouse(MOUSE_NO_SELL_BACK, wwsmall);
- break;
- case ACTION_NO_REPAIR:
- case ACTION_REPAIR:
- Set_Default_Mouse(MOUSE_NO_REPAIR, wwsmall);
- break;
- case ACTION_ION:
- Set_Default_Mouse(MOUSE_ION_CANNON, wwsmall);
- break;
- case ACTION_NUKE_BOMB:
- Set_Default_Mouse(MOUSE_NUCLEAR_BOMB, wwsmall);
- break;
- case ACTION_AIR_STRIKE:
- Set_Default_Mouse(MOUSE_AIR_STRIKE, wwsmall);
- break;
- case ACTION_NOMOVE:
- if (CurrentObject.Count()) {
- MouseType mouse_type = MOUSE_NO_MOVE;
- for (int i = 0; i < CurrentObject.Count(); ++i) {
- if (CurrentObject[i]->What_Am_I() != RTTI_AIRCRAFT) {
- mouse_type = MOUSE_CAN_MOVE;
- break;
- }
- }
- Set_Default_Mouse(mouse_type, wwsmall);
- break;
- }
- // Fall into next case for non aircraft object types.
- default:
- Set_Default_Mouse(MOUSE_CAN_MOVE, wwsmall);
- break;
- }
- } else {
- /*
- ** Change the mouse shape according to the default action that will occur
- ** if the mouse button were clicked at this location.
- */
- switch (action) {
- case ACTION_TOGGLE_SELECT:
- case ACTION_SELECT:
- Set_Default_Mouse(MOUSE_CAN_SELECT, wwsmall);
- break;
- case ACTION_MOVE:
- Set_Default_Mouse(MOUSE_CAN_MOVE, wwsmall);
- break;
- case ACTION_GUARD_AREA:
- Set_Default_Mouse(MOUSE_AREA_GUARD, wwsmall);
- break;
- case ACTION_HARVEST:
- case ACTION_ATTACK:
- Set_Default_Mouse(MOUSE_CAN_ATTACK, wwsmall);
- break;
- case ACTION_SABOTAGE:
- Set_Default_Mouse(MOUSE_DEMOLITIONS, wwsmall);
- break;
- case ACTION_ENTER:
- case ACTION_CAPTURE:
- Set_Default_Mouse(MOUSE_ENTER, wwsmall);
- break;
- case ACTION_NOMOVE:
- Set_Default_Mouse(MOUSE_NO_MOVE, wwsmall);
- break;
- case ACTION_NO_SELL:
- Set_Default_Mouse(MOUSE_NO_SELL_BACK, wwsmall);
- break;
- case ACTION_NO_REPAIR:
- Set_Default_Mouse(MOUSE_NO_REPAIR, wwsmall);
- break;
- case ACTION_SELF:
- Set_Default_Mouse(MOUSE_DEPLOY, wwsmall);
- break;
- case ACTION_REPAIR:
- Set_Default_Mouse(MOUSE_REPAIR, wwsmall);
- break;
- case ACTION_SELL_UNIT:
- Set_Default_Mouse(MOUSE_SELL_UNIT, wwsmall);
- break;
- case ACTION_SELL:
- Set_Default_Mouse(MOUSE_SELL_BACK, wwsmall);
- break;
- case ACTION_ION:
- Set_Default_Mouse(MOUSE_ION_CANNON, wwsmall);
- break;
- case ACTION_NUKE_BOMB:
- Set_Default_Mouse(MOUSE_NUCLEAR_BOMB, wwsmall);
- break;
- case ACTION_AIR_STRIKE:
- Set_Default_Mouse(MOUSE_AIR_STRIKE, wwsmall);
- break;
- case ACTION_TOGGLE_PRIMARY:
- Set_Default_Mouse(MOUSE_DEPLOY, wwsmall);
- break;
- default:
- Set_Default_Mouse(MOUSE_NORMAL, wwsmall);
- break;
- }
- }
- #if 0
- /*
- ** Give a generic help message when over shadow terrain.
- */
- if (shadow) {
- if (Scenario < 4) {
- Help_Text(TXT_SHADOW);
- } else {
- Help_Text(TXT_NONE);
- }
- } else {
- /*
- ** If the mouse is held over objects on the map, then help text may
- ** pop up that tells what the object is. This call informs the help
- ** system of the text name for the object under the mouse.
- */
- if (object) {
- int text;
- int color = LTGREY;
- /*
- ** Fetch the appropriate background color for help text.
- */
- if (PlayerPtr->Is_Ally(object)) {
- color = CC_GREEN;
- } else {
- if (object->Owner() == HOUSE_NONE || object->Owner() == HOUSE_NEUTRAL) {
- color = LTGREY;
- } else {
- color = PINK;
- }
- }
- /*
- ** Fetch the name of the object. If it is an enemy object, then
- ** the exact identity is glossed over with a generic text.
- */
- text = object->Full_Name();
- if (object->Is_Techno() && !((TechnoTypeClass const &)object->Class_Of()).IsNominal) {
- if (!PlayerPtr->Is_Ally(object)) {
- switch (object->What_Am_I()) {
- case RTTI_INFANTRY:
- text = TXT_ENEMY_SOLDIER;
- break;
- case RTTI_UNIT:
- text = TXT_ENEMY_VEHICLE;
- break;
- case RTTI_BUILDING:
- if ( *((BuildingClass*)object) != STRUCT_MISSION) {
- text = TXT_ENEMY_STRUCTURE;
- }
- break;
- }
- }
- }
- if (Scenario > 3 || object->What_Am_I() != RTTI_TERRAIN) {
- Help_Text(text, -1, -1, color);
- } else {
- Help_Text(TXT_NONE);
- }
- } else {
- Help_Text(TXT_NONE);
- }
- }
- #endif
- }
- /***********************************************************************************************
- * DisplayClass::Mouse_Left_Release -- Handles the left mouse button release. *
- * *
- * This routine is called when the left mouse button is released over the tactical map. *
- * The release event is the workhorse of the game. Most actions occur at the moment of *
- * mouse release. *
- * *
- * INPUT: cell -- The cell that the mouse is over. *
- * *
- * x,y -- The mouse pixel coordinate. *
- * *
- * object -- Pointer to the object that the mouse is over. *
- * *
- * action -- The action that the currently selected object (if any) will *
- * perform. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 02/24/1995 JLB : Created. *
- * 03/27/1995 JLB : Handles sell and repair actions. *
- *=============================================================================================*/
- void DisplayClass::Mouse_Left_Release(CELL cell, int x, int y, ObjectClass * object, ActionType action, bool wwsmall)
- {
- if (PendingObjectPtr) {
- /*
- ** Try to place the pending object onto the map.
- */
- if (ProximityCheck) {
- OutList.Add(EventClass(EventClass::PLACE, PendingObjectPtr->What_Am_I(), cell + ZoneOffset));
- } else {
- Speak(VOX_DEPLOY);
- }
- } else {
- if (IsRubberBand) {
- Refresh_Band();
- Select_These(XYPixel_Coord(BandX, BandY), XYPixel_Coord(x, y));
- Set_Default_Mouse(MOUSE_NORMAL, wwsmall);
- #ifdef NEVER
- if (CurrentObject.Count()) {
- if (CurrentObject[0]->Can_Player_Fire()) {
- Set_Default_Mouse(MOUSE_CAN_ATTACK, wwsmall);
- } else {
- Set_Default_Mouse(MOUSE_NORMAL, wwsmall);
- }
- } else {
- Set_Default_Mouse(MOUSE_NORMAL, wwsmall);
- }
- #endif
- IsRubberBand = false;
- IsTentative = false;
- Map.DisplayClass::IsToRedraw = true;
- Map.Flag_To_Redraw(false);
- } else {
- /*
- ** Toggle the select state of the object.
- */
- if (action == ACTION_TOGGLE_SELECT) {
- if (!object || !CurrentObject.Count()) {
- action = ACTION_SELECT;
- } else {
- if (object->Is_Selected_By_Player()) {
- object->Unselect();
- } else {
- object->Select();
- }
- }
- }
- /*
- ** Selection of other object action.
- */
- if (action == ACTION_SELECT || (action == ACTION_NONE && object && object->Class_Of().IsSelectable && !object->Is_Selected_By_Player())) {
- if (object->Is_Selected_By_Player()) {
- object->Unselect();
- }
- if (object->Select()) {
- Unselect_All_Except(object);
- Set_Default_Mouse(MOUSE_NORMAL, wwsmall);
- }
- #ifdef NEVER
- if (object->Can_Player_Fire()) {
- Set_Default_Mouse(MOUSE_CAN_ATTACK, wwsmall);
- } else {
- Set_Default_Mouse(MOUSE_NORMAL, wwsmall);
- }
- #endif
- }
- /*
- ** If an action was detected as possible, then pass this action event
- ** to all selected objects.
- */
- if (action != ACTION_NONE && action != ACTION_SELECT && action != ACTION_TOGGLE_SELECT) {
- /*
- ** Pass the action to all the selected objects. But first, redetermine
- ** what action that object should perform. This, seemingly redundant
- ** process, is necessary since multiple objects could be selected and each
- ** might perform a different action when the click occurs.
- */
- bool doflash = true;
- AllowVoice = true;
- for (int index = 0; index < CurrentObject.Count(); index++) {
- ObjectClass * tobject = CurrentObject[index];
- ActionType action = ACTION_NONE;
- if (object) {
- action = tobject->What_Action(object);
- tobject->Active_Click_With(action, object);
- } else {
- action = tobject->What_Action(cell);
- tobject->Active_Click_With(action, cell);
- }
- if (action != ACTION_NONE) {
- AllowVoice = false;
- }
- }
- AllowVoice = true;
- if (action == ACTION_REPAIR && object->What_Am_I() == RTTI_BUILDING) {
- OutList.Add(EventClass(EventClass::REPAIR, object->As_Target()));
- }
- if (action == ACTION_SELL_UNIT && object) {
- switch (object->What_Am_I()) {
- case RTTI_AIRCRAFT:
- case RTTI_UNIT:
- OutList.Add(EventClass(EventClass::SELL, object->As_Target()));
- break;
- default:
- break;
- }
- }
- if (action == ACTION_SELL) {
- if (object) {
- OutList.Add(EventClass(EventClass::SELL, object->As_Target()));
- } else {
- OutList.Add(EventClass(EventClass::SELL, ::As_Target(cell)));
- }
- }
- if (action == ACTION_ION) {
- OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_ION_CANNON, cell));
- }
- if (action == ACTION_NUKE_BOMB) {
- OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_NUCLEAR_BOMB, cell));
- }
- if (action == ACTION_AIR_STRIKE) {
- OutList.Add(EventClass(EventClass::SPECIAL_PLACE, SPC_AIR_STRIKE, cell));
- }
- }
- IsTentative = false;
- }
- }
- }
- /***********************************************************************************************
- * DisplayClass::Mouse_Left_Press -- Handles the left mouse button press. *
- * *
- * Handle the left mouse button press while over the tactical map. If it isn't is *
- * repair or sell mode, then a tentative transition to rubber band mode is flagged. If the *
- * mouse moves a sufficient distance from this recorded position, then rubber band mode *
- * is officially started. *
- * *
- * INPUT: x,y -- The mouse coordinates at the time of the press. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 02/24/1995 JLB : Created. *
- *=============================================================================================*/
- void DisplayClass::Mouse_Left_Press(int x, int y)
- {
- if (!IsRepairMode && !IsSellMode && !IsTargettingMode && !PendingObject) {
- IsTentative = true;
- BandX = x;
- BandY = y;
- NewX = x;
- NewY = y;
- }
- }
- /***********************************************************************************************
- * DisplayClass::Mouse_Left_Held -- Handles the left button held down. *
- * *
- * This routine is called continuously while the left mouse button is held down over *
- * the tactical map. This handles the rubber band mode detection and dragging. *
- * *
- * INPUT: x,y -- The mouse coordinate. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 02/24/1995 JLB : Created. *
- *=============================================================================================*/
- void DisplayClass::Mouse_Left_Held(int x, int y)
- {
- if (IsRubberBand) {
- if (x != NewX || y != NewY) {
- x = Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1);
- y = Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1);
- Refresh_Band();
- NewX = x;
- NewY = y;
- IsToRedraw = true;
- Flag_To_Redraw(false);
- }
- } else {
- /*
- ** If the mouse is still held down while a tentative extended select is possible, then
- ** check to see if the mouse has moved a sufficient distance in order to activate
- ** extended select mode.
- */
- if (IsTentative) {
- /*
- ** The mouse must have moved a minimum distance before rubber band mode can be
- ** initiated.
- */
- if (ABS(x - BandX) > 4 || ABS(y - BandY) > 4) {
- IsRubberBand = true;
- x = Bound(x, 0, Lepton_To_Pixel(TacLeptonWidth)-1);
- y = Bound(y, 0, Lepton_To_Pixel(TacLeptonHeight)-1);
- NewX = x;
- NewY = y;
- IsToRedraw = true;
- Flag_To_Redraw(false);
- }
- }
- }
- }
- // Needed to accomodate Glyphx client sidebar. ST - 4/12/2019 5:29PM
- extern int GlyphXClientSidebarWidthInLeptons;
- /***********************************************************************************************
- * DisplayClass::Set_Tactical_Position -- Sets the tactical view position. *
- * *
- * This routine is used to set the tactical view position. The requested position is *
- * clipped to the map dimensions as necessary. *
- * *
- * INPUT: coord -- The coordinate desired for the upper left corner. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 08/13/1995 JLB : Created. *
- *=============================================================================================*/
- void DisplayClass::Set_Tactical_Position(COORDINATE coord)
- {
- /*
- ** Bound the desired location to fit the legal map edges.
- */
- int xx = 0;// Coord_X(coord) - Cell_To_Lepton(MapCellX);
- int yy = 0;// Coord_Y(coord) - Cell_To_Lepton(MapCellY);
- Confine_Rect(&xx, &yy, TacLeptonWidth, TacLeptonHeight, Cell_To_Lepton(MapCellWidth) + GlyphXClientSidebarWidthInLeptons, Cell_To_Lepton(MapCellHeight)); // Needed to accomodate Glyphx client sidebar. ST - 4/12/2019 5:29PM
- coord = XY_Coord(xx + Cell_To_Lepton(MapCellX), yy + Cell_To_Lepton(MapCellY));
- if (ScenarioInit) {
- TacticalCoord = coord;
- }
- DesiredTacticalCoord = coord;
- IsToRedraw = true;
- Flag_To_Redraw(false);
- }
- /***********************************************************************************************
- * DisplayClass::Compute_Start_Pos -- Computes player's start pos from unit coords. *
- * *
- * Use this function in multiplayer games, to compute the scenario starting Tactical Pos. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: x, y -- Player starting location *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 02/28/1995 JLB : Commented. *
- * 06/26/1995 JLB : Fixed building loop. *
- *=============================================================================================*/
- void DisplayClass::Compute_Start_Pos(long& x, long& y)
- {
- /*
- ** Find the summation cell-x & cell-y for all the player's units, infantry,
- ** and buildings. Buildings are weighted so that they count 16 times more
- ** than units or infantry.
- */
- x = 0;
- y = 0;
- long num = 0;
- int i;
- for (i = 0; i < Infantry.Count(); i++) {
- InfantryClass * infp = Infantry.Ptr(i);
- if (!infp->IsInLimbo && infp->House == PlayerPtr) {
- x += (long)Coord_XCell (infp->Coord);
- y += (long)Coord_YCell (infp->Coord);
- num++;
- }
- }
- for (i = 0; i < Units.Count(); i++) {
- UnitClass * unitp = Units.Ptr(i);
- if (!unitp->IsInLimbo && unitp->House == PlayerPtr) {
- x += (long)Coord_XCell (unitp->Coord);
- y += (long)Coord_YCell (unitp->Coord);
- num++;
- }
- }
- for (i = 0; i < Buildings.Count(); i++) {
- BuildingClass * bldgp = Buildings.Ptr(i);
- if (!bldgp->IsInLimbo && bldgp->House == PlayerPtr) {
- x += (((long)Coord_XCell (bldgp->Coord)) << 4);
- y += (((long)Coord_YCell (bldgp->Coord)) << 4);
- num += 16;
- }
- }
- /*
- ** Divide each coord by 'num' to compute the average value
- */
- if (num > 0) {
- x /= num;
- } else {
- x = 0;
- }
- if (num > 0) {
- y /= num;
- } else {
- y = 0;
- }
- }
- /***********************************************************************************************
- * DisplayClass::Sell_Mode_Control -- Controls the sell mode. *
- * *
- * This routine will control the sell mode for the player. *
- * *
- * INPUT: control -- The mode to set the sell state to. *
- * 0 = Turn sell mode off. *
- * 1 = Turn sell mode on. *
- * -1 = Toggle sell mode. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 07/08/1995 JLB : Created. *
- *=============================================================================================*/
- void DisplayClass::Sell_Mode_Control(int control)
- {
- bool mode = IsSellMode;
- switch (control) {
- case 0:
- mode = false;
- break;
- case -1:
- mode = (IsSellMode == false);
- break;
- case 1:
- mode = true;
- break;
- }
- if (mode != IsSellMode && !PendingObject) {
- IsRepairMode = false;
- if (mode && PlayerPtr->BScan) {
- IsSellMode = true;
- Unselect_All();
- } else {
- IsSellMode = false;
- Revert_Mouse_Shape();
- }
- }
- }
- /***********************************************************************************************
- * DisplayClass::Repair_Mode_Control -- Controls the repair mode. *
- * *
- * This routine is used to control the repair mode for the player. *
- * *
- * INPUT: control -- The mode to set the repair to. *
- * 0 = Turn repair off. *
- * 1 = Turn repair on. *
- * -1= Toggle repair state. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 07/08/1995 JLB : Created. *
- *=============================================================================================*/
- void DisplayClass::Repair_Mode_Control(int control)
- {
- bool mode = IsRepairMode;
- switch (control) {
- case 0:
- mode = false;
- break;
- case -1:
- mode = (IsRepairMode == false);
- break;
- case 1:
- mode = true;
- break;
- }
- if (mode != IsRepairMode && !PendingObject) {
- IsSellMode = false;
- if (mode && PlayerPtr->BScan) {
- IsRepairMode = true;
- Unselect_All();
- } else {
- IsRepairMode = false;
- Revert_Mouse_Shape();
- }
- }
- }
- /***********************************************************************************************
- * DisplayClass::In_View -- Determines if cell is visible on screen. *
- * *
- * Use this routine to determine if the specified cell is visible on *
- * the display. This is a useful fact, since many display operations *
- * can be skipped if the cell is not visible. *
- * *
- * INPUT: cell -- The cell number to check. *
- * *
- * OUTPUT: bool; Is this cell visible on the display? *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 04/30/1994 JLB : Created. *
- * 04/30/1994 JLB : Converted to member function. *
- *=============================================================================================*/
- bool DisplayClass::In_View(register CELL cell)
- {
- COORDINATE coord = Cell_Coord(cell) & 0xFF00FF00L;
- COORDINATE tcoord = TacticalCoord & 0xFF00FF00L;
- if ((Coord_X(coord) - Coord_X(tcoord)) > TacLeptonWidth+255) return(false);
- if ((Coord_Y(coord) - Coord_Y(tcoord)) > TacLeptonHeight+255) return(false);
- return(true);
- #ifdef OBSOLETE
- int fudgex = Coord_XLepton(TacticalCoord) ? -1 : 0;
- int fudgey = Coord_YLepton(TacticalCoord) ? -1 : 0;
- if ((unsigned)(Cell_X(cell)-Coord_XCell(TacticalCoord)) > Lepton_To_Cell(TacLeptonWidth)+fudgex) return(false);
- if ((unsigned)(Cell_Y(cell)-Coord_YCell(TacticalCoord)) > Lepton_To_Cell(TacLeptonHeight)+fudgey) return(false);
- return(true);
- #endif
- #ifdef OBSOLETE
- cell -= TacticalCell;
- if (Cell_X(cell) >= TacWidth + (TacPartialX ? 1 : 0)) return(false);
- if (Cell_Y(cell) >= TacHeight + (TacPartialY ? 1 : 0)) return(false);
- return(true);
- #endif
- }
- COORDINATE DisplayClass::Closest_Free_Spot(COORDINATE coord, bool any) const
- {
- if (coord & 0xC000C000) {
- return(0x00800080);
- }
- return (*this)[Coord_Cell(coord)].Closest_Free_Spot(coord, any);
- }
- bool DisplayClass::Is_Spot_Free(COORDINATE coord) const
- {
- // This doesn't seem right... ST - 12/18/2018 10:09AM
- //if (coord & 0xC000C000) {
- // return(0x00800080);
- //}
- return (*this)[Coord_Cell(coord)].Is_Spot_Free(CellClass::Spot_Index(coord));
- }
- /***********************************************************************************************
- * DisplayClass::Center_Map -- Centers the map about the currently selected objects *
- * *
- * This routine will average the position of all the selected objects and then center *
- * the map about those objects. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: The center coordinate. *
- * *
- * WARNINGS: The map position changes by this routine. *
- * *
- * HISTORY: *
- * 08/22/1995 JLB : Created. *
- *=============================================================================================*/
- COORDINATE DisplayClass::Center_Map(void)
- {
- if (CurrentObject.Count()) {
- unsigned x = 0;
- unsigned y = 0;
- for (int index = 0; index < CurrentObject.Count(); index++) {
- COORDINATE coord = CurrentObject[index]->Center_Coord();
- x += Coord_X(coord);
- y += Coord_Y(coord);
- }
- x /= CurrentObject.Count();
- y /= CurrentObject.Count();
- Set_Tactical_Position(XY_Coord(x - (TacLeptonWidth/2), y - (TacLeptonHeight/2)));
- return XY_Coord(x, y);
- }
- return 0;
- }
- static ActionType _priority_actions[] = {
- ACTION_ATTACK,
- ACTION_ENTER,
- ACTION_REPAIR,
- ACTION_SABOTAGE,
- ACTION_CAPTURE,
- ACTION_MOVE
- };
- static int get_action_priority(ActionType action)
- {
- for (int i = 0; i < sizeof(_priority_actions) / sizeof(_priority_actions[0]); ++i) {
- if (_priority_actions[i] == action) {
- return i;
- }
- }
- return INT_MAX;
- }
- template <typename T>
- static int index_of(const DynamicVectorClass<T*>& list, T* object)
- {
- for (int i = 0; i < list.Count(); i++) {
- if (list[i] == object) {
- return i;
- }
- }
- return -1;
- }
- template <typename T>
- static ObjectClass* Best_Object_With_ActionT(DynamicVectorClass<ObjectClass*>& objects, T subject)
- {
- DynamicVectorClass<const ObjectTypeClass*> checked_types;
- if (objects.Count()) {
- int best_priority = INT_MAX;
- ObjectClass* best_object = objects[0];
- for (int i = 0; i < objects.Count(); ++i) {
- ObjectClass* object = objects[i];
- const ObjectTypeClass* type = &object->Class_Of();
- if (index_of(checked_types, type) != -1) {
- continue;
- }
- checked_types.Add(type);
- ActionType action = object->What_Action(subject);
- int priority = get_action_priority(action);
- if (priority < best_priority) {
- best_priority = priority;
- best_object = object;
- if (best_priority == 0) {
- break;
- }
- }
- }
- return best_object;
- }
- return NULL;
- }
- ObjectClass* Best_Object_With_Action(DynamicVectorClass<ObjectClass*>& objects, ObjectClass* object)
- {
- return Best_Object_With_ActionT(objects, object);
- }
- ObjectClass* Best_Object_With_Action(DynamicVectorClass<ObjectClass*>& objects, CELL cell)
- {
- return Best_Object_With_ActionT(objects, cell);
- }
- ActionType Best_Object_Action(DynamicVectorClass<ObjectClass*>& objects, ObjectClass* object)
- {
- ObjectClass* obj = Best_Object_With_Action(objects, object);
- return (obj != NULL) ? obj->What_Action(object) : ACTION_NONE;
- }
- ActionType Best_Object_Action(DynamicVectorClass<ObjectClass*>& objects, CELL cell)
- {
- ObjectClass* obj = Best_Object_With_Action(objects, cell);
- return (obj != NULL) ? obj->What_Action(cell) : ACTION_NONE;
- }
- ObjectClass* Best_Object_With_Action(ObjectClass* object)
- {
- return Best_Object_With_Action(CurrentObject.Raw(), object);
- }
- ObjectClass* Best_Object_With_Action(CELL cell)
- {
- return Best_Object_With_Action(CurrentObject.Raw(), cell);
- }
- ActionType Best_Object_Action(ObjectClass* object)
- {
- return Best_Object_Action(CurrentObject.Raw(), object);
- }
- ActionType Best_Object_Action(CELL cell)
- {
- return Best_Object_Action(CurrentObject.Raw(), cell);
- }
|