TECHNO.CPP 197 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996
  1. /*
  2. ** Command & Conquer(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /* $Header: F:\projects\c&c\vcs\code\techno.cpv 2.13 02 Aug 1995 17:01:08 JOE_BOSTIC $ */
  19. /***********************************************************************************************
  20. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  21. ***********************************************************************************************
  22. * *
  23. * Project Name : Command & Conquer *
  24. * *
  25. * File Name : BASE.CPP *
  26. * *
  27. * Programmer : Joe L. Bostic *
  28. * *
  29. * Start Date : May 8, 1994 *
  30. * *
  31. * Last Update : August 23, 1995 [JLB] *
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * Functions: *
  35. * TechnoClass::AI -- Handles AI processing for techno object. *
  36. * TechnoClass::Assign_Destination -- Assigns movement destination to the object. *
  37. * TechnoClass::Assign_Target -- Assigns the targeting computer with specified target. *
  38. * TechnoClass::Base_Is_Attacked -- Handle panic response to base being attacked. *
  39. * TechnoClass::Can_Fire -- Determines if this techno object can fire. *
  40. * TechnoClass::Can_Player_Fire -- Determines if the player can give this object a fire order*
  41. * TechnoClass::Can_Player_Move -- Determines if the object can move be moved by player. *
  42. * TechnoClass::Can_Repair -- Determines if the object can and should be repaired. *
  43. * TechnoClass::Captured -- Handles capturing this object. *
  44. * TechnoClass::Clicked_As_Target -- Sets the flash count for this techno object. *
  45. * TechnoClass::Crew_Type -- Fetches the kind of crew this object contains. *
  46. * TechnoClass::Debug_Dump -- Displays the base class data to the monochrome screen. *
  47. * TechnoClass::Desired_Load_Dir -- Fetches loading parameters for this object. *
  48. * TechnoClass::Detach -- Handles removal of target from tracking system. *
  49. * TechnoClass::Do_Cloak -- Start the object into cloaking stage. *
  50. * TechnoClass::Do_Shimmer -- Causes this object to shimmer if it is cloaked. *
  51. * TechnoClass::Do_Uncloak -- Cause the stealth tank to uncloak. *
  52. * TechnoClass::Draw_It -- Draws the health bar (if necessary). *
  53. * TechnoClass::Draw_Pips -- Draws the transport pips and other techno graphics. *
  54. * TechnoClass::Enter_Idle_Mode -- Object enters its default idle condition. *
  55. * TechnoClass::Evaluate_Cell -- Determine the value and object of specified cell. *
  56. * TechnoClass::Evaluate_Object -- Determines score value of specified object. *
  57. * TechnoClass::Exit_Object -- Causes specified object to leave this object. *
  58. * TechnoClass::Find_Docking_Bay -- Searches for a close docking bay. *
  59. * TechnoClass::Find_Exit_Cell -- Finds an appropriate exit cell for this object. *
  60. * TechnoClass::Fire_At -- Fires projectile at target specified. *
  61. * TechnoClass::Fire_Direction -- Fetches the direction projectile fire will take. *
  62. * TechnoClass::Get_Ownable -- Fetches the ownable bits for this object. *
  63. * TechnoClass::Greatest_Threat -- Determines best target given search criteria. *
  64. * TechnoClass::Hidden -- Returns the object back into the hidden state. *
  65. * TechnoClass::In_Range -- Determines if specified target is within weapon range. *
  66. * TechnoClass::In_Range -- Determines if specified target is within weapon range. *
  67. * TechnoClass::In_Range -- Determines if the specified coordinate is within range. *
  68. * TechnoClass::Is_Techno -- Confirms that this is a TechnoClass object. *
  69. * TechnoClass::Is_Weapon_Equipped -- Determines if this object has a combat weapon. *
  70. * TechnoClass::Kill_Cargo -- Destroys any cargo attached to this object. *
  71. * TechnoClass::Mark -- Handles marking of techno objects. *
  72. * TechnoClass::Nearby_Location -- Radiates outward looking for clear cell nearby. *
  73. * TechnoClass::Owner -- Who is the owner of this object? *
  74. * TechnoClass::Per_Cell_Process -- Handles once-per-cell operations for techno type objects.*
  75. * TechnoClass::Pip_Count -- Fetches the number of pips to display on this object. *
  76. * TechnoClass::Player_Assign_Mission -- Assigns a mission as result of player input. *
  77. * TechnoClass::Random_Animate -- Performs some idle animation for the object. *
  78. * TechnoClass::Rearm_Delay -- Calculates the delay before firing can occur. *
  79. * TechnoClass::Receive_Message -- Handles inbound message as appropriate. *
  80. * TechnoClass::Record_The_Kill -- Records the death of this object. *
  81. * TechnoClass::Remap_Table -- Fetches the appropriate remap table to use. *
  82. * TechnoClass::Response_Attack -- Handles the voice response when given attack order. *
  83. * TechnoClass::Response_Move -- Handles the voice repsonse to a movement request. *
  84. * TechnoClass::Response_Select -- Handles the voice response when selected. *
  85. * TechnoClass::Revealed -- Handles revealing an object to the house specified. *
  86. * TechnoClass::Risk -- Fetches the risk associated with this object. *
  87. * TechnoClass::Scatter -- Causes the object to scatter to an adjacent cell. *
  88. * TechnoClass::Select -- Selects object and checks to see if can be selected. *
  89. * TechnoClass::Set_Mission -- Forced mission set (used by editor). *
  90. * TechnoClass::Stun -- Prepares the object for removal from the game. *
  91. * TechnoClass::Take_Damage -- Records damage assessed to this object. *
  92. * TechnoClass::Target_Something_Nearby -- Handles finding and assigning a nearby target. *
  93. * TechnoClass::TechnoClass -- Constructor for techno type objects. *
  94. * TechnoClass::TechnoClass -- Default constructor for techno objects. *
  95. * TechnoClass::Techno_Draw_Object -- General purpose draw object routine. *
  96. * TechnoClass::Threat_Range -- Returns the range to scan based on threat control. *
  97. * TechnoClass::Tiberium_Load -- Fetches the current tiberium load percentage. *
  98. * TechnoClass::Unlimbo -- Performs unlimbo process for all techno type objects. *
  99. * TechnoClass::Value -- Fetches the target value for this object. *
  100. * TechnoClass::Visual_Character -- Determine the visual character of the object. *
  101. * TechnoClass::Weapon_Range -- Determines the maximum range for the weapon. *
  102. * TechnoClass::What_Action -- Determines action to perform if cell is clicked on. *
  103. * TechnoClass::What_Action -- Determines what action to perform if object is selected. *
  104. * TechnoTypeClass::Cost_Of -- Fetches the cost of this object type. *
  105. * TechnoTypeClass::Get_Cameo_Data -- Fetches the cameo image for this object type. *
  106. * TechnoTypeClass::Get_Ownable -- Fetches the ownable bits for this object type. *
  107. * TechnoTypeClass::Max_Passengers -- Fetches the maximum passengers allowed. *
  108. * TechnoTypeClass::Repair_Cost -- Fetches the cost to repair one step. *
  109. * TechnoTypeClass::Repair_Step -- Fetches the health to repair one step. *
  110. * TechnoTypeClass::TechnoTypeClass -- Constructor for techno type objects. *
  111. * TechnoTypeClass::Time_To_Build -- Fetches the time to build this object. *
  112. * TechnoTypeClass::Raw_Cost -- Fetches the raw (base) cost of the object. *
  113. * TechnoClass::Refund_Amount -- Returns with the money to refund if this object is sold. *
  114. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  115. #include "function.h"
  116. /***************************************************************************
  117. ** Cloaking control values.
  118. */
  119. #define MAX_UNCLOAK_STAGE 38
  120. #define UNCLOAK_VIS_TIME (1*TICKS_PER_SECOND)
  121. /***************************************************************************
  122. ** Which shape to use depending on which facing is controlled by these arrays.
  123. */
  124. int const TechnoClass::BodyShape[32] = {0,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1};
  125. /***********************************************************************************************
  126. * TechnoTypeClass::TechnoTypeClass -- Constructor for techno type objects. *
  127. * *
  128. * This is the normal constructor for techno type objects. It is called in the process of *
  129. * constructing all the object type (constant) data for the various techno type objects. *
  130. * *
  131. * INPUT: see below... *
  132. * *
  133. * OUTPUT: none *
  134. * *
  135. * WARNINGS: none *
  136. * *
  137. * HISTORY: *
  138. * 03/19/1995 JLB : Created. *
  139. *=============================================================================================*/
  140. TechnoTypeClass::TechnoTypeClass(
  141. int name,
  142. char const *ininame,
  143. unsigned char level,
  144. long pre,
  145. bool is_leader,
  146. bool is_scanner,
  147. bool is_nominal,
  148. bool is_transporter,
  149. bool is_flammable,
  150. bool is_crushable,
  151. bool is_stealthy,
  152. bool is_selectable,
  153. bool is_legal_target,
  154. bool is_insignificant,
  155. bool is_immune,
  156. bool is_theater,
  157. bool is_twoshooter,
  158. bool is_turret_equipped,
  159. bool is_repairable,
  160. bool is_buildable,
  161. bool is_crew,
  162. int ammo,
  163. unsigned short strength,
  164. MPHType maxspeed,
  165. int sightrange,
  166. int cost,
  167. int scenario,
  168. int risk,
  169. int reward,
  170. int ownable,
  171. WeaponType primary,
  172. WeaponType secondary,
  173. ArmorType armor) :
  174. ObjectTypeClass( true,
  175. is_flammable,
  176. is_crushable,
  177. is_stealthy,
  178. is_selectable,
  179. is_legal_target,
  180. is_insignificant,
  181. is_immune,
  182. name,
  183. ininame,
  184. armor,
  185. strength)
  186. {
  187. Level = level;
  188. Pre = pre;
  189. MaxAmmo = ammo;
  190. MaxSpeed = maxspeed;
  191. CameoData = NULL;
  192. Primary = primary,
  193. Secondary = secondary,
  194. Cost = cost;
  195. IsLeader = is_leader;
  196. IsScanner = is_scanner;
  197. IsTransporter = is_transporter;
  198. IsTwoShooter = is_twoshooter;
  199. IsBuildable = is_buildable;
  200. IsCrew = is_crew;
  201. IsTheater = is_theater;
  202. IsRepairable = is_repairable;
  203. IsTurretEquipped= is_turret_equipped;
  204. IsNominal = is_nominal;
  205. Ownable = ownable;
  206. Reward = reward;
  207. Scenario = scenario;
  208. SightRange = sightrange;
  209. /*
  210. ** Units risk value is based on the type of weapon he has and the
  211. ** rate of fire it shoots at.
  212. */
  213. risk = risk;
  214. Risk = 0;
  215. if (primary != WEAPON_NONE) {
  216. Risk = (Weapons[primary].Attack * (Weapons[primary].Range >> 4)) / Weapons[primary].ROF;
  217. }
  218. }
  219. /***********************************************************************************************
  220. * TechnoTypeClass::Raw_Cost -- Fetches the raw (base) cost of the object. *
  221. * *
  222. * This routine is used to find the underlying cost for this object. The underlying cost *
  223. * does not include any free items that normally come with the object when purchased *
  224. * directly. Example: The raw cost of a refinery is the normal cost minus the cost of a *
  225. * harvester. *
  226. * *
  227. * INPUT: none *
  228. * *
  229. * OUTPUT: Returns with the credit cost of the base object type. *
  230. * *
  231. * WARNINGS: none *
  232. * *
  233. * HISTORY: *
  234. * 08/13/1995 JLB : Created. *
  235. *=============================================================================================*/
  236. int TechnoTypeClass::Raw_Cost(void) const
  237. {
  238. return(Cost);
  239. }
  240. /***********************************************************************************************
  241. * TechnoTypeClass::Get_Ownable -- Fetches the ownable bits for this object type. *
  242. * *
  243. * This routine will return the ownable bits for this object type. The ownable bits are *
  244. * a bitflag composite of the houses that can own (build) this object type. *
  245. * *
  246. * INPUT: none *
  247. * *
  248. * OUTPUT: Returns with the ownable bits for this object type. *
  249. * *
  250. * WARNINGS: none *
  251. * *
  252. * HISTORY: *
  253. * 07/29/1995 JLB : Created. *
  254. *=============================================================================================*/
  255. unsigned short TechnoTypeClass::Get_Ownable(void) const
  256. {
  257. return(Ownable);
  258. }
  259. /***********************************************************************************************
  260. * TechnoTypeClass::Time_To_Build -- Fetches the time to build this object. *
  261. * *
  262. * This routine will return the time it takes to construct this object. Usually the time *
  263. * to produce is directly related to cost. *
  264. * *
  265. * INPUT: none *
  266. * *
  267. * OUTPUT: Returns with the time to produce this object type. The time is expressed in the *
  268. * form of game ticks. *
  269. * *
  270. * WARNINGS: none *
  271. * *
  272. * HISTORY: *
  273. * 07/29/1995 JLB : Created. *
  274. *=============================================================================================*/
  275. int TechnoTypeClass::Time_To_Build(HousesType house) const
  276. {
  277. int cost = Raw_Cost();
  278. /*
  279. ** For computer controlled buildings, slow down production on
  280. ** cheaper buildings.
  281. */
  282. if (!Special.IsDifficult &&
  283. GameToPlay == GAME_NORMAL &&
  284. What_Am_I() == RTTI_BUILDINGTYPE &&
  285. PlayerPtr->Class->House != house) {
  286. cost = (cost + (Special.IsEasy ? 4000 : 2000)) / 2;
  287. }
  288. /*
  289. ** Fudge factor, so that Nod builds a bit faster if the object must be delivered to
  290. ** an airfield.
  291. */
  292. if (What_Am_I() == RTTI_UNITTYPE && !(Ownable & HOUSEF_GOOD)) {
  293. return (cost - (cost/4));
  294. }
  295. return(cost);
  296. }
  297. /***********************************************************************************************
  298. * TechnoTypeClass::Cost_Of -- Fetches the cost of this object type. *
  299. * *
  300. * This routine will return the cost to produce an object of this type. *
  301. * *
  302. * INPUT: none *
  303. * *
  304. * OUTPUT: Returns with the cost to produce one object of this type. *
  305. * *
  306. * WARNINGS: none *
  307. * *
  308. * HISTORY: *
  309. * 07/29/1995 JLB : Created. *
  310. *=============================================================================================*/
  311. int TechnoTypeClass::Cost_Of(void) const
  312. {
  313. return(Cost);
  314. }
  315. /***********************************************************************************************
  316. * TechnoTypeClass::Get_Cameo_Data -- Fetches the cameo image for this object type. *
  317. * *
  318. * This routine will fetch the cameo (sidebar small image) shape of this object type. *
  319. * If there is no cameo data available (typical for non-producable units), then NULL will *
  320. * be returned. *
  321. * *
  322. * INPUT: none *
  323. * *
  324. * OUTPUT: Returns with a pointer to the cameo data for this object type if present. *
  325. * *
  326. * WARNINGS: none *
  327. * *
  328. * HISTORY: *
  329. * 07/29/1995 JLB : Created. *
  330. *=============================================================================================*/
  331. void const * TechnoTypeClass::Get_Cameo_Data(void) const
  332. {
  333. return(CameoData);
  334. }
  335. /***********************************************************************************************
  336. * TechnoTypeClass::Repair_Cost -- Fetches the cost to repair one step. *
  337. * *
  338. * This routine will return the cost to repair one step. At the TechnoTypeClass level, *
  339. * this merely serves as a placeholder function. The derived classes will provide a *
  340. * functional version of this routine. *
  341. * *
  342. * INPUT: none *
  343. * *
  344. * OUTPUT: Returns with the cost to repair one step. *
  345. * *
  346. * WARNINGS: none *
  347. * *
  348. * HISTORY: *
  349. * 07/29/1995 JLB : Created. *
  350. *=============================================================================================*/
  351. int TechnoTypeClass::Repair_Cost(void) const
  352. {
  353. return(0);
  354. }
  355. /***********************************************************************************************
  356. * TechnoTypeClass::Repair_Step -- Fetches the health to repair one step. *
  357. * *
  358. * This routine merely serves as placeholder virtual function. The various type classes *
  359. * will override this routine to return the number of health points to repair in one *
  360. * "step". *
  361. * *
  362. * INPUT: none *
  363. * *
  364. * OUTPUT: Returns with the number of health points to repair in one step. *
  365. * *
  366. * WARNINGS: none *
  367. * *
  368. * HISTORY: *
  369. * 07/29/1995 JLB : Created. *
  370. *=============================================================================================*/
  371. int TechnoTypeClass::Repair_Step(void) const
  372. {
  373. return(0);
  374. }
  375. #ifdef CHEAT_KEYS
  376. /***********************************************************************************************
  377. * TechnoClass::Debug_Dump -- Displays the base class data to the monochrome screen. *
  378. * *
  379. * This routine is used to dump the status of the object class to the monochrome screen. *
  380. * This display can be used to track down or prevent bugs. *
  381. * *
  382. * INPUT: none *
  383. * *
  384. * OUTPUT: none *
  385. * *
  386. * WARNINGS: none *
  387. * *
  388. * HISTORY: *
  389. * 06/02/1994 JLB : Created. *
  390. *=============================================================================================*/
  391. void TechnoClass::Debug_Dump(MonoClass *mono) const
  392. {
  393. mono->Set_Cursor(0,0);mono->Printf("(%04X)p=%d,d=%d", House->Power_Fraction(), House->Power, House->Drain);
  394. // mono->Set_Cursor(0,0);mono->Printf("(%d)", House->Blockage);
  395. mono->Text_Print("X", 16 + (IsALoaner?2:0), 11);
  396. mono->Text_Print("X", 16 + (IsLocked?2:0), 9);
  397. mono->Text_Print("X", 16 + (IsInRecoilState?2:0), 17);
  398. mono->Text_Print("X", 16 + (IsTethered?2:0), 8);
  399. mono->Text_Print("X", 16 + (IsOwnedByPlayer?2:0), 5);
  400. mono->Text_Print("X", 16 + (IsDiscoveredByPlayer?2:0), 6);
  401. // mono->Text_Print("X", 16 + (IsALemon?2:0), 9);
  402. mono->Set_Cursor(28, 7);mono->Printf("%2d", Arm);
  403. mono->Set_Cursor(34, 1);mono->Printf("%04X", TarCom);
  404. mono->Set_Cursor(29, 3);mono->Printf("%02X", PrimaryFacing.Current());
  405. FlasherClass::Debug_Dump(mono);
  406. StageClass::Debug_Dump(mono);
  407. RadioClass::Debug_Dump(mono);
  408. }
  409. #endif
  410. /***********************************************************************************************
  411. * TechnoClass::TechnoClass -- Default constructor for techno objects. *
  412. * *
  413. * This default constructor for techno objects is used to reset all internal variables to *
  414. * their default state. *
  415. * *
  416. * INPUT: none *
  417. * *
  418. * OUTPUT: none *
  419. * *
  420. * WARNINGS: none *
  421. * *
  422. * HISTORY: *
  423. * 12/09/1994 JLB : Created. *
  424. *=============================================================================================*/
  425. TechnoClass::TechnoClass(void) :
  426. TarCom(TARGET_NONE),
  427. House(0)
  428. {
  429. Arm = 0;
  430. Ammo = -1;
  431. PurchasePrice = 0;
  432. IsTickedOff = false;
  433. Cloak = UNCLOAKED;
  434. CloakingDevice.Set_Stage(1);
  435. CloakingDevice.Set_Rate(0);
  436. IsCloakable = false;
  437. IsALemon = false;
  438. IsALoaner = false;
  439. IsDiscoveredByPlayer = false;
  440. IsDiscoveredByComputer = false;
  441. IsInRecoilState = false;
  442. IsLeader = false;
  443. IsLocked = false;
  444. IsOwnedByPlayer = false;
  445. IsSecondShot = true;
  446. IsTethered = false;
  447. SuspendedTarCom = TARGET_NONE;
  448. PrimaryFacing.Set(DIR_N);
  449. }
  450. /***********************************************************************************************
  451. * TechnoClass::Revealed -- Handles revealing an object to the house specified. *
  452. * *
  453. * When a unit moves out from under the shroud or when it gets delivered into already *
  454. * explored terrain, then it must be "revealed". Objects that are revealed may be *
  455. * announced to the player. The discovered bit updated accordingly. *
  456. * *
  457. * INPUT: house -- The house that this object is revealed to. *
  458. * *
  459. * OUTPUT: none *
  460. * *
  461. * WARNINGS: none *
  462. * *
  463. * HISTORY: *
  464. * 06/02/1994 JLB : Created. *
  465. * 12/27/1994 JLB : Discovered trigger event processing. *
  466. *=============================================================================================*/
  467. bool TechnoClass::Revealed(HouseClass * house)
  468. {
  469. if (house == PlayerPtr && IsDiscoveredByPlayer) return(false);
  470. if (house != PlayerPtr && IsDiscoveredByComputer) return(false);
  471. if (RadioClass::Revealed(house)) {
  472. /*
  473. ** An enemy object that is discovered will go into hunt mode if
  474. ** its current mission is to ambush.
  475. */
  476. if (!house->IsHuman && Mission == MISSION_AMBUSH) {
  477. Assign_Mission(MISSION_HUNT);
  478. }
  479. if (house == PlayerPtr) {
  480. if (!IsOwnedByPlayer) {
  481. /*
  482. ** If there is a trigger event associated with this object, then process
  483. ** it for discovery purposes.
  484. */
  485. if (Trigger) {
  486. Trigger->Spring(EVENT_DISCOVERED, this);
  487. }
  488. /*
  489. ** Alert the enemy house to presence of the friendly side.
  490. */
  491. House->IsDiscovered = true;
  492. } else {
  493. /*
  494. ** A newly revealed object will always perform a look operation.
  495. */
  496. if (house == PlayerPtr) IsDiscoveredByPlayer = true;
  497. if (house != PlayerPtr) IsDiscoveredByComputer = true;
  498. Look();
  499. }
  500. }
  501. if (house == PlayerPtr) IsDiscoveredByPlayer = true;
  502. if (house != PlayerPtr) IsDiscoveredByComputer = true;
  503. return(true);
  504. }
  505. return(false);
  506. }
  507. /***********************************************************************************************
  508. * TechnoClass::Hidden -- Returns the object back into the hidden state. *
  509. * *
  510. * This routine is called for every object that returns to the darkness shroud or when *
  511. * it gets destroyed. This also occurs when an object enters another (such as infantry *
  512. * entering a transport helicopter). *
  513. * *
  514. * INPUT: none *
  515. * *
  516. * OUTPUT: none *
  517. * *
  518. * WARNINGS: none *
  519. * *
  520. * HISTORY: *
  521. * 06/02/1994 JLB : Created. *
  522. *=============================================================================================*/
  523. void TechnoClass::Hidden(void)
  524. {
  525. if (!IsDiscoveredByPlayer) return;
  526. if (!House->IsHuman) {
  527. IsDiscoveredByPlayer = false;
  528. }
  529. }
  530. /***********************************************************************************************
  531. * TechnoClass::Mark -- Handles marking of techno objects. *
  532. * *
  533. * On the Techno-level, marking handles transmission of the redraw command to any object *
  534. * that it is 'connected' with. This only occurs during loading and unloading. *
  535. * *
  536. * INPUT: mark -- The marking method. This routine just passes this on to base classes. *
  537. * *
  538. * OUTPUT: none *
  539. * *
  540. * WARNINGS: none *
  541. * *
  542. * HISTORY: *
  543. * 10/17/1994 JLB : Created. *
  544. *=============================================================================================*/
  545. bool TechnoClass::Mark(MarkType mark)
  546. {
  547. if (RadioClass::Mark(mark)) {
  548. /*
  549. ** When redrawing an object, if there is another object teathered to this one,
  550. ** redraw it as well.
  551. */
  552. if (IsTethered) {
  553. Transmit_Message(RADIO_REDRAW);
  554. }
  555. return(true);
  556. }
  557. return(false);
  558. }
  559. /***********************************************************************************************
  560. * TechnoClass::Receive_Message -- Handles inbound message as appropriate. *
  561. * *
  562. * This routine is used to handle inbound radio messages. It only handles those messages *
  563. * that deal with techno objects. Typically, these include loading and unloading. *
  564. * *
  565. * INPUT: from -- Pointer to the originator of the radio message. *
  566. * *
  567. * message -- The inbound radio message. *
  568. * *
  569. * param -- Reference to optional parameter that might be used to transfer *
  570. * more information than is possible with the simple radio message *
  571. * type. *
  572. * *
  573. * OUTPUT: Returns with the radio response. *
  574. * *
  575. * WARNINGS: none *
  576. * *
  577. * HISTORY: *
  578. * 10/17/1994 JLB : Created. *
  579. * 06/17/1995 JLB : Handles tether contact messages. *
  580. *=============================================================================================*/
  581. RadioMessageType TechnoClass::Receive_Message(RadioClass * from, RadioMessageType message, long & param)
  582. {
  583. switch (message) {
  584. /*
  585. ** Just received instructions to attack the specified target.
  586. */
  587. case RADIO_ATTACK_THIS:
  588. if (Techno_Type_Class()->Primary != WEAPON_NONE) {
  589. Assign_Target(param);
  590. Assign_Mission(MISSION_ATTACK);
  591. return(RADIO_ROGER);
  592. }
  593. break;
  594. /*
  595. ** Establish a tethered connection to the object in radio contact.
  596. */
  597. case RADIO_TETHER:
  598. if (!IsTethered) {
  599. IsTethered = true;
  600. Transmit_Message(RADIO_TETHER, from);
  601. return(RADIO_ROGER);
  602. }
  603. break;
  604. /*
  605. ** Break the tethered connection to the object in radio contact.
  606. */
  607. case RADIO_UNTETHER:
  608. if (IsTethered) {
  609. IsTethered = false;
  610. Transmit_Message(RADIO_UNTETHER, from);
  611. return(RADIO_ROGER);
  612. }
  613. break;
  614. /*
  615. ** A teathered unit has reached it's destination. All is
  616. ** clear, so radio contact can be broken.
  617. */
  618. case RADIO_UNLOADED:
  619. Transmit_Message(RADIO_UNTETHER, from);
  620. return(Transmit_Message(RADIO_OVER_OUT, from));
  621. /*
  622. ** When this message is received, it means that the other object
  623. ** has already turned its radio off. Turn this radio off as well.
  624. */
  625. case RADIO_OVER_OUT:
  626. Transmit_Message(RADIO_UNTETHER, from);
  627. RadioClass::Receive_Message(from, message, param);
  628. return(RADIO_ROGER);
  629. /*
  630. ** Request to be informed when unloaded. This message is transmitted
  631. ** by the transport unit to the transported unit as it is about to be
  632. ** unloaded. It is saying, "All is clear. Drive off now."
  633. */
  634. case RADIO_UNLOAD:
  635. case RADIO_BACKUP_NOW:
  636. case RADIO_HOLD_STILL:
  637. Transmit_Message(RADIO_TETHER, from);
  638. RadioClass::Receive_Message(from, message, param);
  639. return(RADIO_ROGER);
  640. /*
  641. ** Handle reloading one ammo point for this unit.
  642. */
  643. case RADIO_RELOAD:
  644. if (Ammo == Techno_Type_Class()->MaxAmmo) return(RADIO_NEGATIVE);
  645. Ammo++;
  646. return(RADIO_ROGER);
  647. /*
  648. ** Handle repair of this unit.
  649. */
  650. case RADIO_REPAIR:
  651. if (/*param > 0 &&*/ Health_Ratio() < 0x0100) {
  652. int cost = Techno_Type_Class()->Repair_Cost();
  653. // int cost = Fixed_To_Cardinal(Techno_Type_Class()->Repair_Cost(), param);
  654. cost = MAX(cost, 1);
  655. int step = Techno_Type_Class()->Repair_Step();
  656. // int step = Fixed_To_Cardinal(Techno_Type_Class()->Repair_Step(), param);
  657. step = MAX(step, 1);
  658. if (House->Available_Money() >= cost) {
  659. #ifdef OBSOLETE
  660. if (Health_Ratio() >= 0x0100) {
  661. Strength = Class_Of().MaxStrength;
  662. from->Scatter(true);
  663. return(RADIO_NEGATIVE);
  664. }
  665. #endif
  666. House->Spend_Money(cost);
  667. Strength += step;
  668. return(RADIO_ROGER);
  669. }
  670. }
  671. break;
  672. default:
  673. break;
  674. }
  675. return(RadioClass::Receive_Message(from, message, param));
  676. }
  677. /***********************************************************************************************
  678. * TechnoClass::TechnoClass -- Constructor for techno type objects. *
  679. * *
  680. * This constructor sets the owner of this object and its strength. Any object not owned *
  681. * by the player is marked as a loaner. This is a special flag that indicates off-map *
  682. * movement is allowed. The flag is cleared when the object finally enters the map. *
  683. * *
  684. * INPUT: house -- The house (owner) of this object. *
  685. * *
  686. * strength -- The strength to assign to this object. *
  687. * *
  688. * OUTPUT: none *
  689. * *
  690. * WARNINGS: none *
  691. * *
  692. * HISTORY: *
  693. * 10/17/1994 JLB : Created. *
  694. *=============================================================================================*/
  695. TechnoClass::TechnoClass(HousesType house) :
  696. House(HouseClass::As_Pointer(house)),
  697. TarCom(TARGET_NONE)
  698. {
  699. Arm = 0;
  700. Ammo = -1;
  701. PurchasePrice = 0;
  702. IsTickedOff = false;
  703. Cloak = UNCLOAKED;
  704. CloakingDevice.Set_Stage(1);
  705. CloakingDevice.Set_Rate(0);
  706. IsCloakable = false;
  707. IsALemon = false;
  708. IsALoaner = false;
  709. IsDiscoveredByComputer = false;
  710. IsOwnedByPlayer = (house == PlayerPtr->Class->House);
  711. IsDiscoveredByPlayer = false;
  712. IsInRecoilState = false;
  713. IsLeader = false;
  714. IsLocked = false;
  715. IsSecondShot = false;
  716. IsTethered = false;
  717. SuspendedTarCom = TARGET_NONE;
  718. PrimaryFacing.Set(DIR_N);
  719. /*
  720. ** There is a chance that a vehicle will be a "lemon".
  721. */
  722. if (Random_Pick(0, 255) < House->Class->Lemon) {
  723. IsALemon = true;
  724. }
  725. }
  726. /***********************************************************************************************
  727. * TechnoClass::Per_Cell_Process -- Handles once-per-cell operations for techno type objects. *
  728. * *
  729. * This routine handles marking a game object as not a loaner. It is set only if the unit *
  730. * is not player owned and is on the regular map. This is necessary so that enemy objects *
  731. * can exist off-map but as soon as they move onto the map, are flagged so that can never *
  732. * leave it again. *
  733. * *
  734. * INPUT: none *
  735. * *
  736. * OUTPUT: none *
  737. * *
  738. * WARNINGS: none *
  739. * *
  740. * HISTORY: *
  741. * 10/17/1994 JLB : Created. *
  742. * 10/26/94 JLB : Handles scanner units. *
  743. * 12/27/1994 JLB : Checks for an processes any trigger in cell. *
  744. *=============================================================================================*/
  745. void TechnoClass::Per_Cell_Process(bool )
  746. {
  747. CELL cell = Coord_Cell(Center_Coord());
  748. /*
  749. ** When enemy units enter the proper map area from off map, they are
  750. ** flagged so that they won't travel back off the map again.
  751. */
  752. if (Map.In_Radar(cell)) {
  753. if (What_Am_I() == RTTI_UNIT) {
  754. UnitClass * u = (UnitClass *)this;
  755. if (*u != UNIT_HOVER && *u != UNIT_GUNBOAT) {
  756. IsLocked = true;
  757. }
  758. } else {
  759. IsLocked = true;
  760. }
  761. }
  762. /*
  763. ** If this object somehow moves into mapped terrain, but is not yet
  764. ** discovered, then flag it to be discovered.
  765. */
  766. if (!IsDiscoveredByPlayer && Map[cell].IsVisible) {
  767. Revealed(PlayerPtr);
  768. }
  769. }
  770. /***********************************************************************************************
  771. * TechnoClass::Draw_It -- Draws the health bar (if necessary). *
  772. * *
  773. * This routine will draw the common elements for techno type objects. This element is *
  774. * the health bar. The main game object has already been rendered by the time this *
  775. * routine is called. *
  776. * *
  777. * INPUT: x,y -- The coordinate of the center of the unit. *
  778. * *
  779. * OUTPUT: none *
  780. * *
  781. * WARNINGS: none *
  782. * *
  783. * HISTORY: *
  784. * 10/17/1994 JLB : Created. *
  785. * 10/26/94 JLB : Knows about radar scanned cells. *
  786. * 12/13/1994 JLB : Clips health bar against map edge. *
  787. * 01/23/1995 JLB : Dynamic selected object rectangle. *
  788. *=============================================================================================*/
  789. void TechnoClass::Draw_It(int x, int y, WindowNumberType window)
  790. {
  791. Clear_Redraw_Flag();
  792. if (IsSelected || Special.IsBarOn) {
  793. GraphicViewPortClass draw_window( LogicPage->Get_Graphic_Buffer(),
  794. WindowList[window][WINDOWX] << 3 + LogicPage->Get_XPos(),
  795. WindowList[window][WINDOWY] + LogicPage->Get_YPos(),
  796. WindowList[window][WINDOWWIDTH] << 3,
  797. WindowList[window][WINDOWHEIGHT]);
  798. /*
  799. ** The infantry select box should be a bit higher than normal.
  800. */
  801. if (What_Am_I() == RTTI_INFANTRY) {
  802. y -= 6;
  803. }
  804. if (What_Am_I() == RTTI_BUILDING && ((BuildingTypeClass const &)Class_Of()).Type == STRUCT_BARRACKS) {
  805. y -= 5;
  806. }
  807. /*
  808. ** Fetch the dimensions of the object. These dimensions will be used to draw
  809. ** the selection box and the health bar.
  810. */
  811. int width,height;
  812. Class_Of().Dimensions(width, height);
  813. if (Strength && (House->Is_Ally(PlayerPtr) || Special.IsHealthBar)) {
  814. unsigned ratio = Health_Ratio();
  815. int pwidth; // Pixel width of bar interior.
  816. int color; // The color to give the interior of the bargraph.
  817. int xx = x-width/2;
  818. int yy = y-(height/2);
  819. /*
  820. ** Draw the outline of the bargraph.
  821. */
  822. draw_window.Remap(xx+1, yy+1, width-1, 3-1, Map.FadingShade);
  823. draw_window.Draw_Rect(xx, yy, xx+width-1, yy+3, BLACK);
  824. /*
  825. ** Determine the width of the interior strength
  826. ** graph.
  827. */
  828. pwidth = Fixed_To_Cardinal(width-2, ratio);
  829. pwidth = Bound(pwidth, 1, width-2);
  830. color = LTGREEN;
  831. if (ratio < 0x7F) {
  832. color = YELLOW;
  833. }
  834. if (ratio < 0x3F) {
  835. color = RED;
  836. }
  837. draw_window.Fill_Rect(xx+1, yy+1, xx+pwidth, yy+(3-1), color);
  838. }
  839. /*
  840. ** Draw the selected object graphic.
  841. */
  842. if (IsSelected) {
  843. int lx = width/2;
  844. int ly = height/2;
  845. int dx = width/5;
  846. int dy = height/5;
  847. int fudge = (House->Is_Ally(PlayerPtr) || Special.IsHealthBar) ? 4 : 0;
  848. // Upper left corner.
  849. draw_window.Draw_Line(x-lx, fudge+y-ly, x-lx+dx, fudge+y-ly, WHITE);
  850. draw_window.Draw_Line(x-lx, fudge+y-ly, x-lx, fudge+y-ly+dy, WHITE);
  851. // Upper right corner.
  852. draw_window.Draw_Line(x+lx, fudge+y-ly, x+lx-dx, fudge+y-ly, WHITE);
  853. draw_window.Draw_Line(x+lx, fudge+y-ly, x+lx, fudge+y-ly+dy, WHITE);
  854. // Lower right corner.
  855. draw_window.Draw_Line(x+lx, y+ly, x+lx-dx, y+ly, WHITE);
  856. draw_window.Draw_Line(x+lx, y+ly, x+lx, y+ly-dy, WHITE);
  857. // Lower left corner.
  858. draw_window.Draw_Line(x-lx, y+ly, x-lx+dx, y+ly, WHITE);
  859. draw_window.Draw_Line(x-lx, y+ly, x-lx, y+ly-dy, WHITE);
  860. if (House->Is_Ally(PlayerPtr)) {
  861. Draw_Pips((x-lx)+5, y+ly-3, window);
  862. }
  863. }
  864. }
  865. }
  866. /***********************************************************************************************
  867. * TechnoClass::Unlimbo -- Performs unlimbo process for all techno type objects. *
  868. * *
  869. * This routine handles the common operation between techno objects when they are *
  870. * unlimboed. This includes revealing the map. *
  871. * *
  872. * INPUT: coord -- The coordinate to unlimbo object at. *
  873. * *
  874. * dir (optional) -- initial facing direction for this object *
  875. * *
  876. * OUTPUT: bool; Was the unlimbo successful? *
  877. * *
  878. * WARNINGS: none *
  879. * *
  880. * HISTORY: *
  881. * 11/14/1994 JLB : Created. *
  882. *=============================================================================================*/
  883. bool TechnoClass::Unlimbo(COORDINATE coord, DirType dir)
  884. {
  885. if (RadioClass::Unlimbo(coord, dir)) {
  886. PrimaryFacing = dir;
  887. Enter_Idle_Mode(true);
  888. Commence();
  889. IsLocked = Map.In_Radar(Coord_Cell(coord));
  890. return(true);
  891. }
  892. return(false);
  893. }
  894. /***********************************************************************************************
  895. * TechnoClass::In_Range -- Determines if specified target is within weapon range. *
  896. * *
  897. * This routine is used to compare the distance to the specified target with the range *
  898. * of the weapon. If the target is outside of weapon range, then false is returned. *
  899. * *
  900. * INPUT: target -- The target to check if it is within weapon range. *
  901. * *
  902. * which -- Which weapon to use in determining range. 0=primary, 1=secondary. *
  903. * *
  904. * OUTPUT: bool; Is the specified target within weapon range? *
  905. * *
  906. * WARNINGS: none *
  907. * *
  908. * HISTORY: *
  909. * 11/14/1994 JLB : Created. *
  910. *=============================================================================================*/
  911. bool TechnoClass::In_Range(TARGET target, int which) const
  912. {
  913. if (IsLocked && Target_Legal(target)) {
  914. int range = Weapon_Range(which);
  915. BuildingClass const * building = As_Building(target);
  916. if (building) {
  917. range += ((building->Class->Width() + building->Class->Height()) * (ICON_LEPTON_W / 4));
  918. }
  919. if (::Distance(Fire_Coord(which), As_Coord(target)) <= range) {
  920. return(true);
  921. }
  922. }
  923. return(false);
  924. }
  925. /***********************************************************************************************
  926. * TechnoClass::In_Range -- Determines if specified target is within weapon range. *
  927. * *
  928. * This routine will determine if the pointer to the target object passed into this *
  929. * routine is within weapon range. *
  930. * *
  931. * INPUT: target -- Pointer to the target object to check if within weapon range. *
  932. * *
  933. * which -- Which weapon to use in determining range. 0=primary, 1=secondary. *
  934. * *
  935. * OUTPUT: bool; Is the target within weapon range? *
  936. * *
  937. * WARNINGS: none *
  938. * *
  939. * HISTORY: *
  940. * 11/14/1994 JLB : Created. *
  941. *=============================================================================================*/
  942. bool TechnoClass::In_Range(ObjectClass const * target, int which) const
  943. {
  944. if (IsLocked && target) {
  945. int range = Weapon_Range(which);
  946. if (target->What_Am_I() == RTTI_BUILDING) {
  947. BuildingClass const * building = (BuildingClass const *)target;
  948. range += ((building->Class->Width() + building->Class->Height()) * (ICON_LEPTON_W / 4));
  949. }
  950. if (::Distance(Fire_Coord(which), target->Center_Coord()) <= range) {
  951. return(true);
  952. }
  953. }
  954. return(false);
  955. }
  956. /***********************************************************************************************
  957. * TechnoClass::In_Range -- Determines if the specified coordinate is within range. *
  958. * *
  959. * Use this routine to determine if the specified coordinate is within weapon range. *
  960. * *
  961. * INPUT: coord -- The coordinate to examine against the object to determine range. *
  962. * *
  963. * which -- The weapon to consider when determining range. 0=primary, 1=secondary. *
  964. * *
  965. * OUTPUT: bool; Is the weapon within range? *
  966. * *
  967. * WARNINGS: none *
  968. * *
  969. * HISTORY: *
  970. * 03/16/1995 JLB : Created. *
  971. *=============================================================================================*/
  972. bool TechnoClass::In_Range(COORDINATE coord, int which) const
  973. {
  974. return(IsLocked && ::Distance(Fire_Coord(which), coord) <= Weapon_Range(which));
  975. }
  976. /***********************************************************************************************
  977. * TechnoClass::Evaluate_Object -- Determines score value of specified object. *
  978. * *
  979. * This routine is used to determing the score value (value as a potential target) of the *
  980. * object specified. This routine will check the specified object for all the various *
  981. * legality checks that threat scanning requires. This is the main workhorse routine for *
  982. * target searching. *
  983. * *
  984. * INPUT: method -- The threat method requested. This is a combined bitflag value that *
  985. * not only specified the kind of targets to consider, but how far away *
  986. * they are allowed to be. *
  987. * *
  988. * mask -- This is an RTTI mask to use for quickly eliminating object types. *
  989. * The mask is created outside of this routine because this routine is *
  990. * usually called from within a loop and this value is constant in that *
  991. * context. *
  992. * *
  993. * range -- The range at which potential target objects are rejected. *
  994. * 0 = must be within weapon range. *
  995. * >0 = must be within this lepton distance. *
  996. * <0 = range doesn't matter. *
  997. * *
  998. * object -- Pointer to the object itself. *
  999. * *
  1000. * value -- Reference to the value variable that this routine will fill in. The *
  1001. * higher the value the more likely this object will be selected as best. *
  1002. * *
  1003. * OUTPUT: Did the target pass all legality checks? If this value is returned true, then the *
  1004. * value parameter will be filled in correctly. *
  1005. * *
  1006. * WARNINGS: This routine is time consuming. Don't call unless necessary. *
  1007. * *
  1008. * HISTORY: *
  1009. * 06/30/1995 JLB : Created. *
  1010. * 07/14/1995 JLB : Forces SAM site to not fire on landed aircraft. *
  1011. *=============================================================================================*/
  1012. bool TechnoClass::Evaluate_Object(ThreatType method, int mask, int range, TechnoClass const * object, int & value) const
  1013. {
  1014. /*
  1015. ** An object in limbo can never be a valid target.
  1016. */
  1017. if (object->IsInLimbo) return(false);
  1018. /*
  1019. ** Friendly units are never considered a good target. Bail if this
  1020. ** object is a friend.
  1021. */
  1022. if (House->Is_Ally(object)) return(false);
  1023. /*
  1024. ** If the object is farther away than allowed, bail.
  1025. */
  1026. int dist = Distance(object);
  1027. if (range > 0 && dist > range) return(false);
  1028. if (range == 0 && !In_Range(object, 0) && !In_Range(object, 1)) return(false);
  1029. /*
  1030. ** If the object is not visible, then bail. Human controled units
  1031. ** are always considered to be visible.
  1032. */
  1033. if (!object->IsOwnedByPlayer && !object->IsDiscoveredByPlayer && GameToPlay == GAME_NORMAL && object->What_Am_I() != RTTI_AIRCRAFT) {
  1034. return(false);
  1035. }
  1036. /*
  1037. ** Quickly eliminate all unit types that are not allowed according to the mask
  1038. ** value.
  1039. */
  1040. RTTIType otype = object->What_Am_I();
  1041. if (!((1 << otype) & mask)) return(false); // Mask failure.
  1042. /*
  1043. ** If the object is cloaked, then it isn't a legal target.
  1044. */
  1045. if (object->Cloak == CLOAKED) return(false);
  1046. /*
  1047. ** Determine if the target is theoretically allowed to be a target. If
  1048. ** not, then bail.
  1049. */
  1050. TechnoTypeClass const * tclass = object->Techno_Type_Class();
  1051. if (!tclass->IsLegalTarget) return(false); // Legality failure.
  1052. /*
  1053. ** Never consider agent Delphi a valid target.
  1054. */
  1055. if (otype == RTTI_INFANTRY && ((InfantryTypeClass const *)tclass)->Type == INFANTRY_DELPHI) {
  1056. return(false);
  1057. }
  1058. /*
  1059. ** Special case so that SAM site doesn't fire on aircraft that are landed.
  1060. */
  1061. if (otype == RTTI_AIRCRAFT && What_Am_I() == RTTI_BUILDING && *((BuildingClass *)this) == STRUCT_SAM) {
  1062. if (((AircraftClass *)object)->Altitude == 0) return(false);
  1063. }
  1064. /*
  1065. ** If only allowed to attack civilians, then eliminate all other types.
  1066. */
  1067. if ((method & THREAT_CIVILIANS) && object->Owner() != HOUSE_NEUTRAL) {
  1068. return(false);
  1069. }
  1070. /*
  1071. ** If the scan is limited to capturable buildings only, then bail if the examined
  1072. ** object isn't a capturable building.
  1073. */
  1074. if ((method & THREAT_CAPTURE) && (otype != RTTI_BUILDING || !((BuildingTypeClass const *)tclass)->IsCaptureable)) {
  1075. return(false);
  1076. }
  1077. /*
  1078. ** If not allowed to attack boats, then eliminate them from consideration.
  1079. */
  1080. if (!(method & THREAT_BOATS) &&
  1081. otype == RTTI_UNIT &&
  1082. (((UnitTypeClass const *)tclass)->Speed == SPEED_HOVER || ((UnitTypeClass const *)tclass)->Speed == SPEED_FLOAT)) {
  1083. return(false);
  1084. }
  1085. /*
  1086. ** SPECIAL CASE: Friendly units won't automatically fire on buildings
  1087. ** if the building is not aggressive.
  1088. */
  1089. if (House->IsHuman && otype == RTTI_BUILDING && tclass->Primary == WEAPON_NONE) return(false);
  1090. /*
  1091. ** If the search is restricted to Tiberium processing objects, then
  1092. ** perform the special qualification check now.
  1093. */
  1094. if (method & THREAT_TIBERIUM) {
  1095. switch (otype) {
  1096. case RTTI_UNIT:
  1097. if (!((UnitTypeClass const *)tclass)->IsToHarvest) return(false);
  1098. break;
  1099. case RTTI_BUILDING:
  1100. if (!((BuildingTypeClass const *)tclass)->Capacity) return(false);
  1101. break;
  1102. default:
  1103. return(false);
  1104. }
  1105. }
  1106. /*
  1107. ** If this target value is better than the previously recorded best
  1108. ** target value then record this target for possible return as the
  1109. ** best target available.
  1110. */
  1111. int rawval = object->Value();
  1112. value = rawval + object->Kills;
  1113. #ifdef ADVANCED
  1114. /*
  1115. ** Lessen threat as a factor of distance.
  1116. */
  1117. if (rawval) {
  1118. value = (value * 32000) / (((dist/ICON_LEPTON_W)*(dist/ICON_LEPTON_W))+1);
  1119. //value = Fixed_To_Cardinal(value, Cardinal_To_Fixed(MAP_CELL_W*2, (MAP_CELL_W*2) - (dist/ICON_LEPTON_W)));
  1120. //value = MAX(value, 2);
  1121. if (value < MAP_CELL_W*2) value = dist/ICON_LEPTON_W;
  1122. value = MAX(value, 1);
  1123. return(true);
  1124. }
  1125. value = 0;
  1126. return(false);
  1127. #else
  1128. /*
  1129. ** Lessen threat as a factor of distance.
  1130. */
  1131. int modifier = dist;
  1132. int crange = range / ICON_LEPTON_W;
  1133. if (crange) modifier /= crange;
  1134. if (modifier) value /= modifier;
  1135. if (rawval) {
  1136. value = MAX(value, 2);
  1137. }
  1138. return(true);
  1139. #endif
  1140. }
  1141. /***********************************************************************************************
  1142. * TechnoClass::Evaluate_Cell -- Determine the value and object of specified cell. *
  1143. * *
  1144. * This routine will examine the specified cell and return with the potential target *
  1145. * object it contains and the value of it. Use this routine when searching for threats. *
  1146. * *
  1147. * INPUT: method -- The scan method to use for target searching. *
  1148. * *
  1149. * mask -- Prebuilt mask of object RTTI types acceptable for scanning. *
  1150. * *
  1151. * range -- Scan range limit to use for elimination purposes. This ensures that *
  1152. * objects in the "corner" of a square scan get properly discarded. *
  1153. * *
  1154. * object -- Pointer to object pointer to be filled in with the object at this *
  1155. * cell as a valid target. *
  1156. * *
  1157. * value -- Reference to the value of the object in this cell. It will be set *
  1158. * according to the object's value. *
  1159. * *
  1160. * OUTPUT: Was a valid potential target found in this cell? *
  1161. * *
  1162. * WARNINGS: none *
  1163. * *
  1164. * HISTORY: *
  1165. * 06/19/1995 JLB : Created. *
  1166. *=============================================================================================*/
  1167. bool TechnoClass::Evaluate_Cell(ThreatType method, int mask, CELL cell, int range, TechnoClass const * * object, int & value) const
  1168. {
  1169. *object = NULL;
  1170. value = 0;
  1171. /*
  1172. ** If the cell is not on the legal map, then always ignore it.
  1173. */
  1174. if (cell & 0xF000) return(false);
  1175. if (!Map.In_Radar(cell)) return(false);
  1176. /*
  1177. ** Fetch the techno object from the cell. If there is no
  1178. ** techno object there, then bail.
  1179. */
  1180. CellClass * cellptr = &Map[cell];
  1181. TechnoClass const * tentative = (TechnoClass const *)cellptr->Cell_Occupier();
  1182. while (tentative) {
  1183. if (tentative->Is_Techno() && !House->Is_Ally(tentative)) break;
  1184. tentative = (TechnoClass const *)tentative->Next;
  1185. }
  1186. if (!tentative) return(false);
  1187. // if (!tentative->Is_Techno()) return(false);
  1188. *object = tentative;
  1189. return(Evaluate_Object(method, mask, range, tentative, value));
  1190. }
  1191. /***********************************************************************************************
  1192. * TechnoClass::Greatest_Threat -- Determines best target given search criteria. *
  1193. * *
  1194. * This routine will scan game objects looking for the best target. It is used by the *
  1195. * general target searching processes. The type of target scan to perform is controlled *
  1196. * by the method control parameter. *
  1197. * *
  1198. * INPUT: method -- The method control parameter is used to control the type of target *
  1199. * scan performed. It consists of a series of bit flags (see ThreatType) *
  1200. * that are combined to form the target scan desired. *
  1201. * *
  1202. * OUTPUT: Returns the target value of a suitable target. If no target was found then the *
  1203. * value TARGET_NONE is returned. *
  1204. * *
  1205. * WARNINGS: none *
  1206. * *
  1207. * HISTORY: *
  1208. * 11/14/1994 JLB : Created. *
  1209. * 06/20/1995 JLB : Greatly optimized scan method. *
  1210. *=============================================================================================*/
  1211. TARGET TechnoClass::Greatest_Threat(ThreatType method) const
  1212. {
  1213. ObjectClass const * bestobject = NULL;
  1214. int bestval = -1;
  1215. /*
  1216. ** Build a quick elimination mask. If the RTTI of the object doesn't
  1217. ** qualify with this mask, then we KNOW that it shouldn't be considered.
  1218. */
  1219. int mask = 0;
  1220. if (method & THREAT_CIVILIANS) mask |= ((1 << RTTI_BUILDING) | (1 << RTTI_INFANTRY) | (1 << RTTI_UNIT));
  1221. if (method & THREAT_AIR) mask |= (1 << RTTI_AIRCRAFT);
  1222. if (method & THREAT_CAPTURE) mask |= (1 << RTTI_BUILDING);
  1223. if (method & THREAT_BUILDINGS) mask |= (1 << RTTI_BUILDING);
  1224. if (method & THREAT_INFANTRY) mask |= (1 << RTTI_INFANTRY);
  1225. if (method & THREAT_VEHICLES) mask |= (1 << RTTI_UNIT);
  1226. /*
  1227. ** Limit area target scans use a method where the actual map cells are
  1228. ** examined for occupants. The occupant is then examined in turn. The
  1229. ** best target within the area is returned as a target.
  1230. */
  1231. if (method & (THREAT_AREA|THREAT_RANGE)) {
  1232. int range = Threat_Range((method & THREAT_RANGE) ? 0 : 1);
  1233. // int range = MAX(Weapon_Range(0), Weapon_Range(1));
  1234. // if (!(method & THREAT_RANGE)) range *= 2;
  1235. // range = Bound(range, 0x0100, 0x1400); // Limit maximum scan distance.
  1236. int crange = range / ICON_LEPTON_W;
  1237. if (range == 0) {
  1238. crange = MAX(Weapon_Range(0), Weapon_Range(1)) / ICON_LEPTON_W;
  1239. crange++;
  1240. }
  1241. CELL cell = Coord_Cell(Fire_Coord(0));
  1242. // CELL cell = Coord_Cell(Center_Coord());
  1243. /*
  1244. ** If aircraft are a legal target, then scan through all of them at this time.
  1245. ** Scanning by cell is not possible for aircraft since they are not recorded
  1246. ** at the cell level.
  1247. */
  1248. if (method & THREAT_AIR) {
  1249. for (int index = 0; index < Aircraft.Count(); index++) {
  1250. TechnoClass * object = Aircraft.Ptr(index);
  1251. int value = 0;
  1252. if (Evaluate_Object(method, mask, range, object, value)) {
  1253. if (value > bestval) {
  1254. bestobject = object;
  1255. bestval = value;
  1256. }
  1257. }
  1258. }
  1259. }
  1260. /*
  1261. ** When scanning the ground, always consider landed aircraft as a valid
  1262. ** potential target. This is only true if vehicles are considered a
  1263. ** valid target. A landed aircraft is considered a vehicle.
  1264. */
  1265. if (method & THREAT_VEHICLES) {
  1266. mask |= (1 << RTTI_AIRCRAFT);
  1267. }
  1268. /*
  1269. ** Radiate outward from the object's location, looking for the best
  1270. ** target.
  1271. */
  1272. TechnoClass const * object;
  1273. int value;
  1274. for (int radius = 1; radius < crange; radius++) {
  1275. /*
  1276. ** Scan the top and bottom rows of the "box".
  1277. */
  1278. for (int x = -radius; x <= radius; x++) {
  1279. CELL newcell;
  1280. if ((Cell_X(cell) + x) < Map.MapCellX) continue;
  1281. if ((Cell_X(cell) + x) >= (Map.MapCellX+Map.MapCellWidth)) continue;
  1282. if ((Cell_Y(cell) - radius) >= Map.MapCellY) {
  1283. newcell = XY_Cell(Cell_X(cell) + x, Cell_Y(cell)-radius);
  1284. if (Evaluate_Cell(method, mask, newcell, range, &object, value)) {
  1285. if (bestval < value) {
  1286. bestobject = object;
  1287. }
  1288. }
  1289. }
  1290. if ((Cell_Y(cell) + radius) < (Map.MapCellY+Map.MapCellHeight)) {
  1291. newcell = XY_Cell(Cell_X(cell)+x, Cell_Y(cell)+radius);
  1292. if (Evaluate_Cell(method, mask, newcell, range, &object, value)) {
  1293. if (bestval < value) {
  1294. bestobject = object;
  1295. }
  1296. }
  1297. }
  1298. }
  1299. /*
  1300. ** Scan the left and right columns of the "box".
  1301. */
  1302. for (int y = -(radius-1); y < radius; y++) {
  1303. CELL newcell;
  1304. if ((Cell_Y(cell) + y) < Map.MapCellY) continue;
  1305. if ((Cell_Y(cell) + y) >= (Map.MapCellY+Map.MapCellHeight)) continue;
  1306. if ((Cell_X(cell) - radius) >= Map.MapCellX) {
  1307. newcell = XY_Cell(Cell_X(cell)-radius, Cell_Y(cell)+y);
  1308. if (Evaluate_Cell(method, mask, newcell, range, &object, value)) {
  1309. if (bestval < value) {
  1310. bestobject = object;
  1311. }
  1312. }
  1313. }
  1314. if ((Cell_X(cell) + radius) < (Map.MapCellX+Map.MapCellWidth)) {
  1315. newcell = XY_Cell(Cell_X(cell)+radius, Cell_Y(cell)+y);
  1316. if (Evaluate_Cell(method, mask, newcell, range, &object, value)) {
  1317. if (bestval < value) {
  1318. bestobject = object;
  1319. }
  1320. }
  1321. }
  1322. }
  1323. /*
  1324. ** Bail early if a target has already been found and the range is at
  1325. ** one of the breaking points (i.e., normal range or range * 2).
  1326. */
  1327. if (bestobject) {
  1328. if (radius == crange/4) {
  1329. return(bestobject->As_Target());
  1330. }
  1331. if (radius == crange/2) {
  1332. return(bestobject->As_Target());
  1333. }
  1334. }
  1335. }
  1336. } else {
  1337. /*
  1338. ** A full map scan was requested. First scan through aircraft. The top map layer
  1339. ** is NOT scanned since that layer will probably contain more bullets and animations
  1340. ** than aircraft.
  1341. */
  1342. for (int index = 0; index < Aircraft.Count(); index++) {
  1343. TechnoClass * object = Aircraft.Ptr(index);
  1344. int value = 0;
  1345. if (Evaluate_Object(method, mask, -1, object, value)) {
  1346. if (value > bestval) {
  1347. bestobject = object;
  1348. bestval = value;
  1349. }
  1350. }
  1351. }
  1352. /*
  1353. ** Now scan through the entire ground layer. This is painful, but what other
  1354. ** choice is there?
  1355. */
  1356. for (index = 0; index < Map.Layer[LAYER_GROUND].Count(); index++) {
  1357. ObjectClass const * object = Map.Layer[LAYER_GROUND][index];
  1358. int value = 0;
  1359. if (object->Is_Techno() && Evaluate_Object(method, mask, -1, (TechnoClass const *)object, value)) {
  1360. if (value > bestval) {
  1361. bestobject = object;
  1362. bestval = value;
  1363. }
  1364. }
  1365. }
  1366. }
  1367. /*
  1368. ** If a good target object was found, then return with the target value
  1369. ** of it.
  1370. */
  1371. if (bestobject) {
  1372. return(bestobject->As_Target());
  1373. }
  1374. return(TARGET_NONE);
  1375. }
  1376. /***********************************************************************************************
  1377. * TechnoClass::Owner -- Who is the owner of this object? *
  1378. * *
  1379. * Use this routine to examine this object and return who the owner is. *
  1380. * *
  1381. * INPUT: none *
  1382. * *
  1383. * OUTPUT: Returns with the house number of the owner of this object. *
  1384. * *
  1385. * WARNINGS: none *
  1386. * *
  1387. * HISTORY: *
  1388. * 12/09/1994 JLB : Created. *
  1389. *=============================================================================================*/
  1390. HousesType TechnoClass::Owner(void) const
  1391. {
  1392. return(House->Class->House);
  1393. }
  1394. /***********************************************************************************************
  1395. * TechnoClass::Clicked_As_Target -- Sets the flash count for this techno object. *
  1396. * *
  1397. * Use this routine to set the flash count for the object. This flash count is the number *
  1398. * of times the object will "flash". Typically it is called as a result of the player *
  1399. * clicking on this object in order to make it the target of a move or attack. *
  1400. * *
  1401. * INPUT: count -- The number of times the object should flash. *
  1402. * *
  1403. * OUTPUT: none *
  1404. * *
  1405. * WARNINGS: none *
  1406. * *
  1407. * HISTORY: *
  1408. * 12/09/1994 JLB : Created. *
  1409. *=============================================================================================*/
  1410. void TechnoClass::Clicked_As_Target(int count)
  1411. {
  1412. FlashCount = count;
  1413. }
  1414. /***********************************************************************************************
  1415. * TechnoClass::AI -- Handles AI processing for techno object. *
  1416. * *
  1417. * This routine handles AI processing for techno objects. Typically, this merely dispatches *
  1418. * to the appropriate AI routines for the base classes. *
  1419. * *
  1420. * INPUT: none *
  1421. * *
  1422. * OUTPUT: none *
  1423. * *
  1424. * WARNINGS: Make sure that this routine is only called ONCE per game tick. *
  1425. * *
  1426. * HISTORY: *
  1427. * 12/09/1994 JLB : Created. *
  1428. *=============================================================================================*/
  1429. void TechnoClass::AI(void)
  1430. {
  1431. CargoClass::AI();
  1432. RadioClass::AI();
  1433. DoorClass::AI();
  1434. /*
  1435. ** Handle decision to re-cloak here. Process the cloaking/decloaking operation.
  1436. */
  1437. if (IsCloakable) {
  1438. /*
  1439. ** If this object is uncloaked, but it can be cloaked and it thinks that it
  1440. ** is a good time do so, then begin cloaking.
  1441. */
  1442. if (Cloak == UNCLOAKED) {
  1443. if (IsOwnedByPlayer) Mark(MARK_CHANGE);
  1444. CloakingDevice.Graphic_Logic();
  1445. if (!Arm && CloakingDevice.Fetch_Stage()) {
  1446. if (Health_Ratio() > 0x0040) {
  1447. Do_Cloak();
  1448. } else {
  1449. if (Random_Pick(0, 25) == 1) {
  1450. Do_Cloak();
  1451. }
  1452. }
  1453. }
  1454. } else {
  1455. VisualType pre = Visual_Character(true);
  1456. CloakingDevice.Graphic_Logic();
  1457. switch (Cloak) {
  1458. /*
  1459. ** Handle the uncloaking process. Always mark to redraw
  1460. ** the object and when cloaking is complete, stabilize into
  1461. ** the normal uncloaked state.
  1462. */
  1463. case UNCLOAKING:
  1464. Mark(MARK_CHANGE);
  1465. if (Visual_Character(true) == VISUAL_NORMAL) {
  1466. CloakingDevice.Set_Rate(UNCLOAK_VIS_TIME);
  1467. CloakingDevice.Set_Stage(0); // re-start the stage counter
  1468. Cloak = UNCLOAKED;
  1469. }
  1470. break;
  1471. /*
  1472. ** Handle the cloaking process. Always mark to redraw the object
  1473. ** and when the cloaking process is complete, stabilize into the
  1474. ** normal cloaked state.
  1475. */
  1476. case CLOAKING:
  1477. Mark(MARK_CHANGE);
  1478. switch (Visual_Character(true)) {
  1479. /*
  1480. ** If badly damaged, then it can never fully cloak.
  1481. */
  1482. case VISUAL_DARKEN:
  1483. if (Health_Ratio() < 0x0040 && Random_Pick(1, 3) == 1) {
  1484. Cloak = UNCLOAKING;
  1485. }
  1486. break;
  1487. #ifdef NEVER
  1488. case VISUAL_SHADOWY:
  1489. if (pre != Visual_Character(true)) {
  1490. Detach_All(false);
  1491. }
  1492. break;
  1493. #endif
  1494. case VISUAL_HIDDEN:
  1495. Cloak = CLOAKED;
  1496. CloakingDevice.Set_Rate(0);
  1497. /*
  1498. ** Special check to ensure that if the unit is carring a captured
  1499. ** flag, it will never fully cloak.
  1500. */
  1501. if (What_Am_I() == RTTI_UNIT && ((UnitClass *)this)->Flagged != HOUSE_NONE) {
  1502. Do_Shimmer();
  1503. } else {
  1504. Detach_All(false);
  1505. }
  1506. /*
  1507. ** A computer controlled unit will try to scatter if possible so
  1508. ** that it will be much harder to locate.
  1509. */
  1510. if (What_Am_I() == RTTI_UNIT && !House->IsHuman) {
  1511. Scatter(0, true);
  1512. }
  1513. break;
  1514. }
  1515. break;
  1516. /*
  1517. ** A cloaked object will always be redrawn if it is owned by the
  1518. ** player. This ensures that the shimmering effect will animate.
  1519. */
  1520. case CLOAKED:
  1521. if (IsOwnedByPlayer) {
  1522. Mark(MARK_CHANGE);
  1523. }
  1524. break;
  1525. }
  1526. }
  1527. }
  1528. /*
  1529. ** Arming delay always counts down to zero.
  1530. */
  1531. if (Arm) Arm--;
  1532. /*
  1533. ** Update the animation timer system. If the animation stage
  1534. ** changes, then flag the object to be redrawn as well as determine
  1535. ** if the current animation process needs to change.
  1536. */
  1537. if (What_Am_I() != RTTI_BUILDING) {
  1538. if (StageClass::Graphic_Logic() || Time_To_Redraw()) {
  1539. Mark(MARK_CHANGE);
  1540. }
  1541. }
  1542. /*
  1543. ** If the object is flashing and a change of flash state has occured, then mark the
  1544. ** object to be redrawn.
  1545. */
  1546. if (FlasherClass::Process()) {
  1547. Mark(MARK_CHANGE);
  1548. }
  1549. }
  1550. /***********************************************************************************************
  1551. * TechnoClass::Select -- Selects object and checks to see if can be selected. *
  1552. * *
  1553. * This function checks to see if this techno object can be selected. If it can, then it *
  1554. * is selected. *
  1555. * *
  1556. * INPUT: none *
  1557. * *
  1558. * OUTPUT: none *
  1559. * *
  1560. * WARNINGS: none *
  1561. * *
  1562. * HISTORY: *
  1563. * 12/11/1994 JLB : Created. *
  1564. *=============================================================================================*/
  1565. bool TechnoClass::Select(void)
  1566. {
  1567. if (!IsDiscoveredByPlayer && !IsOwnedByPlayer && !Debug_Unshroud) {
  1568. return(false);
  1569. }
  1570. if (RadioClass::Select()) {
  1571. /*
  1572. ** Speak a confirmation of selection.
  1573. */
  1574. if (IsOwnedByPlayer && AllowVoice) {
  1575. Response_Select();
  1576. }
  1577. return(true);
  1578. }
  1579. return(false);
  1580. }
  1581. /***********************************************************************************************
  1582. * TechnoClass::Can_Fire -- Determines if this techno object can fire. *
  1583. * *
  1584. * This performs a simple check to make sure that this techno object can fire. At this *
  1585. * level, the only thing checked for is the rearming delay. *
  1586. * *
  1587. * INPUT: none *
  1588. * *
  1589. * OUTPUT: Returns with the fire legality control code. *
  1590. * *
  1591. * WARNINGS: none *
  1592. * *
  1593. * HISTORY: *
  1594. * 12/23/1994 JLB : Created. *
  1595. *=============================================================================================*/
  1596. FireErrorType TechnoClass::Can_Fire(TARGET target, int which) const
  1597. {
  1598. /*
  1599. ** Don't allow firing if the target is illegal.
  1600. */
  1601. if (!Target_Legal(target)) {
  1602. return(FIRE_ILLEGAL);
  1603. }
  1604. ObjectClass * object = As_Object(target);
  1605. /*
  1606. ** If the object is completely cloaked, then you can't fire on it.
  1607. */
  1608. //Mono_Printf("Units[0]=%p.\n", Units.Raw_Ptr(0));
  1609. //Mono_Printf("Infantry[0]=%p.\n", Infantry.Raw_Ptr(0));
  1610. //Mono_Printf("Buildings[0]=%p.\n", Buildings.Raw_Ptr(0));
  1611. //Mono_Printf("Aircraft[0]=%p.\n", Aircraft.Raw_Ptr(0));
  1612. //Mono_Printf("object=%p, Strength=%d, IsActive=%d, IsInLimbo=%d.\n", object, (long)object->Strength, object->IsActive, object->IsInLimbo);Get_Key();
  1613. if (object && /*(object->IsActive || GameToPlay != GAME_NORMAL) &&*/ object->Is_Techno() && ((TechnoClass *)object)->Cloak == CLOAKED) {
  1614. return(FIRE_CANT);
  1615. }
  1616. /*
  1617. ** If there is no weapon, then firing is not allowed.
  1618. */
  1619. WeaponType weap = (which == 0) ? Techno_Type_Class()->Primary : Techno_Type_Class()->Secondary;
  1620. if (weap == WEAPON_NONE) {
  1621. return(FIRE_CANT);
  1622. }
  1623. /*
  1624. ** Can only fire anti-aircraft weapons against aircraft unless the aircraft is
  1625. ** sitting on the ground.
  1626. */
  1627. if (object && object->What_Am_I() == RTTI_AIRCRAFT &&
  1628. !BulletTypeClass::As_Reference(Weapons[weap].Fires).IsAntiAircraft &&
  1629. ((AircraftClass *)object)->Altitude > 0) {
  1630. return(FIRE_CANT);
  1631. }
  1632. /*
  1633. ** Don't allow firing if still rearming.
  1634. */
  1635. if (Arm) return(FIRE_REARM);
  1636. /*
  1637. ** The target must be within range in order to allow firing.
  1638. */
  1639. if (!In_Range(target, which)) {
  1640. return(FIRE_RANGE);
  1641. }
  1642. /*
  1643. ** If there is no ammo left, then it can't fire.
  1644. */
  1645. if (!Ammo) {
  1646. return(FIRE_AMMO);
  1647. }
  1648. /*
  1649. ** If cloaked, then firing is disabled.
  1650. */
  1651. if (Cloak != UNCLOAKED) {
  1652. return(FIRE_CLOAKED);
  1653. }
  1654. return(FIRE_OK);
  1655. }
  1656. /***********************************************************************************************
  1657. * TechnoClass::Stun -- Prepares the object for removal from the game. *
  1658. * *
  1659. * This routine handles cleaning up this techno object from the game system so that when *
  1660. * it is subsequently removed, it doesn't leave any loose ends. *
  1661. * *
  1662. * INPUT: none *
  1663. * *
  1664. * OUTPUT: none *
  1665. * *
  1666. * WARNINGS: none *
  1667. * *
  1668. * HISTORY: *
  1669. * 12/23/1994 JLB : Created. *
  1670. *=============================================================================================*/
  1671. void TechnoClass::Stun(void)
  1672. {
  1673. Assign_Target(TARGET_NONE);
  1674. Assign_Destination(TARGET_NONE);
  1675. Transmit_Message(RADIO_OVER_OUT);
  1676. Detach_All();
  1677. Unselect();
  1678. }
  1679. /***********************************************************************************************
  1680. * TechnoClass::Assign_Target -- Assigns the targeting computer with specified target. *
  1681. * *
  1682. * Use this routine to set the targeting computer for this object. It checks to make sure *
  1683. * that targeting of itself is prohibited. *
  1684. * *
  1685. * INPUT: target -- The target for this object to attack. *
  1686. * *
  1687. * OUTPUT: none *
  1688. * *
  1689. * WARNINGS: none *
  1690. * *
  1691. * HISTORY: *
  1692. * 12/23/1994 JLB : Created. *
  1693. *=============================================================================================*/
  1694. void TechnoClass::Assign_Target(TARGET target)
  1695. {
  1696. if (target == TarCom) return;
  1697. if (!Target_Legal(target)) {
  1698. target = TARGET_NONE;
  1699. } else {
  1700. /*
  1701. ** Prevent targeting of self.
  1702. */
  1703. if (target == As_Target()) {
  1704. target = ::As_Target(Coord_Cell(Coord));
  1705. } else {
  1706. /*
  1707. ** Make sure that the target is not already dead.
  1708. */
  1709. ObjectClass * object = As_Object(target);
  1710. if (object && (object->IsActive == false || object->Strength == 0)) {
  1711. target = TARGET_NONE;
  1712. }
  1713. }
  1714. }
  1715. /*
  1716. ** Set the unit's targeting computer.
  1717. */
  1718. TarCom = target;
  1719. }
  1720. /***********************************************************************************************
  1721. * TechnoClass::Rearm_Delay -- Calculates the delay before firing can occur. *
  1722. * *
  1723. * This function calculates the delay between shots. It determines this from the standard *
  1724. * rate of fire (ROF) of the base class and modifies it according to game speed and *
  1725. * whether this is the first or second shot. All single shot attackers consider their *
  1726. * shots to be "second" since the second shot is the one handled normally. The first shot *
  1727. * usually gets assigned a much shorter delay time before the next shot can fire. *
  1728. * *
  1729. * INPUT: second -- bool; Is this the second of a two shot salvo? *
  1730. * *
  1731. * OUTPUT: Returns with the number of game frames to delay before the next shot may fire. *
  1732. * *
  1733. * WARNINGS: none *
  1734. * *
  1735. * HISTORY: *
  1736. * 12/26/1994 JLB : Created. *
  1737. *=============================================================================================*/
  1738. int TechnoClass::Rearm_Delay(bool second) const
  1739. {
  1740. if (second) {
  1741. return(Weapons[Techno_Type_Class()->Primary].ROF + 3);
  1742. }
  1743. return(9);
  1744. }
  1745. /***********************************************************************************************
  1746. * TechnoClass::Fire_At -- Fires projectile at target specified. *
  1747. * *
  1748. * This is the main projectile firing code. Buildings, units, and infantry route fire *
  1749. * requests through this function. *
  1750. * *
  1751. * INPUT: target -- The target that the projectile is to be fired at. *
  1752. * *
  1753. * which -- Which weapon to fire. *
  1754. * *
  1755. * OUTPUT: Returns with a pointer to the projectile object that was fired. If no projectile *
  1756. * could be created or there was some other illegality detected, the return value *
  1757. * will be NULL. *
  1758. * *
  1759. * WARNINGS: none *
  1760. * *
  1761. * HISTORY: *
  1762. * 12/26/1994 JLB : Created. *
  1763. * 07/03/1995 JLB : Moving platforms fire inaccurate projectiles. *
  1764. *=============================================================================================*/
  1765. BulletClass * TechnoClass::Fire_At(TARGET target, int which)
  1766. {
  1767. BulletClass *bullet; // Projectile.
  1768. DirType dir; // The facing to impart upon the projectile.
  1769. COORDINATE target_coord; // Coordinate of the target.
  1770. COORDINATE fire_coord; // Coordinate of firing position.
  1771. TechnoTypeClass const & tclass = *Techno_Type_Class();
  1772. ObjectClass *object;
  1773. WeaponTypeClass const *weapon = (which == 0) ? &Weapons[tclass.Primary] : &Weapons[tclass.Secondary];
  1774. BulletTypeClass const &btype = BulletTypeClass::As_Reference(weapon->Fires);
  1775. /*
  1776. ** Perform a quick legality check to see if firing can occur.
  1777. */
  1778. if (Debug_Map || weapon->Fires == BULLET_NONE || !Target_Legal(target)) {
  1779. return(NULL);
  1780. }
  1781. /*
  1782. ** Fetch the target coordinate for the target specified.
  1783. */
  1784. object = As_Object(target);
  1785. if (object) {
  1786. target_coord = object->Target_Coord();
  1787. } else {
  1788. target_coord = As_Coord(target);
  1789. }
  1790. /*
  1791. ** Get the location where the projectile should appear.
  1792. */
  1793. fire_coord = Fire_Coord(which);
  1794. /*
  1795. ** If the projectile is a homing type (such as a missile), then it will
  1796. ** launch in the direction the turret is facing, NOT necessarily the same
  1797. ** direction as the target.
  1798. */
  1799. if (btype.IsHoming || btype.IsDropping) {
  1800. dir = Fire_Direction();
  1801. if (btype.IsDropping) {
  1802. fire_coord = Center_Coord();
  1803. }
  1804. } else {
  1805. dir = ::Direction(fire_coord, target_coord);
  1806. }
  1807. /*
  1808. ** Create the projectile. Then process any special operations that
  1809. ** need to be performed according to the style of projectile
  1810. ** created.
  1811. */
  1812. bullet = new BulletClass(weapon->Fires);
  1813. if (bullet) {
  1814. bullet->Assign_Target(target);
  1815. bullet->Payback = this;
  1816. bullet->Strength = weapon->Attack;
  1817. /*
  1818. ** If this is firing from a moving platform, then the projectile is inaccurate.
  1819. */
  1820. if (Special.IsDefenderAdvantage && What_Am_I() != RTTI_BUILDING && ((FootClass const *)this)->IsDriving) {
  1821. bullet->IsInaccurate = true;
  1822. }
  1823. if (bullet->Unlimbo(fire_coord, dir)) {
  1824. //Mono_Printf("Units[0]=%p.\n", Units.Raw_Ptr(0));
  1825. //Mono_Printf("Infantry[0]=%p.\n", Infantry.Raw_Ptr(0));
  1826. //Mono_Printf("Buildings[0]=%p.\n", Buildings.Raw_Ptr(0));
  1827. //Mono_Printf("Aircraft[0]=%p.\n", Aircraft.Raw_Ptr(0));
  1828. //Mono_Printf("object=%p, Strength=%d, IsActive=%d, IsInLimbo=%d.\n", object, (long)object->Strength, object->IsActive, object->IsInLimbo);Get_Key();
  1829. bullet->Payback = this;
  1830. bullet->Strength = weapon->Attack;
  1831. } else {
  1832. delete bullet;
  1833. }
  1834. if (!bullet->Class->IsFueled) {
  1835. IsInRecoilState = true;
  1836. }
  1837. Arm = Rearm_Delay(IsSecondShot);
  1838. if (tclass.IsTwoShooter) {
  1839. IsSecondShot = (IsSecondShot == false);
  1840. }
  1841. /*
  1842. ** Perform any animation effect for this weapon.
  1843. */
  1844. AnimType a = weapon->Anim;
  1845. switch (a) {
  1846. case ANIM_GUN_N:
  1847. case ANIM_CHEM_N:
  1848. case ANIM_FLAME_N:
  1849. a = (AnimType)(a + Dir_Facing(Fire_Direction()));
  1850. break;
  1851. }
  1852. /*
  1853. ** If there is a special firing animation, then create and attach it
  1854. ** now.
  1855. */
  1856. if (a != ANIM_NONE) {
  1857. AnimClass * anim = new AnimClass(a, Fire_Coord(which));
  1858. if (anim) {
  1859. anim->Attach_To(this);
  1860. }
  1861. }
  1862. /*
  1863. ** Reduce ammunition for this object.
  1864. */
  1865. if (Ammo > 0) {
  1866. Ammo--;
  1867. }
  1868. /*
  1869. ** Firing will in all likelihood, require the unit to be redraw. Flag it to be
  1870. ** redrawn here.
  1871. */
  1872. Mark(MARK_CHANGE);
  1873. /*
  1874. ** If a projectile was fired from a unit that is hidden in the darkness,
  1875. ** reveal that unit and a little area around it.
  1876. ** For multiplayer games, only reveal the unit if the target is the
  1877. ** local player.
  1878. */
  1879. if ((!IsOwnedByPlayer && !IsDiscoveredByPlayer) || !Map[Coord_Cell(Center_Coord())].IsMapped) {
  1880. if (GameToPlay == GAME_NORMAL) {
  1881. Map.Sight_From(Coord_Cell(Center_Coord()), 1, false);
  1882. } else {
  1883. ObjectClass *obj = As_Object(target);
  1884. if (obj) {
  1885. HousesType tgt_owner = obj->Owner();
  1886. if (PlayerPtr->Class->House == tgt_owner) {
  1887. Map.Sight_From(Coord_Cell(Center_Coord()), 1, false);
  1888. }
  1889. }
  1890. }
  1891. }
  1892. }
  1893. return(bullet);
  1894. }
  1895. /***********************************************************************************************
  1896. * TechnoClass::Player_Assign_Mission -- Assigns a mission as result of player input. *
  1897. * *
  1898. * This routine is called when the mission for an object needs to change as a result of *
  1899. * player input. The basic operation would be to queue the event and let the action *
  1900. * occur at the frame dictated by the queing system. However, if a voice response is *
  1901. * indicated, then perform it at this time. This will give a greater illusion of *
  1902. * immediate response. *
  1903. * *
  1904. * INPUT: order -- The mission order to assign to this object. *
  1905. * *
  1906. * target -- The target of this object. This will be used for combat and attack. *
  1907. * *
  1908. * destination -- The movement destination for this object. *
  1909. * *
  1910. * OUTPUT: none *
  1911. * *
  1912. * WARNINGS: none *
  1913. * *
  1914. * HISTORY: *
  1915. * 05/22/1995 JLB : Created. *
  1916. *=============================================================================================*/
  1917. void TechnoClass::Player_Assign_Mission(MissionType mission, TARGET target, TARGET destination)
  1918. {
  1919. if (AllowVoice) {
  1920. if (mission == MISSION_ATTACK) {
  1921. Response_Attack();
  1922. } else {
  1923. Response_Move();
  1924. }
  1925. }
  1926. Queue_Mission(As_Target(), mission, target, destination);
  1927. }
  1928. /***********************************************************************************************
  1929. * TechnoClass::What_Action -- Determines what action to perform if object is selected. *
  1930. * *
  1931. * This routine will examine the object specified and return with the action that will *
  1932. * be performed if the mouse button were clicked over the object. *
  1933. * *
  1934. * INPUT: object -- The object that the mouse button might be clicked on. *
  1935. * *
  1936. * OUTPUT: Returns with the action that will be performed if the object was clicked on. *
  1937. * *
  1938. * WARNINGS: none *
  1939. * *
  1940. * HISTORY: *
  1941. * 01/19/1995 JLB : Created. *
  1942. * 03/21/1995 JLB : Special target control for trees. *
  1943. *=============================================================================================*/
  1944. ActionType TechnoClass::What_Action(ObjectClass * object) const
  1945. {
  1946. if (object) {
  1947. /*
  1948. ** Return the ACTION_SELF flag if clicking on itself. However, if this
  1949. ** object cannot do anything special with itself, then just return with
  1950. ** the no action flag.
  1951. */
  1952. if (object == this && CurrentObject.Count() == 1 && House == PlayerPtr) {
  1953. return(ACTION_SELF);
  1954. }
  1955. bool altdown = (Keyboard::Down(KN_LALT) || Keyboard::Down(KN_RALT));
  1956. bool ctrldown = (Keyboard::Down(KN_LCTRL) || Keyboard::Down(KN_RCTRL));
  1957. bool shiftdown = (Keyboard::Down(KN_LSHIFT) || Keyboard::Down(KN_RSHIFT));
  1958. /*
  1959. ** Special guard area mission is possible if both the control and the
  1960. ** alt keys are held down.
  1961. */
  1962. if (IsOwnedByPlayer && ctrldown && altdown && Can_Player_Move() && Can_Player_Fire()) {
  1963. return(ACTION_GUARD_AREA);
  1964. }
  1965. /*
  1966. ** Special override to force a move regardless of what is occupying the location.
  1967. */
  1968. if (altdown) {
  1969. if (IsOwnedByPlayer && Can_Player_Move()) {
  1970. return(ACTION_MOVE);
  1971. }
  1972. }
  1973. /*
  1974. ** Override so that toggled select state can be performed while the <SHIFT> key
  1975. ** is held down.
  1976. */
  1977. if (shiftdown) {
  1978. if (IsOwnedByPlayer && !IsALoaner) {
  1979. return(ACTION_TOGGLE_SELECT);
  1980. }
  1981. }
  1982. /*
  1983. ** If firing is possible and legal, then return this action potential.
  1984. */
  1985. bool control = Keyboard::Down(KN_LCTRL) || Keyboard::Down(KN_RCTRL);
  1986. if (IsOwnedByPlayer && (ctrldown || !House->Is_Ally(object)) && (ctrldown || object->Class_Of().IsLegalTarget || (Special.IsTreeTarget && object->What_Am_I() == RTTI_TERRAIN))) {
  1987. if (Can_Player_Move() || In_Range(object, 0)) {
  1988. return(ACTION_ATTACK);
  1989. }
  1990. }
  1991. /*
  1992. ** Possibly try to select the specified object, if that is warranted.
  1993. */
  1994. if (!Is_Weapon_Equipped() || !IsOwnedByPlayer || object->Owner() == Owner()) {
  1995. if ((!IsALoaner || !IsOwnedByPlayer) && object->Class_Of().IsSelectable && !object->IsSelected) {
  1996. return(ACTION_SELECT);
  1997. }
  1998. return(ACTION_NONE);
  1999. }
  2000. }
  2001. return(ACTION_NONE);
  2002. }
  2003. /***********************************************************************************************
  2004. * TechnoClass::What_Action -- Determines action to perform if cell is clicked on. *
  2005. * *
  2006. * Use this routine to determine what action will be performed if the specified cell *
  2007. * is clicked on. Usually this action is either a ACTION_MOVE or ACTION_NOMOVE. The action *
  2008. * nomove is used to perform special case checking for nearby cells if in fact the mouse *
  2009. * is clicked over the cell. *
  2010. * *
  2011. * INPUT: cell -- The cell to check for being clicked over. *
  2012. * *
  2013. * OUTPUT: Returns with the action that will occur if the cell is clicked on. *
  2014. * *
  2015. * WARNINGS: none *
  2016. * *
  2017. * HISTORY: *
  2018. * 01/19/1995 JLB : Created. *
  2019. * 07/10/1995 JLB : Force fire for buildings is explicitely disabled. *
  2020. *=============================================================================================*/
  2021. ActionType TechnoClass::What_Action(CELL cell) const
  2022. {
  2023. CellClass const * cellptr = &Map[cell];
  2024. OverlayTypeClass const * optr = NULL;
  2025. bool ctrldown = Keyboard::Down(KN_LCTRL) || Keyboard::Down(KN_RCTRL);
  2026. bool shiftdown = Keyboard::Down(KN_LSHIFT) || Keyboard::Down(KN_RSHIFT);
  2027. bool altdown = (Keyboard::Down(KN_LALT) || Keyboard::Down(KN_RALT));
  2028. /*
  2029. ** Disable recognizing the <CTRL> key forced fire option when dealing with buildings.
  2030. */
  2031. if (What_Am_I() == RTTI_BUILDING) ctrldown = false;
  2032. if (cellptr->Overlay != OVERLAY_NONE) {
  2033. optr = &OverlayTypeClass::As_Reference(cellptr->Overlay);
  2034. }
  2035. /*
  2036. ** Special guard area mission is possible if both the control and the
  2037. ** alt keys are held down.
  2038. */
  2039. if (IsOwnedByPlayer && ctrldown && altdown && Can_Player_Move() && Can_Player_Fire()) {
  2040. return(ACTION_GUARD_AREA);
  2041. }
  2042. if (IsOwnedByPlayer && Techno_Type_Class()->Primary != WEAPON_NONE && (ctrldown || (optr && optr->IsLegalTarget))) {
  2043. WarheadTypeClass const * whead = &Warheads[BulletTypeClass::As_Reference(Weapons[Techno_Type_Class()->Primary].Fires).Warhead];
  2044. if (!optr || (optr->IsWall && (whead->IsWallDestroyer || (whead->IsWoodDestroyer && optr->IsWooden)))) {
  2045. if (Can_Player_Move() || In_Range(::As_Target(cell), 0)) {
  2046. return(ACTION_ATTACK);
  2047. }
  2048. }
  2049. }
  2050. if (IsOwnedByPlayer && Can_Player_Move()) {
  2051. /*
  2052. ** Special override to force a move regardless of what is occupying the location.
  2053. */
  2054. if (shiftdown) {
  2055. return(ACTION_MOVE);
  2056. }
  2057. /*
  2058. ** If the object can enter the cell specified, then allow
  2059. ** movement to it.
  2060. */
  2061. if (Can_Enter_Cell(cell) <= MOVE_CLOAK) {
  2062. return(ACTION_MOVE);
  2063. }
  2064. return(ACTION_NOMOVE);
  2065. }
  2066. return(ACTION_NONE);
  2067. }
  2068. /***********************************************************************************************
  2069. * TechnoClass::Can_Player_Move -- Determines if the object can move be moved by player. *
  2070. * *
  2071. * Use this routine to determine whether a movement order can be given to this object. *
  2072. * *
  2073. * INPUT: none *
  2074. * *
  2075. * OUTPUT: bool; Can this object be given a movement order by the player? *
  2076. * *
  2077. * WARNINGS: none *
  2078. * *
  2079. * HISTORY: *
  2080. * 01/19/1995 JLB : Created. *
  2081. *=============================================================================================*/
  2082. bool TechnoClass::Can_Player_Move(void) const
  2083. {
  2084. return(PlayerPtr == House);
  2085. }
  2086. /***********************************************************************************************
  2087. * TechnoClass::Can_Player_Fire -- Determines if the player can give this object a fire order. *
  2088. * *
  2089. * Call this routine to determine if this object can be given a fire order by the player. *
  2090. * Such objects will affect the mouse cursor accordingly -- usually causes the targeting *
  2091. * cursor to appear. *
  2092. * *
  2093. * INPUT: none *
  2094. * *
  2095. * OUTPUT: bool; Can this object be given firing orders by the player? *
  2096. * *
  2097. * WARNINGS: none *
  2098. * *
  2099. * HISTORY: *
  2100. * 01/23/1995 JLB : Created. *
  2101. *=============================================================================================*/
  2102. bool TechnoClass::Can_Player_Fire(void) const
  2103. {
  2104. if (House->IsHuman && Is_Techno() && Techno_Type_Class()->Primary != WEAPON_NONE) {
  2105. return(true);
  2106. }
  2107. return(false);
  2108. }
  2109. /***********************************************************************************************
  2110. * TechnoClass::Is_Weapon_Equipped -- Determines if this object has a combat weapon. *
  2111. * *
  2112. * Use this routine to determine if this object is equipped with a combat weapon. Such *
  2113. * determination is used by the AI system to gauge the threat potential of the object. *
  2114. * *
  2115. * INPUT: none *
  2116. * *
  2117. * OUTPUT: bool; Is this object equipped with a combat weapon? *
  2118. * *
  2119. * WARNINGS: none *
  2120. * *
  2121. * HISTORY: *
  2122. * 01/23/1995 JLB : Created. *
  2123. *=============================================================================================*/
  2124. bool TechnoClass::Is_Weapon_Equipped(void) const
  2125. {
  2126. return(Techno_Type_Class()->Primary != WEAPON_NONE);
  2127. }
  2128. /***********************************************************************************************
  2129. * TechnoClass::Can_Repair -- Determines if the object can and should be repaired. *
  2130. * *
  2131. * Use this routine to determine if the specified object is a candidate for repair. In *
  2132. * order to qualify, the object must be allowed to be repaired (in theory) and it must *
  2133. * be below full strength. If these conditions are met, then it can be repaired. *
  2134. * *
  2135. * INPUT: none *
  2136. * *
  2137. * OUTPUT: bool; May this unit be repaired? A return value of false may mean that the object *
  2138. * is not allowed to be repaired, or it might be full strength already. *
  2139. * *
  2140. * WARNINGS: none *
  2141. * *
  2142. * HISTORY: *
  2143. * 01/23/1995 JLB : Created. *
  2144. *=============================================================================================*/
  2145. bool TechnoClass::Can_Repair(void) const
  2146. {
  2147. /*
  2148. ** Temporary hack to disable repair cursor over non-buildings.
  2149. */
  2150. if (What_Am_I() == RTTI_UNIT || What_Am_I() == RTTI_INFANTRY || What_Am_I() == RTTI_AIRCRAFT) {
  2151. return(false);
  2152. }
  2153. return(Techno_Type_Class()->IsRepairable && Strength != Class_Of().MaxStrength);
  2154. }
  2155. /***********************************************************************************************
  2156. * TechnoClass::Weapon_Range -- Determines the maximum range for the weapon. *
  2157. * *
  2158. * Use this routine to determine the maximum range for the weapon indicated. *
  2159. * *
  2160. * INPUT: which -- Which weapon to use when determining the range. 0=primary, 1=secondary. *
  2161. * *
  2162. * OUTPUT: Returns with the range of the weapon (in leptons). *
  2163. * *
  2164. * WARNINGS: none *
  2165. * *
  2166. * HISTORY: *
  2167. * 03/19/1995 JLB : Created. *
  2168. *=============================================================================================*/
  2169. int TechnoClass::Weapon_Range(int which) const
  2170. {
  2171. WeaponType weapon = WEAPON_NONE;
  2172. TechnoTypeClass const & ttype = *Techno_Type_Class();
  2173. switch (which) {
  2174. case 0:
  2175. weapon = ttype.Primary;
  2176. break;
  2177. case 1:
  2178. weapon = ttype.Secondary;
  2179. break;
  2180. }
  2181. if (weapon != WEAPON_NONE) {
  2182. if (weapon == WEAPON_NIKE && GameToPlay == GAME_NORMAL) {
  2183. return(Weapons[weapon].Range*2);
  2184. }
  2185. return(Weapons[weapon].Range);
  2186. }
  2187. return(0);
  2188. }
  2189. /***************************************************************************
  2190. * TechnoClass::Override_Mission -- temporarily overides a units mission *
  2191. * *
  2192. * *
  2193. * *
  2194. * INPUT: MissionType mission - the mission we want to overide *
  2195. * TARGET tarcom - the new target we want to overide *
  2196. * TARGET navcom - the new navigation point to overide *
  2197. * *
  2198. * OUTPUT: none *
  2199. * *
  2200. * WARNINGS: If a mission is already overidden, the current mission is *
  2201. * just re-assigned. *
  2202. * *
  2203. * HISTORY: *
  2204. * 04/28/1995 PWG : Created. *
  2205. *=========================================================================*/
  2206. void TechnoClass::Override_Mission(MissionType mission, TARGET tarcom, TARGET navcom)
  2207. {
  2208. SuspendedTarCom = TarCom;
  2209. RadioClass::Override_Mission(mission, tarcom, navcom);
  2210. Assign_Target(tarcom);
  2211. }
  2212. /***************************************************************************
  2213. * TechnoClass::Restore_Mission -- Restores an overidden mission *
  2214. * *
  2215. * INPUT: none *
  2216. * *
  2217. * OUTPUT: none *
  2218. * *
  2219. * WARNINGS: none *
  2220. * *
  2221. * HISTORY: *
  2222. * 04/28/1995 PWG : Created. *
  2223. *=========================================================================*/
  2224. bool TechnoClass::Restore_Mission(void)
  2225. {
  2226. if (RadioClass::Restore_Mission()) {
  2227. Assign_Target(SuspendedTarCom);
  2228. return(true);
  2229. }
  2230. return(false);
  2231. }
  2232. /***********************************************************************************************
  2233. * TechnoClass::Captured -- Handles capturing this object. *
  2234. * *
  2235. * This routine is called when this object gets captured by the house specified. It handles *
  2236. * removing this object from any targeting computers and then changes the ownership of *
  2237. * the object to the new house. *
  2238. * *
  2239. * INPUT: newowner -- Pointer to the house that is now the new owner. *
  2240. * *
  2241. * OUTPUT: Was the object captured? Failure would mean that it is already under control of *
  2242. * the house specified. *
  2243. * *
  2244. * WARNINGS: none *
  2245. * *
  2246. * HISTORY: *
  2247. * 05/08/1995 JLB : Created. *
  2248. *=============================================================================================*/
  2249. bool TechnoClass::Captured(HouseClass * newowner)
  2250. {
  2251. if (newowner != House) {
  2252. /*
  2253. ** Capture attempt springs any "entered" trigger. The entered trigger
  2254. ** occurs first since there may be a special trigger attached to this
  2255. ** object that flags a capture as a win and a destroy as a loss. This
  2256. ** order is necessary because the object is recorded as a kill as well.
  2257. */
  2258. if (Trigger /*&& Trigger->House == newowner->Class->House*/) {
  2259. Trigger->Spring(EVENT_PLAYER_ENTERED, this);
  2260. }
  2261. /*
  2262. ** Record this as a kill.
  2263. */
  2264. Record_The_Kill(NULL);
  2265. /*
  2266. ** Special kill record logic for capture process.
  2267. */
  2268. switch (What_Am_I()) {
  2269. case RTTI_BUILDING:
  2270. if (newowner) newowner->BuildingsKilled[Owner()]++;
  2271. break;
  2272. case RTTI_AIRCRAFT:
  2273. case RTTI_INFANTRY:
  2274. case RTTI_UNIT:
  2275. if (newowner) newowner->UnitsKilled[Owner()]++;
  2276. break;
  2277. default:
  2278. break;
  2279. }
  2280. House->WhoLastHurtMe = newowner->Class->House;
  2281. /*
  2282. ** Remove from targeting computers.
  2283. */
  2284. Detach_All(false);
  2285. #ifdef NEVER
  2286. /*
  2287. ** Break off any radio contact.
  2288. */
  2289. Transmit_Message(RADIO_OVER_OUT);
  2290. #endif
  2291. /*
  2292. ** Change ownership now.
  2293. */
  2294. House = newowner;
  2295. IsOwnedByPlayer = (House == PlayerPtr);
  2296. return(true);
  2297. }
  2298. return(false);
  2299. }
  2300. /***********************************************************************************************
  2301. * TechnoClass::Take_Damage -- Records damage assessed to this object. *
  2302. * *
  2303. * This routine is called when this object has taken damage. It handles recording whether *
  2304. * this object has been destroyed. If it has, then mark the appropriate kill records as *
  2305. * necessary. *
  2306. * *
  2307. * INPUT: *
  2308. * *
  2309. * OUTPUT: *
  2310. * *
  2311. * WARNINGS: *
  2312. * *
  2313. * HISTORY: *
  2314. * 06/20/1995 JLB : Created. *
  2315. *=============================================================================================*/
  2316. ResultType TechnoClass::Take_Damage(int & damage, int distance, WarheadType warhead, TechnoClass * source)
  2317. {
  2318. ResultType result = ObjectClass::Take_Damage(damage, distance, warhead, source);
  2319. switch (result) {
  2320. case RESULT_DESTROYED:
  2321. Transmit_Message(RADIO_OVER_OUT);
  2322. Stun();
  2323. break;
  2324. /*
  2325. ** If some damage was received and this object is cloaked, shimmer
  2326. ** the cloak a bit.
  2327. */
  2328. default:
  2329. if (source && !House->Is_Ally(source)) {
  2330. IsTickedOff = true;
  2331. }
  2332. Do_Shimmer();
  2333. break;
  2334. case RESULT_NONE:
  2335. break;
  2336. }
  2337. return(result);
  2338. }
  2339. /***********************************************************************************************
  2340. * TechnoTypeClass::Max_Passengers -- Fetches the maximum passengers allowed. *
  2341. * *
  2342. * This routine will return with the maximum number of passengers allowed in this *
  2343. * transport. This typically applies to APCs and possibley transport helicopters. *
  2344. * *
  2345. * INPUT: none *
  2346. * *
  2347. * OUTPUT: Returns with the number of passengers this transport can carry. *
  2348. * *
  2349. * WARNINGS: none *
  2350. * *
  2351. * HISTORY: *
  2352. * 06/20/1995 JLB : Created. *
  2353. *=============================================================================================*/
  2354. int TechnoTypeClass::Max_Passengers(void) const
  2355. {
  2356. if (IsTransporter) {
  2357. return(5);
  2358. }
  2359. return(0);
  2360. }
  2361. /***********************************************************************************************
  2362. * TechnoClass::Record_The_Kill -- Records the death of this object. *
  2363. * *
  2364. * This routine is used to record the death of this object. It will handle updating the *
  2365. * owner house with the kill record as well as springing any trigger events associated with *
  2366. * this object's death. *
  2367. * *
  2368. * INPUT: source -- Pointer to the source of this object's death (if there is a source). *
  2369. * *
  2370. * OUTPUT: none *
  2371. * *
  2372. * WARNINGS: none *
  2373. * *
  2374. * HISTORY: *
  2375. * 07/08/1995 JLB : Created. *
  2376. * 08/23/1995 JLB : Building loss is only counted if it received damage. *
  2377. *=============================================================================================*/
  2378. void TechnoClass::Record_The_Kill(TechnoClass * source)
  2379. {
  2380. /*
  2381. ** Handle any trigger event associated with this object.
  2382. */
  2383. if (Trigger && source) Trigger->Spring(EVENT_ATTACKED, this);
  2384. if (Trigger && source) Trigger->Spring(EVENT_DISCOVERED, this);
  2385. if (Trigger) Trigger->Spring(EVENT_DESTROYED, this);
  2386. if (source) {
  2387. /*
  2388. ** Call the explicity cast versions of the Made_A_Kill function. This
  2389. ** is necessary because we don't want to add a virtual function to the
  2390. ** CrewClass. Doing so would complicate the save/load process.
  2391. */
  2392. switch (source->What_Am_I()) {
  2393. case RTTI_INFANTRY:
  2394. ((InfantryClass *)source)->Made_A_Kill();
  2395. break;
  2396. case RTTI_UNIT:
  2397. ((UnitClass *)source)->Made_A_Kill();
  2398. break;
  2399. case RTTI_BUILDING:
  2400. ((BuildingClass *)source)->Made_A_Kill();
  2401. break;
  2402. case RTTI_AIRCRAFT:
  2403. ((AircraftClass *)source)->Made_A_Kill();
  2404. break;
  2405. }
  2406. House->WhoLastHurtMe = source->Owner();
  2407. }
  2408. switch (What_Am_I()) {
  2409. case RTTI_BUILDING:
  2410. if ( ((BuildingClass *)this)->WhoLastHurtMe != HOUSE_NONE) {
  2411. House->BuildingsLost++;
  2412. }
  2413. if (source){
  2414. if (GameToPlay == GAME_INTERNET){
  2415. source->House->DestroyedBuildings->Increment_Unit_Total( ((BuildingClass*)this)->Class->Type );
  2416. }
  2417. source->House->BuildingsKilled[Owner()]++;
  2418. }
  2419. /*
  2420. ** If the map is displaying the multiplayer player names & their
  2421. ** # of kills, tell it to redraw.
  2422. */
  2423. if (Map.Is_Player_Names()) {
  2424. Map.Player_Names(true);
  2425. }
  2426. break;
  2427. case RTTI_AIRCRAFT:
  2428. House->UnitsLost++;
  2429. if (source){
  2430. if (GameToPlay == GAME_INTERNET){
  2431. source->House->DestroyedAircraft->Increment_Unit_Total( ((AircraftClass*)this)->Class->Type );
  2432. }
  2433. source->House->UnitsKilled[Owner()]++;
  2434. }
  2435. /*
  2436. ** If the map is displaying the multiplayer player names & their
  2437. ** # of kills, tell it to redraw.
  2438. */
  2439. if (Map.Is_Player_Names()) {
  2440. Map.Player_Names(true);
  2441. }
  2442. break;
  2443. case RTTI_INFANTRY:
  2444. House->UnitsLost++;
  2445. if (source){
  2446. if (GameToPlay == GAME_INTERNET){
  2447. source->House->DestroyedInfantry->Increment_Unit_Total( ((InfantryClass*)this)->Class->Type );
  2448. }
  2449. source->House->UnitsKilled[Owner()]++;
  2450. }
  2451. /*
  2452. ** If the map is displaying the multiplayer player names & their
  2453. ** # of kills, tell it to redraw.
  2454. */
  2455. if (Map.Is_Player_Names()) {
  2456. Map.Player_Names(true);
  2457. }
  2458. break;
  2459. case RTTI_UNIT:
  2460. House->UnitsLost++;
  2461. if (source){
  2462. if (GameToPlay == GAME_INTERNET){
  2463. source->House->DestroyedUnits->Increment_Unit_Total( ((UnitClass*)this)->Class->Type );
  2464. }
  2465. source->House->UnitsKilled[Owner()]++;
  2466. }
  2467. /*
  2468. ** If the map is displaying the multiplayer player names & their
  2469. ** # of kills, tell it to redraw.
  2470. */
  2471. if (Map.Is_Player_Names()) {
  2472. Map.Player_Names(true);
  2473. }
  2474. break;
  2475. default:
  2476. break;
  2477. }
  2478. }
  2479. /***********************************************************************************************
  2480. * TechnoClass::Nearby_Location -- Radiates outward looking for clear cell nearby. *
  2481. * *
  2482. * This routine is used to find a nearby location from center of this object. It can lean *
  2483. * toward finding a location closest to an optional object. *
  2484. * *
  2485. * INPUT: object -- Optional object that the finding algorithm will try to find a close *
  2486. * spot to. *
  2487. * *
  2488. * OUTPUT: Returns with the cell that is closest to this object. *
  2489. * *
  2490. * WARNINGS: none *
  2491. * *
  2492. * HISTORY: *
  2493. * 07/06/1995 JLB : Created. *
  2494. *=============================================================================================*/
  2495. CELL TechnoClass::Nearby_Location(TechnoClass const * ) const
  2496. {
  2497. /*
  2498. ** Radiate outward from the object's location, looking for the best
  2499. ** target.
  2500. */
  2501. CELL best = 0;
  2502. CELL cell = Coord_Cell(Center_Coord());
  2503. for (int radius = 0; radius < MAP_CELL_W/2; radius++) {
  2504. /*
  2505. ** Scan the top and bottom rows of the "box".
  2506. */
  2507. for (int x = -radius; x <= radius; x++) {
  2508. CELL newcell = cell + XY_Cell(x, -radius);
  2509. if (Map.In_Radar(newcell) && Map[newcell].Is_Generally_Clear()) {
  2510. best = newcell;
  2511. }
  2512. newcell = cell + XY_Cell(x, radius);
  2513. if (Map.In_Radar(newcell) && Map[newcell].Is_Generally_Clear()) {
  2514. best = newcell;
  2515. }
  2516. }
  2517. /*
  2518. ** Scan the left and right columns of the "box".
  2519. */
  2520. for (int y = -(radius-1); y < radius; y++) {
  2521. CELL newcell = cell + XY_Cell(-radius, y);
  2522. if (Map.In_Radar(newcell) && Map[newcell].Is_Generally_Clear()) {
  2523. best = newcell;
  2524. }
  2525. newcell = cell + XY_Cell(radius, y);
  2526. if (Map.In_Radar(newcell) && Map[newcell].Is_Generally_Clear()) {
  2527. best = newcell;
  2528. }
  2529. }
  2530. if (best) break;
  2531. }
  2532. return(best);
  2533. }
  2534. /***********************************************************************************************
  2535. * TechnoClass::Do_Uncloak -- Cause the stealth tank to uncloak. *
  2536. * *
  2537. * This routine will start the stealth tank to uncloak. *
  2538. * *
  2539. * INPUT: none *
  2540. * *
  2541. * OUTPUT: none *
  2542. * *
  2543. * WARNINGS: none *
  2544. * *
  2545. * HISTORY: *
  2546. * 05/08/1995 JLB : Created. *
  2547. *=============================================================================================*/
  2548. void TechnoClass::Do_Uncloak(void)
  2549. {
  2550. if (IsCloakable && (Cloak == CLOAKED || Cloak == CLOAKING)) {
  2551. Sound_Effect(VOC_CLOAK, Coord);
  2552. Cloak = UNCLOAKING;
  2553. CloakingDevice.Set_Stage(0);
  2554. CloakingDevice.Set_Rate(1);
  2555. }
  2556. }
  2557. /***********************************************************************************************
  2558. * TechnoClass::Do_Cloak -- Start the object into cloaking stage. *
  2559. * *
  2560. * This routine will start the object into its cloaking state. *
  2561. * *
  2562. * INPUT: none *
  2563. * *
  2564. * OUTPUT: none *
  2565. * *
  2566. * WARNINGS: none *
  2567. * *
  2568. * HISTORY: *
  2569. * 07/08/1995 JLB : Created. *
  2570. *=============================================================================================*/
  2571. void TechnoClass::Do_Cloak(void)
  2572. {
  2573. if (IsCloakable && (Cloak == UNCLOAKED || Cloak == UNCLOAKING)) {
  2574. Sound_Effect(VOC_CLOAK, Coord);
  2575. Detach_All(false);
  2576. Cloak = CLOAKING;
  2577. CloakingDevice.Set_Stage(0);
  2578. CloakingDevice.Set_Rate(1);
  2579. }
  2580. }
  2581. /***********************************************************************************************
  2582. * TechnoClass::Do_Shimmer -- Causes this object to shimmer if it is cloaked. *
  2583. * *
  2584. * This routine is called when this object should shimmer. If the object is cloaked, then *
  2585. * a shimmering effect (partial decloak) occurs. For objects that are not cloaked, no *
  2586. * affect occurs. *
  2587. * *
  2588. * INPUT: none *
  2589. * *
  2590. * OUTPUT: none *
  2591. * *
  2592. * WARNINGS: none *
  2593. * *
  2594. * HISTORY: *
  2595. * 07/29/1995 JLB : Created. *
  2596. *=============================================================================================*/
  2597. void TechnoClass::Do_Shimmer(void)
  2598. {
  2599. if (IsCloakable && Cloak == CLOAKED) {
  2600. Cloak = CLOAKING;
  2601. CloakingDevice.Set_Stage(MAX_UNCLOAK_STAGE/2);
  2602. CloakingDevice.Set_Rate(1);
  2603. }
  2604. }
  2605. /***********************************************************************************************
  2606. * TechnoClass::Visual_Character -- Determine the visual character of the object. *
  2607. * *
  2608. * This routine will determine how this object should be drawn. Typically, this is the *
  2609. * unmodified visible state, but cloaked objects have a different character. *
  2610. * *
  2611. * INPUT: raw -- Should the check be based on the unmodified cloak condition of the *
  2612. * object? If false, then an object owned by the player will never become *
  2613. * completely invisible. *
  2614. * *
  2615. * OUTPUT: Returns with the visual character to use when displaying this object. *
  2616. * *
  2617. * WARNINGS: none *
  2618. * *
  2619. * HISTORY: *
  2620. * 07/07/1995 JLB : Created. *
  2621. *=============================================================================================*/
  2622. VisualType TechnoClass::Visual_Character(bool raw)
  2623. {
  2624. /*
  2625. ** When uncloaked or in map editor mode, always draw the object normally.
  2626. */
  2627. if (Cloak == UNCLOAKED || Debug_Map) return(VISUAL_NORMAL);
  2628. /*
  2629. ** A cloaked unit will not be visible at all unless it is owned
  2630. ** by the player.
  2631. */
  2632. if (Cloak == CLOAKED) {
  2633. if (!raw && IsOwnedByPlayer) return(VISUAL_SHADOWY);
  2634. return(VISUAL_HIDDEN);
  2635. }
  2636. int stage = CloakingDevice.Fetch_Stage();
  2637. if (Cloak == UNCLOAKING) stage = MAX_UNCLOAK_STAGE - stage;
  2638. if (stage <= 0) {
  2639. return(VISUAL_NORMAL);
  2640. }
  2641. stage = Cardinal_To_Fixed(MAX_UNCLOAK_STAGE, stage);
  2642. if (stage < 0x0040) return(VISUAL_INDISTINCT);
  2643. if (stage < 0x0080) return(VISUAL_DARKEN);
  2644. if (stage < 0x00C0) return(VISUAL_SHADOWY);
  2645. if (!raw && IsOwnedByPlayer) return(VISUAL_SHADOWY);
  2646. if (stage < 0x00FF) return(VISUAL_RIPPLE);
  2647. return(VISUAL_HIDDEN);
  2648. }
  2649. /***********************************************************************************************
  2650. * TechnoClass::Techno_Draw_Object -- General purpose draw object routine. *
  2651. * *
  2652. * This routine is used to draw the object. It will handle any remapping or cloaking *
  2653. * effects required. This logic is isolated here since all techno object share the same *
  2654. * render logic when it comes to remapping and cloaking. *
  2655. * *
  2656. * INPUT: shapefile -- Pointer to the shape file that the shape will be drawn from. *
  2657. * *
  2658. * shapenum -- The shape number of the object in the file to use. *
  2659. * *
  2660. * x,y -- Center pixel coordinate to use for rendering this object. *
  2661. * *
  2662. * window -- The clipping window to use when rendering. *
  2663. * *
  2664. * OUTPUT: none *
  2665. * *
  2666. * WARNINGS: none *
  2667. * *
  2668. * HISTORY: *
  2669. * 07/08/1995 JLB : Created. *
  2670. *=============================================================================================*/
  2671. void TechnoClass::Techno_Draw_Object(void const * shapefile, int shapenum, int x, int y, WindowNumberType window)
  2672. {
  2673. if (shapefile) {
  2674. VisualType visual = Visual_Character();
  2675. void const * remap = Remap_Table();
  2676. if (visual != VISUAL_HIDDEN && visual != VISUAL_RIPPLE) {
  2677. if (visual == VISUAL_SHADOWY) {
  2678. CC_Draw_Shape(shapefile, shapenum, x, y, window, SHAPE_CENTER|SHAPE_WIN_REL|SHAPE_FADING|SHAPE_PREDATOR, NULL, Map.FadingShade);
  2679. } else {
  2680. CC_Draw_Shape(shapefile, shapenum, x, y, window, SHAPE_CENTER|SHAPE_WIN_REL|SHAPE_FADING|SHAPE_GHOST, remap, Map.UnitShadow);
  2681. }
  2682. if (visual == VISUAL_DARKEN) {
  2683. CC_Draw_Shape(shapefile, shapenum, x, y, window, SHAPE_PREDATOR|SHAPE_CENTER|SHAPE_WIN_REL|SHAPE_FADING, remap, Map.FadingShade);
  2684. }
  2685. }
  2686. if (visual != VISUAL_NORMAL && visual != VISUAL_HIDDEN) {
  2687. CC_Draw_Shape(shapefile, shapenum, x, y, window, SHAPE_PREDATOR|SHAPE_CENTER|SHAPE_WIN_REL);
  2688. }
  2689. }
  2690. }
  2691. /***********************************************************************************************
  2692. * TechnoClass::Remap_Table -- Fetches the appropriate remap table to use. *
  2693. * *
  2694. * This routine is used to fetch the appropriate remap table to use for this object. *
  2695. * *
  2696. * INPUT: none *
  2697. * *
  2698. * OUTPUT: Returns with a pointer to the remap table to use for this object. *
  2699. * *
  2700. * WARNINGS: none *
  2701. * *
  2702. * HISTORY: *
  2703. * 07/08/1995 JLB : Created. *
  2704. *=============================================================================================*/
  2705. void const * TechnoClass::Remap_Table(void)
  2706. {
  2707. return(House->Remap_Table(IsBlushing, true));
  2708. }
  2709. /***********************************************************************************************
  2710. * TechnoClass::Detach -- Handles removal of target from tracking system. *
  2711. * *
  2712. * This routine is called when the specified object is about to be removed from the game *
  2713. * system. The target object is removed from any tracking computers that this object may *
  2714. * have. *
  2715. * *
  2716. * INPUT: target -- The target object (as a target value) that is being removed from the *
  2717. * game. *
  2718. * *
  2719. * all -- Is the target about to die? A false value might indicate that the *
  2720. * object is merely cloaking. In such a case, radio contact will not *
  2721. * be affected. *
  2722. * *
  2723. * OUTPUT: none *
  2724. * *
  2725. * WARNINGS: none *
  2726. * *
  2727. * HISTORY: *
  2728. * 07/29/1995 JLB : Created. *
  2729. *=============================================================================================*/
  2730. void TechnoClass::Detach(TARGET target, bool all)
  2731. {
  2732. RadioClass::Detach(target, all);
  2733. if (SuspendedMission != MISSION_NONE && SuspendedTarCom == target) {
  2734. SuspendedMission = MISSION_NONE;
  2735. SuspendedTarCom = TARGET_NONE;
  2736. }
  2737. /*
  2738. ** If the targeting computer is assigned to the target, then the targeting
  2739. ** computer must be cleared.
  2740. */
  2741. if (TarCom == target) {
  2742. Assign_Target(TARGET_NONE);
  2743. Restore_Mission();
  2744. }
  2745. /*
  2746. ** If it is in radio contact with another object, then that radio contact
  2747. ** must be broken.
  2748. */
  2749. if (all && In_Radio_Contact() && Contact_With_Whom()->As_Target() == target) {
  2750. Transmit_Message(RADIO_OVER_OUT);
  2751. }
  2752. }
  2753. /***********************************************************************************************
  2754. * TechnoClass::Kill_Cargo -- Destroys any cargo attached to this object. *
  2755. * *
  2756. * This routine handles the destruction of any cargo this object may contain. Typical of *
  2757. * this would be when a transport helicopter gets destroyed. *
  2758. * *
  2759. * INPUT: source -- The source of the destruction of the cargo. *
  2760. * *
  2761. * OUTPUT: none *
  2762. * *
  2763. * WARNINGS: none *
  2764. * *
  2765. * HISTORY: *
  2766. * 07/29/1995 JLB : Created. *
  2767. *=============================================================================================*/
  2768. void TechnoClass::Kill_Cargo(TechnoClass * source)
  2769. {
  2770. while (Is_Something_Attached()) {
  2771. FootClass * foot = Detach_Object();
  2772. if (foot) {
  2773. foot->Record_The_Kill(source);
  2774. delete foot;
  2775. }
  2776. }
  2777. }
  2778. /***********************************************************************************************
  2779. * TechnoClass::Crew_Type -- Fetches the kind of crew this object contains. *
  2780. * *
  2781. * This routine is called when generating survivors to this object. This routine returns *
  2782. * the type of survivor to generate. *
  2783. * *
  2784. * INPUT: none *
  2785. * *
  2786. * OUTPUT: Returns the infantry type of a survivor. *
  2787. * *
  2788. * WARNINGS: This routine is designed to be called repeatedly. Once for each survivor to *
  2789. * generate. *
  2790. * *
  2791. * HISTORY: *
  2792. * 07/29/1995 JLB : Created. *
  2793. *=============================================================================================*/
  2794. InfantryType TechnoClass::Crew_Type(void) const
  2795. {
  2796. InfantryType infantry = INFANTRY_E1;
  2797. if (House->ActLike == HOUSE_NEUTRAL) {
  2798. infantry = Random_Pick(INFANTRY_C1, INFANTRY_C9);
  2799. } else {
  2800. if (Techno_Type_Class()->Primary == WEAPON_NONE && Random_Pick(0, 6) == 1) {
  2801. if (Random_Pick(0, 1) == 0) {
  2802. infantry = INFANTRY_C1;
  2803. } else {
  2804. infantry = INFANTRY_C7;
  2805. }
  2806. }
  2807. }
  2808. return(infantry);
  2809. }
  2810. /***********************************************************************************************
  2811. * TechnoClass::Value -- Fetches the target value for this object. *
  2812. * *
  2813. * This routine is used to fetch the target value for this object. The greater the value *
  2814. * returned, the better this object is as a target. *
  2815. * *
  2816. * INPUT: none *
  2817. * *
  2818. * OUTPUT: Returns with the target value for this object. *
  2819. * *
  2820. * WARNINGS: none *
  2821. * *
  2822. * HISTORY: *
  2823. * 07/29/1995 JLB : Created. *
  2824. * 08/16/1995 JLB : Adjusted for early mission lame-out. *
  2825. *=============================================================================================*/
  2826. int TechnoClass::Value(void) const
  2827. {
  2828. int value = 0;
  2829. /*
  2830. ** In early missions, contents of transports are not figured
  2831. ** into the total value. - 8/16/95
  2832. */
  2833. if (BuildLevel > 8 || GameToPlay != GAME_NORMAL) {
  2834. if (Is_Something_Attached()) {
  2835. FootClass * object = Attached_Object();
  2836. while (object) {
  2837. value += object->Value();
  2838. object = (FootClass *)object->Next;
  2839. }
  2840. }
  2841. }
  2842. return Risk() + Techno_Type_Class()->Reward + value;
  2843. }
  2844. /***********************************************************************************************
  2845. * TechnoClass::Threat_Range -- Returns the range to scan based on threat control. *
  2846. * *
  2847. * This routine will return the range to scan based on the control value specified. The *
  2848. * value returned by this routine is typically used when scanning for enemies. *
  2849. * *
  2850. * INPUT: control -- The range control parameter. *
  2851. * 0 = Use weapon range (zero is returned in this special case). *
  2852. * -1 = Scan without range restrictions (-1 is returned in this case). *
  2853. * 1 = Scan up to twice weapon range. *
  2854. * *
  2855. * OUTPUT: Returns with a range (or special value) that can be used in the threat scan *
  2856. * process. If zero is returned, then always check threat against In_Range(). If *
  2857. * -1 is returned, then no range limitation restriction exists. *
  2858. * *
  2859. * WARNINGS: none *
  2860. * *
  2861. * HISTORY: *
  2862. * 07/29/1995 JLB : Created. *
  2863. *=============================================================================================*/
  2864. int TechnoClass::Threat_Range(int control) const
  2865. {
  2866. if (control == -1) return(-1);
  2867. if (control == 0) return(0);
  2868. int range = MAX(Weapon_Range(0), Weapon_Range(1));
  2869. range *= 2;
  2870. range = Bound(range, 0x0000, 0x0A00);
  2871. return(range);
  2872. }
  2873. /***********************************************************************************************
  2874. * TechnoClass::Base_Is_Attacked -- Handle panic response to base being attacked. *
  2875. * *
  2876. * This routine is called when the base is being attacked. It will pull units off of the *
  2877. * field and send them back to defend the base. This routine will make taking an enemy *
  2878. * base much more difficult. *
  2879. * *
  2880. * INPUT: enemy -- Pointer to the enemy object that did the damage on the base. *
  2881. * *
  2882. * OUTPUT: none *
  2883. * *
  2884. * WARNINGS: This routine can drastically affect the game play. The computer will probably *
  2885. * call off its attacks as a result. *
  2886. * *
  2887. * HISTORY: *
  2888. * 06/25/1995 JLB : Commented. *
  2889. *=============================================================================================*/
  2890. void TechnoClass::Base_Is_Attacked(TechnoClass const *enemy)
  2891. {
  2892. FootClass *defender[6];
  2893. int value[6];
  2894. int count = 0;
  2895. int weakest = 0;
  2896. int desired = enemy->Risk() * 2;
  2897. int risktotal = 0;
  2898. /*
  2899. ** Humans have to deal with their own base is attacked problems.
  2900. */
  2901. if (!enemy || House->Is_Ally(enemy) || House->IsHuman) {
  2902. return;
  2903. }
  2904. /*
  2905. ** Don't overreact if this building can defend itself.
  2906. */
  2907. if (Techno_Type_Class()->Primary != WEAPON_NONE) return;
  2908. /*
  2909. ** If the enemy is not an infantry or a unit there is not much we can
  2910. ** do about it.
  2911. */
  2912. if (enemy->What_Am_I() != RTTI_INFANTRY && enemy->What_Am_I() != RTTI_UNIT ) {
  2913. return;
  2914. }
  2915. /*
  2916. ** If the enemy is a gunboat, then don't do anything.
  2917. */
  2918. // This should allow helicopters to retaliate however. Hmmm.
  2919. if (enemy->What_Am_I() == RTTI_UNIT && (*((UnitClass const *)enemy) == UNIT_GUNBOAT || *((UnitClass const *)enemy) == UNIT_HOVER)) {
  2920. return;
  2921. }
  2922. /*
  2923. ** If the threat has already been dealt with then we don't need to do
  2924. ** any work. Check for that here.
  2925. */
  2926. if (!((FootClass *)enemy)->BaseAttackTimer.Expired()) {
  2927. return;
  2928. }
  2929. /*
  2930. ** We will need units to defend our base. We need to suspend teams until
  2931. ** the situation has been dealt with.
  2932. */
  2933. TeamClass::Suspend_Teams(20);
  2934. /*
  2935. ** Loop through the infantry looking for those who are capable of going
  2936. ** on a rescue mission.
  2937. */
  2938. for (int index = 0; index < Infantry.Count() && desired > 0; index++) {
  2939. InfantryClass * infantry = Infantry.Ptr(index);
  2940. if (infantry && infantry->Owner() == Owner()) {
  2941. /*
  2942. ** Never recruite sticky guard units to defend a base.
  2943. */
  2944. if (infantry->Mission == MISSION_STICKY || infantry->Mission == MISSION_SLEEP) continue;
  2945. /*
  2946. ** Find the amount of threat that this unit can apply to the
  2947. ** enemy.
  2948. */
  2949. int threat = infantry->Rescue_Mission(enemy->As_Target());
  2950. /*
  2951. ** If it can't apply any threat then do just skip it and do not
  2952. ** add it to the list.
  2953. */
  2954. if (!threat) {
  2955. continue;
  2956. }
  2957. /*
  2958. ** If the value returned is negative then this unit is already
  2959. ** assigned to fighting the enemy, so subtract its value from
  2960. ** the enemys desired value.
  2961. */
  2962. if (threat < 0) {
  2963. desired += threat;
  2964. continue;
  2965. }
  2966. if (count < 6) {
  2967. defender[count] = (FootClass *)infantry;
  2968. value[count] = threat;
  2969. count++;
  2970. continue;
  2971. }
  2972. if (threat > weakest) {
  2973. int newweakest = threat;
  2974. for (int lp = 0; lp < count; lp ++) {
  2975. if (value[lp] == weakest) {
  2976. value[lp] = threat;
  2977. defender[lp] = (FootClass *) infantry;
  2978. continue;
  2979. }
  2980. if (value[count] < newweakest) {
  2981. newweakest = value[lp];
  2982. }
  2983. }
  2984. weakest = newweakest;
  2985. }
  2986. }
  2987. }
  2988. /*
  2989. ** Loop through the units looking for those who are capable of going
  2990. ** on a rescue mission.
  2991. */
  2992. for (index = 0; index < Units.Count() && desired > 0; index++) {
  2993. UnitClass * unit = Units.Ptr(index);
  2994. if (unit && unit->Owner() == Owner()) {
  2995. /*
  2996. ** Never recruite sticky guard units to defend a base.
  2997. */
  2998. if (unit->Mission == MISSION_STICKY || unit->Mission == MISSION_SLEEP) continue;
  2999. /*
  3000. ** Find the amount of threat that this unit can apply to the
  3001. ** enemy.
  3002. */
  3003. int threat = unit->Rescue_Mission(enemy->As_Target());
  3004. /*
  3005. ** If it can't apply any threat then do just skip it and do not
  3006. ** add it to the list.
  3007. */
  3008. if (!threat) {
  3009. continue;
  3010. }
  3011. /*
  3012. ** If the value returned is negative then this unit is already
  3013. ** assigned to fighting the enemy, so subtract its value from
  3014. ** the enemys desired value.
  3015. */
  3016. if (threat < 0) {
  3017. desired += threat;
  3018. continue;
  3019. }
  3020. if (count < 6) {
  3021. defender[count] = (FootClass *)unit;
  3022. value[count] = threat;
  3023. count++;
  3024. continue;
  3025. }
  3026. if (threat > weakest) {
  3027. int newweakest = threat;
  3028. for (int lp = 0; lp < count; lp ++) {
  3029. if (value[lp] == weakest) {
  3030. value[lp] = threat;
  3031. defender[lp] = (FootClass *) unit;
  3032. continue;
  3033. }
  3034. if (value[count] < newweakest) {
  3035. newweakest = value[lp];
  3036. }
  3037. }
  3038. weakest = newweakest;
  3039. }
  3040. }
  3041. }
  3042. if (desired > 0) {
  3043. /*
  3044. ** Sort the defenders by value, this doesn't take very long and will
  3045. ** help the closest defenders to respond.
  3046. */
  3047. for (int lp = 0; lp < count - 1; lp ++) {
  3048. for (int lp2 = lp + 1; lp2 < count; lp2++) {
  3049. if (value[lp] < value[lp2]) {
  3050. value[lp] ^= value[lp2];
  3051. value[lp2] ^= value[lp];
  3052. value[lp] ^= value[lp2];
  3053. FootClass *temp;
  3054. temp = defender[lp];
  3055. defender[lp] = defender[lp2];
  3056. defender[lp2] = temp;
  3057. }
  3058. }
  3059. }
  3060. for (lp = 0; lp < count; lp ++) {
  3061. defender[lp]->Assign_Mission(MISSION_RESCUE);
  3062. defender[lp]->Assign_Target(enemy->As_Target());
  3063. risktotal += defender[lp]->Risk();
  3064. if (risktotal > desired) {
  3065. break;
  3066. }
  3067. }
  3068. }
  3069. if (risktotal > desired) {
  3070. ((FootClass *)enemy)->BaseAttackTimer.Set(15 * 15);
  3071. }
  3072. }
  3073. /***********************************************************************************************
  3074. * TechnoClass::Get_Ownable -- Fetches the ownable bits for this object. *
  3075. * *
  3076. * This routine will return the ownable bits for this object. The ownable bits represent *
  3077. * the houses that are allowed to own this object. *
  3078. * *
  3079. * INPUT: none *
  3080. * *
  3081. * OUTPUT: Returns the ownable bits for this object. *
  3082. * *
  3083. * WARNINGS: none *
  3084. * *
  3085. * HISTORY: *
  3086. * 07/29/1995 JLB : Created. *
  3087. *=============================================================================================*/
  3088. unsigned char TechnoClass::Get_Ownable(void) const
  3089. {
  3090. return ((TechnoTypeClass const &)Class_Of()).Ownable;
  3091. }
  3092. /***********************************************************************************************
  3093. * TechnoClass::Is_Techno -- Confirms that this is a TechnoClass object. *
  3094. * *
  3095. * This routine is called to confirm if this object is derived from the TechnoClass *
  3096. * object. At this level, the return value will always be true. *
  3097. * *
  3098. * INPUT: none *
  3099. * *
  3100. * OUTPUT: Is this object a TechnoClass or derived from it? *
  3101. * *
  3102. * WARNINGS: none *
  3103. * *
  3104. * HISTORY: *
  3105. * 07/29/1995 JLB : Created. *
  3106. *=============================================================================================*/
  3107. bool TechnoClass::Is_Techno(void) const
  3108. {
  3109. return(true);
  3110. }
  3111. /***********************************************************************************************
  3112. * TechnoClass::Risk -- Fetches the risk associated with this object. *
  3113. * *
  3114. * This routine is called when the risk value for this object needs to be determined. *
  3115. * *
  3116. * INPUT: none *
  3117. * *
  3118. * OUTPUT: Returns with the risk value for this object. *
  3119. * *
  3120. * WARNINGS: none *
  3121. * *
  3122. * HISTORY: *
  3123. * 07/29/1995 JLB : Created. *
  3124. *=============================================================================================*/
  3125. int TechnoClass::Risk(void) const
  3126. {
  3127. return(Techno_Type_Class()->Risk);
  3128. }
  3129. /***********************************************************************************************
  3130. * TechnoClass::Tiberium_Load -- Fetches the current tiberium load percentage. *
  3131. * *
  3132. * This routine will return the current Tiberium load (expressed as a fixed point fraction) *
  3133. * that this object currently contains. Typical implementor of this function would be *
  3134. * the harvester. Any object that can return a non-zero value should derive from this *
  3135. * function in order to return the appropriate value. *
  3136. * *
  3137. * INPUT: none *
  3138. * *
  3139. * OUTPUT: Returns with the current Tiberium load expressed as a fixed point number. *
  3140. * 0x0000 = empty *
  3141. * 0x0080 = half full *
  3142. * 0x0100 = full *
  3143. * *
  3144. * WARNINGS: none *
  3145. * *
  3146. * HISTORY: *
  3147. * 07/29/1995 JLB : Created. *
  3148. *=============================================================================================*/
  3149. int TechnoClass::Tiberium_Load(void) const
  3150. {
  3151. return(0x0000);
  3152. }
  3153. /***********************************************************************************************
  3154. * TechnoClass::Desired_Load_Dir -- Fetches loading parameters for this object. *
  3155. * *
  3156. * This routine is called when an object desires to load up on this object. The object *
  3157. * desiring to load is specified. The cell that the loading object should move to is *
  3158. * determined. The direction that this object should face is also calculated. This routine *
  3159. * will be overridden by those objects that can actually load up passengers. *
  3160. * *
  3161. * INPUT: object -- The object that is desiring to load up. *
  3162. * *
  3163. * moveto -- Reference to the cell that the loading object should move to before *
  3164. * the final load process occurs (this value will be filled in). *
  3165. * *
  3166. * OUTPUT: Returns with the direction that the transport object should face. *
  3167. * *
  3168. * WARNINGS: none *
  3169. * *
  3170. * HISTORY: *
  3171. * 07/29/1995 JLB : Created. *
  3172. *=============================================================================================*/
  3173. DirType TechnoClass::Desired_Load_Dir(ObjectClass * , CELL & moveto) const
  3174. {
  3175. moveto = 0;
  3176. return(DIR_N);
  3177. }
  3178. /***********************************************************************************************
  3179. * TechnoClass::Pip_Count -- Fetches the number of pips to display on this object. *
  3180. * *
  3181. * This routine will return the number of pips to display on this object when the object *
  3182. * is selected. The default condition is to return no pips at all. This routine is *
  3183. * derived for those objects that can have pips. *
  3184. * *
  3185. * INPUT: none *
  3186. * *
  3187. * OUTPUT: Returns with the number of pips to display on this object when selected. *
  3188. * *
  3189. * WARNINGS: none *
  3190. * *
  3191. * HISTORY: *
  3192. * 07/29/1995 JLB : Created. *
  3193. *=============================================================================================*/
  3194. int TechnoClass::Pip_Count(void) const
  3195. {
  3196. return(0);
  3197. }
  3198. /***********************************************************************************************
  3199. * TechnoClass::Fire_Direction -- Fetches the direction projectile fire will take. *
  3200. * *
  3201. * This routine will fetch the direction that a fired projectile will take. This is *
  3202. * usually the facing of the object's weapon. This routine will be derived for the objects *
  3203. * that have their weapon barrel facing a different direction than the body. *
  3204. * *
  3205. * INPUT: none *
  3206. * *
  3207. * OUTPUT: Returns with the direction a fired projectile will take. *
  3208. * *
  3209. * WARNINGS: none *
  3210. * *
  3211. * HISTORY: *
  3212. * 07/29/1995 JLB : Created. *
  3213. *=============================================================================================*/
  3214. DirType TechnoClass::Fire_Direction(void) const
  3215. {
  3216. return(PrimaryFacing.Current());
  3217. }
  3218. /***********************************************************************************************
  3219. * TechnoClass::Response_Select -- Handles the voice response when selected. *
  3220. * *
  3221. * This routine is called when a voice reponse to a select action is desired. This routine *
  3222. * should be overridden for any object that actually has a voice response. *
  3223. * *
  3224. * INPUT: none *
  3225. * *
  3226. * OUTPUT: none *
  3227. * *
  3228. * WARNINGS: This routine can generate an audio response. *
  3229. * *
  3230. * HISTORY: *
  3231. * 07/29/1995 JLB : Created. *
  3232. *=============================================================================================*/
  3233. void TechnoClass::Response_Select(void)
  3234. {
  3235. }
  3236. /***********************************************************************************************
  3237. * TechnoClass::Response_Move -- Handles the voice repsonse to a movement request. *
  3238. * *
  3239. * This routine is called when a voice response to a movement order is desired. This *
  3240. * routine should be overridden for any object that actually has a voice response. *
  3241. * *
  3242. * INPUT: none *
  3243. * *
  3244. * OUTPUT: none *
  3245. * *
  3246. * WARNINGS: This can generate an audio repsonse. *
  3247. * *
  3248. * HISTORY: *
  3249. * 07/29/1995 JLB : Created. *
  3250. *=============================================================================================*/
  3251. void TechnoClass::Response_Move(void)
  3252. {
  3253. }
  3254. /***********************************************************************************************
  3255. * TechnoClass::Response_Attack -- Handles the voice response when given attack order. *
  3256. * *
  3257. * This routine is called when a voice response to an attack order is desired. This routine *
  3258. * should be overridden for any object that actually have a voice response. *
  3259. * *
  3260. * INPUT: none *
  3261. * *
  3262. * OUTPUT: none *
  3263. * *
  3264. * WARNINGS: This can generate an audio response. *
  3265. * *
  3266. * HISTORY: *
  3267. * 07/29/1995 JLB : Created. *
  3268. *=============================================================================================*/
  3269. void TechnoClass::Response_Attack(void)
  3270. {
  3271. }
  3272. /***********************************************************************************************
  3273. * TechnoClass::Target_Something_Nearby -- Handles finding and assigning a nearby target. *
  3274. * *
  3275. * This routine will search for a nearby target and assign it to this object's TarCom. *
  3276. * The method to use when scanning for a target is controlled by the parameter passed. *
  3277. * *
  3278. * INPUT: threat -- The threat control parameter used to control the range searched. The *
  3279. * only values recognized are THREAT_RANGE and THREAT_AREA. *
  3280. * *
  3281. * OUTPUT: Was a suitable target aquired and assigned to the TarCom? *
  3282. * *
  3283. * WARNINGS: none *
  3284. * *
  3285. * HISTORY: *
  3286. * 07/29/1995 JLB : Created. *
  3287. *=============================================================================================*/
  3288. bool TechnoClass::Target_Something_Nearby(ThreatType threat)
  3289. {
  3290. threat = threat & (THREAT_RANGE|THREAT_AREA);
  3291. /*
  3292. ** Determine that if there is an existing target it is still legal
  3293. ** and within range.
  3294. */
  3295. if (Target_Legal(TarCom)) {
  3296. if ((threat & THREAT_RANGE) && !In_Range(TarCom)) {
  3297. Assign_Target(TARGET_NONE);
  3298. }
  3299. }
  3300. /*
  3301. ** If there is no target, then try to find one and assign it as
  3302. ** the target for this unit.
  3303. */
  3304. if (!Target_Legal(TarCom)) {
  3305. Assign_Target(Greatest_Threat(threat));
  3306. }
  3307. /*
  3308. ** Return with answer to question: Does this unit have a target?
  3309. */
  3310. return(Target_Legal(TarCom));
  3311. }
  3312. /***********************************************************************************************
  3313. * TechnoClass::Exit_Object -- Causes specified object to leave this object. *
  3314. * *
  3315. * This routine is called when there is an attached object that should detach and leave *
  3316. * this object. Typical of this would be the refinery and APC. *
  3317. * *
  3318. * INPUT: object -- The object that is trying to leave this object. *
  3319. * *
  3320. * OUTPUT: Was the object successfully launched from this object? Failure might indicate that *
  3321. * there is insufficient room to detach the specified object. *
  3322. * *
  3323. * WARNINGS: none *
  3324. * *
  3325. * HISTORY: *
  3326. * 07/24/1995 JLB : Created. *
  3327. *=============================================================================================*/
  3328. int TechnoClass::Exit_Object(TechnoClass *)
  3329. {
  3330. return(0);
  3331. }
  3332. /***********************************************************************************************
  3333. * TechnoClass::Random_Animate -- Performs some idle animation for the object. *
  3334. * *
  3335. * This is a maintenance routine that is called when the object might want to check to see *
  3336. * if it should go into some idle animation. Infantry are a good example of objects that *
  3337. * perform idle animations. This routine must be overridden by the derived object types *
  3338. * in order to give it some functionality. *
  3339. * *
  3340. * INPUT: none *
  3341. * *
  3342. * OUTPUT: none *
  3343. * *
  3344. * WARNINGS: none *
  3345. * *
  3346. * HISTORY: *
  3347. * 07/24/1995 JLB : Created. *
  3348. *=============================================================================================*/
  3349. void TechnoClass::Random_Animate(void)
  3350. {
  3351. }
  3352. /***********************************************************************************************
  3353. * TechnoClass::Assign_Destination -- Assigns movement destination to the object. *
  3354. * *
  3355. * This routine is called when the object needs to have a new movement destination *
  3356. * assigned. This routine must be overridden since at this level, movement is not allowed. *
  3357. * *
  3358. * INPUT: destination -- The destination to assign to this object. *
  3359. * *
  3360. * OUTPUT: none *
  3361. * *
  3362. * WARNINGS: none *
  3363. * *
  3364. * HISTORY: *
  3365. * 07/24/1995 JLB : Created. *
  3366. *=============================================================================================*/
  3367. void TechnoClass::Assign_Destination(TARGET )
  3368. {
  3369. }
  3370. /***********************************************************************************************
  3371. * TechnoClass::Scatter -- Causes the object to scatter to an adjacent cell. *
  3372. * *
  3373. * This routine is called when the object needs to get out of the way. This might be as a *
  3374. * result of combat or findpath reasons. *
  3375. * *
  3376. * INPUT: coord -- The source of the reason to scatter. The object should try to run *
  3377. * away from this coordinate. *
  3378. * *
  3379. * forced -- Is the scatter a forced scatter? If false, then this is merely a *
  3380. * request that scattering might be a good idea. *
  3381. * *
  3382. * OUTPUT: none *
  3383. * *
  3384. * WARNINGS: none *
  3385. * *
  3386. * HISTORY: *
  3387. * 07/24/1995 JLB : Created. *
  3388. *=============================================================================================*/
  3389. void TechnoClass::Scatter(COORDINATE , bool )
  3390. {
  3391. }
  3392. /***********************************************************************************************
  3393. * TechnoClass::Enter_Idle_Mode -- Object enters its default idle condition. *
  3394. * *
  3395. * This routine is called when the object should intelligently revert to an idle state. *
  3396. * Typically this routine is called after some mission has completed. This routine must *
  3397. * be overridden by the various object types. It is located at this level merely to provide *
  3398. * a virtual function entry point. *
  3399. * *
  3400. * INPUT: initial -- Is this called when the unit just leaves a factory or is initially *
  3401. * or is initially placed on the map? *
  3402. * *
  3403. * OUTPUT: none *
  3404. * *
  3405. * WARNINGS: none *
  3406. * *
  3407. * HISTORY: *
  3408. * 07/24/1995 JLB : Created. *
  3409. *=============================================================================================*/
  3410. void TechnoClass::Enter_Idle_Mode(bool )
  3411. {
  3412. }
  3413. /***********************************************************************************************
  3414. * TechnoClass::Draw_Pips -- Draws the transport pips and other techno graphics. *
  3415. * *
  3416. * This routine is used to render the small transportation pip (occupant feedback graphic) *
  3417. * used for transporter object. It will also display if the techno object is "primary" *
  3418. * if necessary. *
  3419. * *
  3420. * INPUT: x,y -- The pixel coordinate for the center of the first pip. Subsiquent pips *
  3421. * are drawn rightward. *
  3422. * *
  3423. * window-- The window that pip clipping is relative to. *
  3424. * *
  3425. * OUTPUT: none *
  3426. * *
  3427. * WARNINGS: none *
  3428. * *
  3429. * HISTORY: *
  3430. * 08/08/1995 JLB : Created. *
  3431. *=============================================================================================*/
  3432. void TechnoClass::Draw_Pips(int x, int y, WindowNumberType window)
  3433. {
  3434. /*
  3435. ** Transporter type objects have a different graphic representation for the pips. The
  3436. ** pip color represents the type of occupant.
  3437. */
  3438. if (Techno_Type_Class()->IsTransporter) {
  3439. ObjectClass const * object = Attached_Object();
  3440. for (int index = 0; index < Class_Of().Max_Pips(); index++) {
  3441. PipEnum pip = PIP_EMPTY;
  3442. if (object) {
  3443. pip = PIP_FULL;
  3444. if (object->What_Am_I() == RTTI_INFANTRY) {
  3445. if (*((InfantryClass *)object) == INFANTRY_RAMBO) {
  3446. pip = PIP_COMMANDO;
  3447. }
  3448. if (*((InfantryClass *)object) == INFANTRY_E7) {
  3449. pip = PIP_ENGINEER;
  3450. }
  3451. if (((InfantryClass *)object)->Class->IsCivilian) {
  3452. pip = PIP_CIVILIAN;
  3453. }
  3454. }
  3455. object = object->Next;
  3456. }
  3457. CC_Draw_Shape(Class_Of().PipShapes, pip, x+index*3, y, window, SHAPE_CENTER|SHAPE_WIN_REL);
  3458. }
  3459. } else {
  3460. /*
  3461. ** Display number of how many attached objects there are. This is also used
  3462. ** to display the fullness rating for a harvester.
  3463. */
  3464. int pips = Pip_Count();
  3465. for (int index = 0; index < Class_Of().Max_Pips(); index++) {
  3466. CC_Draw_Shape(Class_Of().PipShapes, (index < pips) ? PIP_FULL : PIP_EMPTY, x+index*3, y, window, SHAPE_CENTER|SHAPE_WIN_REL);
  3467. }
  3468. }
  3469. /*
  3470. ** Display whether this unit is a leader unit or not.
  3471. */
  3472. if (IsLeader) {
  3473. CC_Draw_Shape(Class_Of().PipShapes, PIP_PRIMARY, x-2, y-3, window, /*SHAPE_CENTER|*/SHAPE_WIN_REL);
  3474. }
  3475. }
  3476. /***********************************************************************************************
  3477. * TechnoClass::Find_Docking_Bay -- Searches for a close docking bay. *
  3478. * *
  3479. * This routine will be used to find a building that can serve as a docking bay. The *
  3480. * closest building that qualifies will be returned. If no building could be found then *
  3481. * return with NULL. *
  3482. * *
  3483. * INPUT: b -- The structure type to look for. *
  3484. * *
  3485. * friendly -- Allow searching for allied buildings as well. *
  3486. * *
  3487. * OUTPUT: Returns with a pointer to the building that can serve as the best docking bay. *
  3488. * *
  3489. * WARNINGS: This routine might return NULL even if there are buildings of the specified *
  3490. * type available. This is the case when the building(s) are currently busy and *
  3491. * cannot serve as a docking bay at the moment. *
  3492. * *
  3493. * HISTORY: *
  3494. * 07/18/1995 JLB : Created. *
  3495. * 08/13/1995 JLB : Recognizes the "IsLeader" method of building preference. *
  3496. *=============================================================================================*/
  3497. BuildingClass * TechnoClass::Find_Docking_Bay(StructType b, bool friendly) const
  3498. {
  3499. BuildingClass * best = 0;
  3500. /*
  3501. ** First check to see if there are ANY buildings of the specified
  3502. ** type in thi house's inventory. If not, then don't bother to scan
  3503. ** for one.
  3504. */
  3505. if (House->BScan & (1L << b)) {
  3506. int bestval = -1;
  3507. /*
  3508. ** Loop through all the buildings and find the one that matches the specification
  3509. ** and is willing to dock with this object.
  3510. */
  3511. for (int index = 0; index < Buildings.Count(); index++) {
  3512. BuildingClass * building = Buildings.Ptr(index);
  3513. /*
  3514. ** Check to see if the building qualifies (preliminary scan).
  3515. */
  3516. if (building &&
  3517. (friendly ? building->House->Is_Ally(this) : building->House == House) &&
  3518. !building->IsInLimbo &&
  3519. *building == b &&
  3520. ((TechnoClass *)this)->Transmit_Message(RADIO_CAN_LOAD, building) == RADIO_ROGER) {
  3521. /*
  3522. ** If the building qualifies and this building is better than the
  3523. ** last qualifying building (as rated by distance), then record
  3524. ** this building and keep scanning.
  3525. */
  3526. if (bestval == -1 || Distance(building) < bestval || building->IsLeader) {
  3527. best = building;
  3528. bestval = Distance(building);
  3529. }
  3530. }
  3531. }
  3532. }
  3533. return(best);
  3534. }
  3535. /***********************************************************************************************
  3536. * TechnoClass::Find_Exit_Cell -- Finds an appropriate exit cell for this object. *
  3537. * *
  3538. * This routine is called when an object would like to exit from this (presumed) transport. *
  3539. * A suitable cell should be returned by this routine. The specified object will probably *
  3540. * be unloaded at that cell. *
  3541. * *
  3542. * INPUT: techno -- Pointer to the object that would like to unload. This is used to *
  3543. * determine suitability for placement. *
  3544. * *
  3545. * OUTPUT: Returns with the cell that is recommended for object exit. *
  3546. * *
  3547. * WARNINGS: none *
  3548. * *
  3549. * HISTORY: *
  3550. * 08/12/1995 JLB : Created. *
  3551. *=============================================================================================*/
  3552. CELL TechnoClass::Find_Exit_Cell(TechnoClass const * ) const
  3553. {
  3554. return(Coord_Cell(Docking_Coord()));
  3555. }
  3556. /***********************************************************************************************
  3557. * TechnoClass::Refund_Amount -- Returns with the money to refund if this object is sold. *
  3558. * *
  3559. * This routine is used by the selling back mechanism in order to credit the owning house *
  3560. * with some refund credits. The value returned is the credits to refund to the owner. *
  3561. * *
  3562. * INPUT: none *
  3563. * *
  3564. * OUTPUT: Returns with the credits to refund to the owner. *
  3565. * *
  3566. * WARNINGS: none *
  3567. * *
  3568. * HISTORY: *
  3569. * 08/13/1995 JLB : Created. *
  3570. *=============================================================================================*/
  3571. int TechnoClass::Refund_Amount(void) const
  3572. {
  3573. int cost = Techno_Type_Class()->Raw_Cost();
  3574. /*
  3575. ** If the object is carrying Tiberium directly (i.e., the harvester), then
  3576. ** account for the credits of the load.
  3577. */
  3578. cost += Fixed_To_Cardinal(UnitTypeClass::FULL_LOAD_CREDITS, Tiberium_Load())/2;
  3579. if (House->IsHuman) {
  3580. cost /= 2;
  3581. }
  3582. return(cost);
  3583. }