MAPEDIT.CPP 69 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923
  1. //
  2. // Copyright 2020 Electronic Arts Inc.
  3. //
  4. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
  5. // software: you can redistribute it and/or modify it under the terms of
  6. // the GNU General Public License as published by the Free Software Foundation,
  7. // either version 3 of the License, or (at your option) any later version.
  8. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
  9. // in the hope that it will be useful, but with permitted additional restrictions
  10. // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
  11. // distributed with this program. You should have received a copy of the
  12. // GNU General Public License along with permitted additional restrictions
  13. // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
  14. /* $Header: F:\projects\c&c\vcs\code\mapedit.cpv 2.18 16 Oct 1995 16:48:40 JOE_BOSTIC $ */
  15. /***************************************************************************
  16. ** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S **
  17. ***************************************************************************
  18. * *
  19. * Project Name : Command & Conquer *
  20. * *
  21. * File Name : MAPEDIT.CPP *
  22. * *
  23. * Programmer : Bill Randolph *
  24. * *
  25. * Start Date : October 20, 1994 *
  26. * *
  27. * Last Update : February 2, 1995 [BR] *
  28. * *
  29. *-------------------------------------------------------------------------*
  30. * Map Editor overloaded routines & utility routines *
  31. *-------------------------------------------------------------------------*
  32. * Map Editor modules: *
  33. * (Yes, they're all one huge class.) *
  34. * mapedit.cpp: overloaded routines, utility routines *
  35. * mapeddlg.cpp: map editor dialogs, most of the main menu options *
  36. * mapedplc.cpp: object-placing routines *
  37. * mapedsel.cpp: object-selection & manipulation routines *
  38. * mapedtm.cpp: team-editing routines *
  39. *-------------------------------------------------------------------------*
  40. * Functions: *
  41. * MapEditClass::MapEditClass -- class constructor *
  42. * MapEditClass::One_Time -- one-time initialization *
  43. * MapEditClass::Read_INI -- overloaded Read_INI function *
  44. * MapEditClass::Clear_List -- clears the internal choosable object list *
  45. * MapEditClass::Add_To_List -- adds a TypeClass to the choosable list *
  46. * MapEditClass::AI -- The map editor's main logic *
  47. * MapEditClass::Draw_It -- overloaded Redraw routine *
  48. * MapEditClass::Main_Menu -- main menu processor for map editor *
  49. * MapEditClass::AI_Menu -- menu of AI options *
  50. * MapEditClass::Mouse_Moved -- checks for mouse motion *
  51. * MapEditClass::Verify_House -- sees if given house can own given obj *
  52. * MapEditClass::Cycle_House -- finds next valid house for object type *
  53. * MapEditClass::Trigger_Needs_Team -- tells if a trigger needs a team *
  54. * MapEditClass::Fatal -- exits with error message *
  55. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  56. #include "function.h"
  57. #ifdef SCENARIO_EDITOR
  58. /*
  59. ****************************** Globals/Externs ******************************
  60. */
  61. /*...........................................................................
  62. Array of all missions supported by the map editor
  63. ...........................................................................*/
  64. MissionType MapEditClass::MapEditMissions[] = {
  65. MISSION_GUARD,
  66. MISSION_STICKY,
  67. MISSION_HARVEST,
  68. MISSION_GUARD_AREA,
  69. MISSION_RETURN,
  70. MISSION_AMBUSH,
  71. MISSION_HUNT,
  72. MISSION_SLEEP,
  73. };
  74. #define NUM_EDIT_MISSIONS (sizeof(MapEditClass::MapEditMissions) / sizeof(MapEditClass::MapEditMissions[0]))
  75. /*...........................................................................
  76. For menu processing
  77. ...........................................................................*/
  78. extern int UnknownKey; // in menus.cpp
  79. char MapEditClass::HealthBuf[20];
  80. /***************************************************************************
  81. * MapEditClass::MapEditClass -- class constructor *
  82. * *
  83. * INPUT: *
  84. * none. *
  85. * *
  86. * OUTPUT: *
  87. * none. *
  88. * *
  89. * WARNINGS: *
  90. * none. *
  91. * *
  92. * HISTORY: *
  93. * 10/20/1994 BR : Created. *
  94. *=========================================================================*/
  95. MapEditClass::MapEditClass(void)
  96. {
  97. /*
  98. ** Init data members.
  99. */
  100. ScenVar = SCEN_VAR_A;
  101. ObjCount = 0;
  102. LastChoice = 0;
  103. LastHouse = HOUSE_GOOD;
  104. GrabbedObject = 0;
  105. for (int i=0; i < NUM_EDIT_CLASSES; i++) {
  106. NumType[i] = 0;
  107. TypeOffset[i] = 0;
  108. }
  109. Waypoint[WAYPT_HOME] = 0;
  110. CurrentCell = 0;
  111. CurTrigger = NULL;
  112. Changed = 0;
  113. LMouseDown = 0;
  114. BaseBuilding = 0;
  115. BasePercent = 100;
  116. }
  117. /***************************************************************************
  118. * MapEditClass::One_Time -- one-time initialization *
  119. * *
  120. * INPUT: *
  121. * none. *
  122. * *
  123. * OUTPUT: *
  124. * none. *
  125. * *
  126. * WARNINGS: *
  127. * none. *
  128. * *
  129. * HISTORY: *
  130. * 02/02/1995 BR : Created. *
  131. *=========================================================================*/
  132. void MapEditClass::One_Time(void)
  133. {
  134. MouseClass::One_Time();
  135. /*------------------------------------------------------------------------
  136. Create the pop-up controls
  137. ------------------------------------------------------------------------*/
  138. /*........................................................................
  139. The map: a single large "button"
  140. ........................................................................*/
  141. //MapArea = new ControlClass(MAP_AREA,0,8,312,192, GadgetClass::LEFTPRESS |
  142. //GadgetClass::LEFTRELEASE, false);
  143. MapArea = new ControlClass(MAP_AREA,0,16,624,384, GadgetClass::LEFTPRESS |
  144. GadgetClass::LEFTRELEASE, false);
  145. /*........................................................................
  146. House buttons
  147. ........................................................................*/
  148. GDIButton = new TextButtonClass (POPUP_GDI, "GDI",
  149. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  150. POPUP_GDI_X, POPUP_GDI_Y, POPUP_GDI_W, POPUP_GDI_H);
  151. NODButton = new TextButtonClass (POPUP_NOD, "NOD",
  152. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  153. POPUP_NOD_X, POPUP_NOD_Y, POPUP_NOD_W, POPUP_NOD_H);
  154. NeutralButton = new TextButtonClass (POPUP_NEUTRAL, "Neutral",
  155. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  156. POPUP_NEUTRAL_X, POPUP_NEUTRAL_Y, POPUP_NEUTRAL_W, POPUP_NEUTRAL_H);
  157. Multi1Button = new TextButtonClass (POPUP_MULTI1, "M1",
  158. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  159. POPUP_MULTI1_X, POPUP_MULTI1_Y, POPUP_MULTI1_W, POPUP_MULTI1_H);
  160. Multi2Button = new TextButtonClass (POPUP_MULTI2, "M2",
  161. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  162. POPUP_MULTI2_X, POPUP_MULTI2_Y, POPUP_MULTI2_W, POPUP_MULTI2_H);
  163. Multi3Button = new TextButtonClass (POPUP_MULTI3, "M3",
  164. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  165. POPUP_MULTI3_X, POPUP_MULTI3_Y, POPUP_MULTI3_W, POPUP_MULTI3_H);
  166. Multi4Button = new TextButtonClass (POPUP_MULTI4, "M4",
  167. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  168. POPUP_MULTI4_X, POPUP_MULTI4_Y, POPUP_MULTI4_W, POPUP_MULTI4_H);
  169. /*........................................................................
  170. The mission list box
  171. ........................................................................*/
  172. MissionList = new ListClass (POPUP_MISSIONLIST,
  173. POPUP_MISSION_X, POPUP_MISSION_Y, POPUP_MISSION_W, POPUP_MISSION_H,
  174. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  175. Hires_Retrieve("BTN-UP.SHP"),
  176. Hires_Retrieve("BTN-DN.SHP"));
  177. for (int i = 0; i < NUM_EDIT_MISSIONS; i++) {
  178. MissionList->Add_Item (MissionClass::Mission_Name(MapEditMissions[i]));
  179. }
  180. /*........................................................................
  181. The health bar
  182. ........................................................................*/
  183. HealthGauge = new TriColorGaugeClass (POPUP_HEALTHGAUGE,
  184. POPUP_HEALTH_X, POPUP_HEALTH_Y, POPUP_HEALTH_W, POPUP_HEALTH_H);
  185. HealthGauge->Use_Thumb(true);
  186. HealthGauge->Set_Maximum(0x100);
  187. HealthGauge->Set_Red_Limit(0x3f - 1);
  188. HealthGauge->Set_Yellow_Limit(0x7f - 1);
  189. /*........................................................................
  190. The health text label
  191. ........................................................................*/
  192. HealthBuf[0] = 0;
  193. HealthText = new TextLabelClass (HealthBuf,
  194. POPUP_HEALTH_X + POPUP_HEALTH_W / 2,
  195. POPUP_HEALTH_Y + POPUP_HEALTH_H + 1,
  196. CC_GREEN, TPF_CENTER | TPF_FULLSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL);
  197. /*........................................................................
  198. The facing dial
  199. ........................................................................*/
  200. FacingDial = new Dial8Class (POPUP_FACINGDIAL, POPUP_FACEBOX_X,
  201. POPUP_FACEBOX_Y, POPUP_FACEBOX_W, POPUP_FACEBOX_H, (DirType)0);
  202. /*........................................................................
  203. The base percent-built slider & its label
  204. ........................................................................*/
  205. BaseGauge = new GaugeClass (POPUP_BASEPERCENT,
  206. POPUP_BASE_X, POPUP_BASE_Y, POPUP_BASE_W, POPUP_BASE_H);
  207. BaseLabel = new TextLabelClass ("Base:", POPUP_BASE_X - 3, POPUP_BASE_Y,
  208. CC_GREEN, TPF_RIGHT | TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL);
  209. BaseGauge->Set_Maximum(100);
  210. BaseGauge->Set_Value(BasePercent);
  211. }
  212. /***********************************************************************************************
  213. * MapeditClass::Init_IO -- Reinitializes the radar map at scenario start. *
  214. * *
  215. * INPUT: none *
  216. * *
  217. * OUTPUT: none *
  218. * *
  219. * WARNINGS: none *
  220. * *
  221. * HISTORY: *
  222. * 12/22/1994 JLB : Created. *
  223. *=============================================================================================*/
  224. void MapEditClass::Init_IO(void)
  225. {
  226. /*------------------------------------------------------------------------
  227. For normal game mode, jump to the parent's Init routine.
  228. ------------------------------------------------------------------------*/
  229. if (!Debug_Map) {
  230. MouseClass::Init_IO();
  231. } else {
  232. /*------------------------------------------------------------------------
  233. For editor mode, add the map area to the button input list
  234. ------------------------------------------------------------------------*/
  235. Buttons = 0;
  236. Add_A_Button(*BaseGauge);
  237. Add_A_Button(*BaseLabel);
  238. Add_A_Button(*MapArea);
  239. }
  240. }
  241. /***************************************************************************
  242. * MapEditClass::Read_INI -- overloaded Read_INI function *
  243. * *
  244. * Overloading this function gives the map editor a chance to initialize *
  245. * certain values every time a new INI is read. *
  246. * *
  247. * INPUT: *
  248. * buffer INI staging area *
  249. * *
  250. * OUTPUT: *
  251. * none. *
  252. * *
  253. * WARNINGS: *
  254. * none. *
  255. * *
  256. * HISTORY: *
  257. * 11/16/1994 BR : Created. *
  258. *=========================================================================*/
  259. void MapEditClass::Read_INI(char *buffer)
  260. {
  261. /*
  262. ------------------------ Invoke parent's Read_INI ------------------------
  263. */
  264. MouseClass::Read_INI(buffer);
  265. BasePercent = WWGetPrivateProfileInt("Basic","Percent",0,buffer);
  266. BaseGauge->Set_Value(BasePercent);
  267. }
  268. /***************************************************************************
  269. * MapEditClass::Write_INI -- overloaded Read_INI function *
  270. * *
  271. * INPUT: *
  272. * buffer INI staging area *
  273. * *
  274. * OUTPUT: *
  275. * none. *
  276. * *
  277. * WARNINGS: *
  278. * none. *
  279. * *
  280. * HISTORY: *
  281. * 11/16/1994 BR : Created. *
  282. *=========================================================================*/
  283. void MapEditClass::Write_INI(char *buffer)
  284. {
  285. /*
  286. ----------------------- Invoke parent's Write_INI ------------------------
  287. */
  288. MouseClass::Write_INI(buffer);
  289. /*
  290. ** Save the base's percent-built value; this must be saved into the BASIC
  291. ** section of the INI, since the Base section will be entirely erased
  292. ** by the Base's Write_INI routine.
  293. */
  294. WWWritePrivateProfileInt("Basic", "Percent", BasePercent, buffer);
  295. }
  296. /***************************************************************************
  297. * MapEditClass::Clear_List -- clears the internal choosable object list *
  298. * *
  299. * INPUT: *
  300. * none. *
  301. * *
  302. * OUTPUT: *
  303. * none. *
  304. * *
  305. * WARNINGS: *
  306. * none. *
  307. * *
  308. * HISTORY: *
  309. * 10/20/1994 BR : Created. *
  310. *=========================================================================*/
  311. void MapEditClass::Clear_List(void)
  312. {
  313. /*------------------------------------------------------------------------
  314. Set # object type ptrs to 0, set NumType for each type to 0
  315. ------------------------------------------------------------------------*/
  316. ObjCount = 0;
  317. for (int i = 0; i < NUM_EDIT_CLASSES; i++) {
  318. NumType[i] = 0;
  319. }
  320. }
  321. /***************************************************************************
  322. * MapEditClass::Add_To_List -- adds a TypeClass to the choosable list *
  323. * *
  324. * Use this routine to add an object to the game object selection list. *
  325. * This list is used by the Add_Object function. All items located in the *
  326. * list will appear and be chooseable by that function. Make sure to *
  327. * clear the list before adding a sequence of items to it. Clearing *
  328. * the list is accomplished by the Clear_List() function. *
  329. * *
  330. * INPUT: *
  331. * object ptr to ObjectTypeClass to add *
  332. * *
  333. * OUTPUT: *
  334. * bool: was the object added to the list? A failure could occur if *
  335. * NULL were passed in or the list is full. *
  336. * *
  337. * WARNINGS: *
  338. * none. *
  339. * *
  340. * HISTORY: *
  341. * 06/04/1994 JLB : Created. *
  342. *=========================================================================*/
  343. bool MapEditClass::Add_To_List(ObjectTypeClass const *object)
  344. {
  345. /*
  346. ** Add the object if there's room.
  347. */
  348. if (object && ObjCount < MAX_EDIT_OBJECTS) {
  349. Objects[ObjCount++] = object;
  350. /*
  351. ** Update type counters.
  352. */
  353. switch (object->What_Am_I()) {
  354. case RTTI_TEMPLATETYPE:
  355. NumType[0]++;
  356. break;
  357. case RTTI_OVERLAYTYPE:
  358. NumType[1]++;
  359. break;
  360. case RTTI_SMUDGETYPE:
  361. NumType[2]++;
  362. break;
  363. case RTTI_TERRAINTYPE:
  364. NumType[3]++;
  365. break;
  366. case RTTI_UNITTYPE:
  367. NumType[4]++;
  368. break;
  369. case RTTI_INFANTRYTYPE:
  370. NumType[5]++;
  371. break;
  372. case RTTI_AIRCRAFTTYPE:
  373. NumType[6]++;
  374. break;
  375. case RTTI_BUILDINGTYPE:
  376. NumType[7]++;
  377. break;
  378. }
  379. return(true);
  380. }
  381. return(false);
  382. }
  383. /***************************************************************************
  384. * MapEditClass::AI -- The map editor's main logic *
  385. * *
  386. * This routine overloads the parent's (DisplayClass) AI function. *
  387. * It checks for any input specific to map editing, and calls the parent *
  388. * AI routine to handle scrolling and other mainstream map stuff. *
  389. * *
  390. * If this detects one of its special input keys, it sets 'input' to 0 *
  391. * before calling the parent AI routine; this prevents input conflict. *
  392. * *
  393. * SUPPORTED INPUT: *
  394. * General: *
  395. * F2/RMOUSE: main menu *
  396. * F6: toggles show-passable mode *
  397. * HOME: go to the Home Cell (scenario's start position)*
  398. * SHIFT-HOME: set the Home Cell to the current TacticalCell*
  399. * ESC: exits to DOS *
  400. * Object Placement: *
  401. * INSERT: go into placement mode *
  402. * ESC: exit placement mode *
  403. * LEFT/RIGHT: prev/next placement object *
  404. * PGUP/PGDN: prev/next placement category *
  405. * HOME: 1st placement object (clear template) *
  406. * h/H: toggle house of placement object *
  407. * LMOUSE: place the placement object *
  408. * MOUSE MOTION: "paint" with the placement object *
  409. * Object selection: *
  410. * LMOUSE: select & "grab" current object *
  411. * If no object is present where the mouse is *
  412. * clicked, the current object is de-selected *
  413. * If the same object is clicked on, it stays *
  414. * selected. Also displays the object-editing *
  415. * gadgets. *
  416. * LMOUSE RLSE: release currently-grabbed object *
  417. * MOUSE MOTION: if an object is grabbed, moves the object *
  418. * SHIFT|ALT|ARROW: moves object in that direction *
  419. * DELETE deletes currently-selected object *
  420. * Object-editing controls: *
  421. * POPUP_GDI: makes GDI the owner of this object *
  422. * POPUP_NOD: makes NOD the owner of this object *
  423. * POPUP_MISSIONLIST: sets that mission for this object *
  424. * POPUP_HEALTHGAUGE: sets that health value for this object *
  425. * POPUP_FACINGDIAL: sets the object's facing *
  426. * *
  427. * Changed is set when you: *
  428. * - place an object *
  429. * - move a grabbed object *
  430. * - delete an object *
  431. * - size the map *
  432. * - create a new scenario *
  433. * Changed is cleared when you: *
  434. * - Save the scenario *
  435. * - Load a scenario *
  436. * - Play the scenario *
  437. * *
  438. * INPUT: *
  439. * input KN_ value, 0 if none *
  440. * *
  441. * OUTPUT: *
  442. * none. *
  443. * *
  444. * WARNINGS: *
  445. * none. *
  446. * *
  447. * HISTORY: *
  448. * 10/20/1994 BR : Created. *
  449. *=========================================================================*/
  450. void MapEditClass::AI(KeyNumType &input, int x, int y)
  451. {
  452. int rc;
  453. MissionType mission;
  454. int strength;
  455. CELL cell;
  456. int i;
  457. int found; // for removing a waypoint label
  458. int waypt_idx; // for labelling a waypoint
  459. BaseNodeClass *node; // for removing from an AI Base
  460. HousesType house;
  461. /*------------------------------------------------------------------------
  462. Trap 'F2' regardless of whether we're in game or editor mode
  463. ------------------------------------------------------------------------*/
  464. if (Debug_Flag) {
  465. if (/*(input == KN_F2 && Session == GAME_SOLO) ||*/ input == (KN_F2 | KN_CTRL_BIT)) {
  466. ScenarioInit = 0;
  467. /*
  468. ** If we're in editor mode & Changed is set, prompt for saving changes
  469. */
  470. if (Debug_Map && Changed) {
  471. rc = CCMessageBox().Process("Save Changes?", TXT_YES, TXT_NO);
  472. HiddenPage.Clear();
  473. Flag_To_Redraw(true);
  474. Render();
  475. /*
  476. ........................ User wants to save ........................
  477. */
  478. if (rc == 0) {
  479. /*
  480. ................ If save cancelled, abort game ..................
  481. */
  482. if (Save_Scenario()!=0) {
  483. input = KN_NONE;
  484. } else {
  485. Changed = 0;
  486. Go_Editor(!Debug_Map);
  487. }
  488. } else {
  489. /*
  490. .................... User doesn't want to save .....................
  491. */
  492. Go_Editor(!Debug_Map);
  493. }
  494. } else {
  495. /*
  496. ** If we're in game mode, set Changed to 0 (so if we didn't save our
  497. ** changes above, they won't keep coming back to haunt us with continual
  498. ** Save Changes? prompts!)
  499. */
  500. if (!Debug_Map) {
  501. Changed = 0;
  502. }
  503. Go_Editor(!Debug_Map);
  504. }
  505. }
  506. }
  507. /*------------------------------------------------------------------------
  508. For normal game mode, jump to the parent's AI routine.
  509. ------------------------------------------------------------------------*/
  510. if (!Debug_Map) {
  511. MouseClass::AI(input, x, y);
  512. return;
  513. }
  514. ::Frame++;
  515. /*------------------------------------------------------------------------
  516. Do special mouse processing if the mouse is over the map
  517. ------------------------------------------------------------------------*/
  518. if (Get_Mouse_X() > TacPixelX && Get_Mouse_X() <
  519. TacPixelX + Lepton_To_Pixel(TacLeptonWidth) &&
  520. Get_Mouse_Y() > TacPixelY && Get_Mouse_Y() <
  521. TacPixelY + Lepton_To_Pixel(TacLeptonHeight)) {
  522. /*.....................................................................
  523. When the mouse moves over a scrolling edge, ScrollClass changes its
  524. shape to the appropriate arrow or NO symbol; it's our job to change it
  525. back to normal (or whatever the shape is set to by Set_Default_Mouse())
  526. when it re-enters the map area.
  527. .....................................................................*/
  528. if (CurTrigger) {
  529. Override_Mouse_Shape(MOUSE_CAN_MOVE);
  530. } else {
  531. Override_Mouse_Shape(MOUSE_NORMAL);
  532. }
  533. }
  534. /*.....................................................................
  535. Set 'ZoneCell' to track the mouse cursor around over the map. Do this
  536. even if the map is scrolling.
  537. .....................................................................*/
  538. if (Get_Mouse_X() >= TacPixelX && Get_Mouse_X() <=
  539. TacPixelX + Lepton_To_Pixel(TacLeptonWidth) &&
  540. Get_Mouse_Y() >= TacPixelY && Get_Mouse_Y() <=
  541. TacPixelY + Lepton_To_Pixel(TacLeptonHeight)) {
  542. cell = Click_Cell_Calc(Get_Mouse_X(), Get_Mouse_Y());
  543. if (cell != -1) {
  544. Set_Cursor_Pos(cell);
  545. if (PendingObject) {
  546. Flag_To_Redraw(true);
  547. }
  548. }
  549. }
  550. /*------------------------------------------------------------------------
  551. Check for mouse motion while left button is down.
  552. ------------------------------------------------------------------------*/
  553. rc = Mouse_Moved();
  554. if (LMouseDown && rc) {
  555. /*.....................................................................
  556. "Paint" mode: place current object, and restart placement
  557. .....................................................................*/
  558. if (PendingObject) {
  559. Flag_To_Redraw(true);
  560. if (Place_Object() == 0) {
  561. Changed = 1;
  562. Start_Placement();
  563. }
  564. } else {
  565. /*.....................................................................
  566. Move the currently-grabbed object
  567. .....................................................................*/
  568. if (GrabbedObject) {
  569. GrabbedObject->Mark(MARK_CHANGE);
  570. if (Move_Grabbed_Object() == 0) {
  571. Changed = 1;
  572. }
  573. }
  574. }
  575. }
  576. /*------------------------------------------------------------------------
  577. Trap special editing keys; if one is detected, set 'input' to 0 to
  578. prevent a conflict with parent's AI().
  579. ------------------------------------------------------------------------*/
  580. switch (input) {
  581. /*---------------------------------------------------------------------
  582. F2/RMOUSE = pop up main menu
  583. ---------------------------------------------------------------------*/
  584. case KN_RMOUSE:
  585. /*
  586. ..................... Turn off placement mode ......................
  587. */
  588. if (PendingObject) {
  589. if (BaseBuilding) {
  590. Cancel_Base_Building();
  591. } else {
  592. Cancel_Placement();
  593. }
  594. }
  595. /*
  596. ................. Turn off trigger placement mode ..................
  597. */
  598. if (CurTrigger) {
  599. Stop_Trigger_Placement();
  600. }
  601. /*
  602. .............. Unselect object & hide popup controls ...............
  603. */
  604. if (CurrentObject.Count()) {
  605. CurrentObject[0]->Unselect();
  606. Popup_Controls();
  607. }
  608. Main_Menu();
  609. input = KN_NONE;
  610. break;
  611. /*---------------------------------------------------------------------
  612. F6 = toggle passable/impassable display
  613. ---------------------------------------------------------------------*/
  614. case KN_F6:
  615. Debug_Passable = (Debug_Passable == false);
  616. HiddenPage.Clear();
  617. Flag_To_Redraw(true);
  618. input = KN_NONE;
  619. break;
  620. /*---------------------------------------------------------------------
  621. INSERT = go into object-placement mode
  622. ---------------------------------------------------------------------*/
  623. case KN_INSERT:
  624. if (!PendingObject) {
  625. /*
  626. ......... Unselect current object, hide popup controls ..........
  627. */
  628. if (CurrentObject.Count()) {
  629. CurrentObject[0]->Unselect();
  630. Popup_Controls();
  631. }
  632. /*
  633. .................... Go into placement mode .....................
  634. */
  635. Start_Placement();
  636. }
  637. input = KN_NONE;
  638. break;
  639. /*---------------------------------------------------------------------
  640. ESC = exit placement mode, or exit to DOS
  641. ---------------------------------------------------------------------*/
  642. case KN_ESC:
  643. /*
  644. .................... Exit object placement mode ....................
  645. */
  646. if (PendingObject) {
  647. if (BaseBuilding) {
  648. Cancel_Base_Building();
  649. } else {
  650. Cancel_Placement();
  651. }
  652. input = KN_NONE;
  653. break;
  654. } else {
  655. /*
  656. ................... Exit trigger placement mode ....................
  657. */
  658. if (CurTrigger) {
  659. Stop_Trigger_Placement();
  660. input = KN_NONE;
  661. break;
  662. } else {
  663. rc = CCMessageBox().Process("Exit Scenario Editor?", TXT_YES, TXT_NO);
  664. HiddenPage.Clear();
  665. Flag_To_Redraw(true);
  666. Render();
  667. /*
  668. .......... User doesn't want to exit; return to editor ..........
  669. */
  670. if (rc==1) {
  671. input = KN_NONE;
  672. break;
  673. }
  674. /*
  675. ................. If changed, prompt for saving .................
  676. */
  677. if (Changed) {
  678. rc = CCMessageBox().Process("Save Changes?", TXT_YES, TXT_NO);
  679. HiddenPage.Clear();
  680. Flag_To_Redraw(true);
  681. Render();
  682. /*
  683. ..................... User wants to save .....................
  684. */
  685. if (rc == 0) {
  686. /*
  687. .............. If save cancelled, abort exit ..............
  688. */
  689. if (Save_Scenario()!=0) {
  690. input = KN_NONE;
  691. break;
  692. } else {
  693. Changed = 0;
  694. }
  695. }
  696. }
  697. }
  698. }
  699. Prog_End();
  700. exit (0);
  701. break;
  702. /*---------------------------------------------------------------------
  703. LEFT = go to previous placement object
  704. ---------------------------------------------------------------------*/
  705. case KN_LEFT:
  706. if (PendingObject) {
  707. Place_Prev();
  708. }
  709. input = KN_NONE;
  710. break;
  711. /*---------------------------------------------------------------------
  712. RIGHT = go to next placement object
  713. ---------------------------------------------------------------------*/
  714. case KN_RIGHT:
  715. if (PendingObject) {
  716. Place_Next();
  717. }
  718. input = KN_NONE;
  719. break;
  720. /*---------------------------------------------------------------------
  721. PGUP = go to previous placement category
  722. ---------------------------------------------------------------------*/
  723. case KN_PGUP:
  724. if (PendingObject) {
  725. Place_Prev_Category();
  726. }
  727. input = KN_NONE;
  728. break;
  729. /*---------------------------------------------------------------------
  730. PGDN = go to next placement category
  731. ---------------------------------------------------------------------*/
  732. case KN_PGDN:
  733. if (PendingObject) {
  734. Place_Next_Category();
  735. }
  736. input = KN_NONE;
  737. break;
  738. /*---------------------------------------------------------------------
  739. HOME = jump to first placement object, or go to Home Cell
  740. ---------------------------------------------------------------------*/
  741. case KN_HOME:
  742. if (PendingObject) {
  743. Place_Home();
  744. } else {
  745. /*
  746. ....................... Set map position ........................
  747. */
  748. ScenarioInit++;
  749. Set_Tactical_Position(Waypoint[WAYPT_HOME]);
  750. ScenarioInit--;
  751. /*
  752. ...................... Force map to redraw ......................
  753. */
  754. HiddenPage.Clear();
  755. Flag_To_Redraw(true);
  756. Render();
  757. }
  758. input = KN_NONE;
  759. break;
  760. /*---------------------------------------------------------------------
  761. SHIFT-HOME: set new Home Cell position
  762. ---------------------------------------------------------------------*/
  763. case ((int)KN_HOME | (int)KN_SHIFT_BIT):
  764. /*
  765. ** Unflag the old Home Cell, if there are no other waypoints
  766. ** pointing to it
  767. */
  768. cell = Waypoint[WAYPT_HOME];
  769. if (cell != -1) {
  770. found = 0;
  771. for (i = 0; i < WAYPT_COUNT; i++) {
  772. if (i != WAYPT_HOME && Waypoint[i]==cell) {
  773. found = 1;
  774. }
  775. }
  776. if (found==0) {
  777. (*this)[cell].IsWaypoint = 0;
  778. Flag_Cell(cell);
  779. }
  780. }
  781. /*
  782. ** Now set the new Home cell
  783. */
  784. Waypoint[WAYPT_HOME] = Coord_Cell(TacticalCoord);
  785. (*this)[Coord_Cell(TacticalCoord)].IsWaypoint = 1;
  786. Flag_Cell(Coord_Cell(TacticalCoord));
  787. Changed = 1;
  788. input = KN_NONE;
  789. break;
  790. /*---------------------------------------------------------------------
  791. SHIFT-R: set new Reinforcement Cell position. Don't allow setting
  792. the Reinf. Cell to the same as the Home Cell (for display purposes.)
  793. ---------------------------------------------------------------------*/
  794. case ((int)KN_R | (int)KN_SHIFT_BIT):
  795. if (CurrentCell==0 || CurrentCell==Waypoint[WAYPT_HOME]) {
  796. break;
  797. }
  798. /*
  799. ** Unflag the old Reinforcement Cell, if there are no other waypoints
  800. ** pointing to it
  801. */
  802. cell = Waypoint[WAYPT_REINF];
  803. if (cell != -1) {
  804. found = 0;
  805. for (i = 0; i < WAYPT_COUNT; i++) {
  806. if (i != WAYPT_REINF && Waypoint[i]==cell) {
  807. found = 1;
  808. }
  809. }
  810. if (found==0) {
  811. (*this)[cell].IsWaypoint = 0;
  812. Flag_Cell(cell);
  813. }
  814. }
  815. /*
  816. ** Now set the new Reinforcement cell
  817. */
  818. Waypoint[WAYPT_REINF] = CurrentCell;
  819. (*this)[CurrentCell].IsWaypoint = 1;
  820. Flag_Cell(CurrentCell);
  821. Changed = 1;
  822. input = KN_NONE;
  823. break;
  824. /*---------------------------------------------------------------------
  825. ALT-Letter: Label a waypoint cell
  826. ---------------------------------------------------------------------*/
  827. case ((int)KN_A | (int)KN_ALT_BIT):
  828. case ((int)KN_B | (int)KN_ALT_BIT):
  829. case ((int)KN_C | (int)KN_ALT_BIT):
  830. case ((int)KN_D | (int)KN_ALT_BIT):
  831. case ((int)KN_E | (int)KN_ALT_BIT):
  832. case ((int)KN_F | (int)KN_ALT_BIT):
  833. case ((int)KN_G | (int)KN_ALT_BIT):
  834. case ((int)KN_H | (int)KN_ALT_BIT):
  835. case ((int)KN_I | (int)KN_ALT_BIT):
  836. case ((int)KN_J | (int)KN_ALT_BIT):
  837. case ((int)KN_K | (int)KN_ALT_BIT):
  838. case ((int)KN_L | (int)KN_ALT_BIT):
  839. case ((int)KN_M | (int)KN_ALT_BIT):
  840. case ((int)KN_N | (int)KN_ALT_BIT):
  841. case ((int)KN_O | (int)KN_ALT_BIT):
  842. case ((int)KN_P | (int)KN_ALT_BIT):
  843. case ((int)KN_Q | (int)KN_ALT_BIT):
  844. case ((int)KN_R | (int)KN_ALT_BIT):
  845. case ((int)KN_S | (int)KN_ALT_BIT):
  846. case ((int)KN_T | (int)KN_ALT_BIT):
  847. case ((int)KN_U | (int)KN_ALT_BIT):
  848. case ((int)KN_V | (int)KN_ALT_BIT):
  849. case ((int)KN_W | (int)KN_ALT_BIT):
  850. case ((int)KN_X | (int)KN_ALT_BIT):
  851. case ((int)KN_Y | (int)KN_ALT_BIT):
  852. case ((int)KN_Z | (int)KN_ALT_BIT):
  853. if (CurrentCell != 0) {
  854. waypt_idx = KN_To_KA(input & 0xff) - KA_a;
  855. /*...............................................................
  856. Unflag cell for this waypoint if there is one
  857. ...............................................................*/
  858. cell = Waypoint[waypt_idx];
  859. if (cell != -1) {
  860. if (Waypoint[WAYPT_HOME] != cell &&
  861. Waypoint[WAYPT_REINF] != cell)
  862. (*this)[cell].IsWaypoint = 0;
  863. Flag_Cell(cell);
  864. }
  865. Waypoint[waypt_idx] = CurrentCell;
  866. (*this)[CurrentCell].IsWaypoint = 1;
  867. Changed = 1;
  868. Flag_Cell(CurrentCell);
  869. }
  870. input = KN_NONE;
  871. break;
  872. /*---------------------------------------------------------------------
  873. ALT-1-4: Designate a cell as a capture-the-flag cell.
  874. ---------------------------------------------------------------------*/
  875. case ((int)KN_1 | (int)KN_ALT_BIT):
  876. case ((int)KN_2 | (int)KN_ALT_BIT):
  877. case ((int)KN_3 | (int)KN_ALT_BIT):
  878. case ((int)KN_4 | (int)KN_ALT_BIT):
  879. /*------------------------------------------------------------------
  880. If there's a current cell, place the flag & waypoint there.
  881. ------------------------------------------------------------------*/
  882. if (CurrentCell != 0) {
  883. waypt_idx = (KN_To_KA(input & 0xff) - KA_1);
  884. house = (HousesType)(HOUSE_MULTI1 + waypt_idx);
  885. if (HouseClass::As_Pointer(house)) {
  886. HouseClass::As_Pointer(house)->Flag_Attach(CurrentCell,true);
  887. }
  888. } else {
  889. /*------------------------------------------------------------------
  890. If there's a current object, attach the flag to it and clear the
  891. waypoint.
  892. ------------------------------------------------------------------*/
  893. if (CurrentObject[0] != 0) {
  894. waypt_idx = (KN_To_KA(input & 0xff) - KA_1);
  895. house = (HousesType)(HOUSE_MULTI1 + waypt_idx);
  896. if (HouseClass::As_Pointer(house) && CurrentObject[0]->What_Am_I() == RTTI_UNIT) {
  897. HouseClass::As_Pointer(house)->Flag_Attach((UnitClass *)CurrentObject[0], true);
  898. }
  899. }
  900. }
  901. input = KN_NONE;
  902. break;
  903. /*---------------------------------------------------------------------
  904. ALT-Space: Remove a waypoint designation
  905. ---------------------------------------------------------------------*/
  906. case ((int)KN_SPACE | (int)KN_ALT_BIT):
  907. if (CurrentCell != 0) {
  908. /*...............................................................
  909. Loop through letter waypoints; if this cell is one of them,
  910. clear that waypoint.
  911. ...............................................................*/
  912. for (i = 0 ; i < 26; i++) {
  913. if (Waypoint[i]==CurrentCell)
  914. Waypoint[i] = -1;
  915. }
  916. /*...............................................................
  917. Loop through flag home values; if this cell is one of them, clear
  918. that waypoint.
  919. ...............................................................*/
  920. for (i = 0; i < MAX_PLAYERS; i++) {
  921. house = (HousesType)(HOUSE_MULTI1 + i);
  922. if (HouseClass::As_Pointer(house) &&
  923. CurrentCell == HouseClass::As_Pointer(house)->FlagHome)
  924. HouseClass::As_Pointer(house)->Flag_Remove(As_Target(CurrentCell),true);
  925. }
  926. /*...............................................................
  927. If there are no more waypoints on this cell, clear the cell's
  928. waypoint designation.
  929. ...............................................................*/
  930. if (Waypoint[WAYPT_HOME]!=CurrentCell &&
  931. Waypoint[WAYPT_REINF]!=CurrentCell)
  932. (*this)[CurrentCell].IsWaypoint = 0;
  933. Changed = 1;
  934. Flag_Cell(CurrentCell);
  935. }
  936. input = KN_NONE;
  937. break;
  938. /*---------------------------------------------------------------------
  939. 'H' = toggle current placement object's house
  940. ---------------------------------------------------------------------*/
  941. case KN_H:
  942. case ((int)KN_H | (int)KN_SHIFT_BIT):
  943. if (PendingObject) {
  944. Toggle_House();
  945. }
  946. input = KN_NONE;
  947. break;
  948. /*---------------------------------------------------------------------
  949. Left-mouse click:
  950. Button DOWN:
  951. - Toggle LMouseDown
  952. - If we're in placement mode, try to place the current object
  953. - If success, re-enter placement mode
  954. - Otherwise, try to select an object, and "grab" it if there is one
  955. - If no object, then select that cell as the "current" cell
  956. Button UP:
  957. - Toggle LMouseDown
  958. - release any grabbed object
  959. ---------------------------------------------------------------------*/
  960. case ((int)MAP_AREA | (int)KN_BUTTON):
  961. /*
  962. ------------------------- Left Button DOWN -------------------------
  963. */
  964. if (Keyboard::Down(KN_LMOUSE)) {
  965. LMouseDown = 1;
  966. /*
  967. ............... Placement mode: place an object .................
  968. */
  969. if (PendingObject) {
  970. if (Place_Object()==0) {
  971. Changed = 1;
  972. Start_Placement();
  973. }
  974. } else {
  975. /*
  976. ....................... Place a trigger .........................
  977. */
  978. if (CurTrigger) {
  979. Place_Trigger();
  980. Changed = 1;
  981. } else {
  982. /*
  983. ................. Select an object or a cell .................
  984. .................. Check for double-click ....................
  985. */
  986. if (CurrentObject.Count() &&
  987. ( (TickCount.Time() - LastClickTime) < 15)) {
  988. ; // stub
  989. } else {
  990. /*
  991. ................ Single-click: select object .................
  992. */
  993. if (Select_Object()==0) {
  994. CurrentCell = 0;
  995. Grab_Object();
  996. } else {
  997. /*
  998. ................ No object: select the cell ..................
  999. */
  1000. CurrentCell = Click_Cell_Calc(_Kbd->MouseQX,_Kbd->MouseQY);
  1001. HiddenPage.Clear();
  1002. Flag_To_Redraw(true);
  1003. Render();
  1004. }
  1005. }
  1006. }
  1007. }
  1008. LastClickTime = TickCount.Time();
  1009. input = KN_NONE;
  1010. } else {
  1011. /*
  1012. -------------------------- Left Button UP --------------------------
  1013. */
  1014. LMouseDown = 0;
  1015. GrabbedObject = 0;
  1016. input = KN_NONE;
  1017. }
  1018. break;
  1019. /*---------------------------------------------------------------------
  1020. SHIFT-ALT-Arrow: move the current object
  1021. ---------------------------------------------------------------------*/
  1022. case (int)KN_UP | (int)KN_ALT_BIT | (int)KN_SHIFT_BIT:
  1023. case (int)KN_DOWN | (int)KN_ALT_BIT | (int)KN_SHIFT_BIT:
  1024. case (int)KN_LEFT | (int)KN_ALT_BIT | (int)KN_SHIFT_BIT:
  1025. case (int)KN_RIGHT | (int)KN_ALT_BIT | (int)KN_SHIFT_BIT:
  1026. if (CurrentObject.Count()) {
  1027. CurrentObject[0]->Move(KN_To_Facing(input));
  1028. Changed = 1;
  1029. }
  1030. input = KN_NONE;
  1031. break;
  1032. /*---------------------------------------------------------------------
  1033. DELETE: delete currently-selected object
  1034. ---------------------------------------------------------------------*/
  1035. case KN_DELETE:
  1036. /*..................................................................
  1037. Delete currently-selected object's trigger, or the object
  1038. ..................................................................*/
  1039. if (CurrentObject.Count()) {
  1040. /*
  1041. ........................ Delete trigger .........................
  1042. */
  1043. if (CurrentObject[0]->Trigger) {
  1044. CurrentObject[0]->Trigger = NULL;
  1045. } else {
  1046. /*
  1047. ** If the current object is part of the AI's Base, remove it
  1048. ** from the Base's Node list.
  1049. */
  1050. if (CurrentObject[0]->What_Am_I()==RTTI_BUILDING &&
  1051. Base.Is_Node((BuildingClass *)CurrentObject[0])) {
  1052. node = Base.Get_Node((BuildingClass *)CurrentObject[0]);
  1053. Base.Nodes.Delete(*node);
  1054. }
  1055. /*
  1056. ................... Delete current object ....................
  1057. */
  1058. delete CurrentObject[0];
  1059. /*
  1060. .................. Hide the popup controls ...................
  1061. */
  1062. Popup_Controls();
  1063. }
  1064. /*
  1065. ........................ Force a redraw .........................
  1066. */
  1067. HiddenPage.Clear();
  1068. Flag_To_Redraw(true);
  1069. Changed = 1;
  1070. } else {
  1071. /*
  1072. ................. Remove trigger from current cell .................
  1073. */
  1074. if (CurrentCell) {
  1075. if ((*this)[CurrentCell].IsTrigger) {
  1076. (*this)[CurrentCell].IsTrigger = 0;
  1077. CellTriggers[CurrentCell] = NULL;
  1078. /*
  1079. ...................... Force a redraw ........................
  1080. */
  1081. HiddenPage.Clear();
  1082. Flag_To_Redraw(true);
  1083. Changed = 1;
  1084. }
  1085. }
  1086. }
  1087. input = KN_NONE;
  1088. break;
  1089. /*---------------------------------------------------------------------
  1090. TAB: select next object on the map
  1091. ---------------------------------------------------------------------*/
  1092. case KN_TAB:
  1093. Select_Next();
  1094. input = KN_NONE;
  1095. break;
  1096. /*---------------------------------------------------------------------
  1097. Object-Editing button: House Button
  1098. ---------------------------------------------------------------------*/
  1099. case (POPUP_GDI | KN_BUTTON):
  1100. case (POPUP_NOD | KN_BUTTON):
  1101. case (POPUP_NEUTRAL | KN_BUTTON):
  1102. case (POPUP_MULTI1 | KN_BUTTON):
  1103. case (POPUP_MULTI2 | KN_BUTTON):
  1104. case (POPUP_MULTI3 | KN_BUTTON):
  1105. case (POPUP_MULTI4 | KN_BUTTON):
  1106. /*..................................................................
  1107. Convert input value into a house value; assume HOUSE_GOOD is 0
  1108. ..................................................................*/
  1109. house = (HousesType)( (input & (~KN_BUTTON)) - POPUP_GDI);
  1110. /*..................................................................
  1111. If that house doesn't own this object, try to transfer it
  1112. ..................................................................*/
  1113. if (CurrentObject[0]->Owner()!=house) {
  1114. if (Change_House(house)) {
  1115. Changed = 1;
  1116. }
  1117. }
  1118. Set_House_Buttons(CurrentObject[0]->Owner(), Buttons, POPUP_GDI);
  1119. HiddenPage.Clear();
  1120. Flag_To_Redraw(true);
  1121. input = KN_NONE;
  1122. break;
  1123. /*---------------------------------------------------------------------
  1124. Object-Editing button: Mission
  1125. ---------------------------------------------------------------------*/
  1126. case (POPUP_MISSIONLIST | KN_BUTTON):
  1127. if (CurrentObject[0]->Is_Techno()) {
  1128. /*
  1129. ........................ Set new mission ........................
  1130. */
  1131. mission = MapEditMissions[MissionList->Current_Index()];
  1132. if (CurrentObject[0]->Get_Mission() != mission) {
  1133. ((TechnoClass *)CurrentObject[0])->Set_Mission(mission);
  1134. Changed = 1;
  1135. }
  1136. }
  1137. Flag_To_Redraw(true);
  1138. input = KN_NONE;
  1139. break;
  1140. /*---------------------------------------------------------------------
  1141. Object-Editing button: Health
  1142. ---------------------------------------------------------------------*/
  1143. case (POPUP_HEALTHGAUGE | KN_BUTTON):
  1144. if (CurrentObject[0]->Is_Techno()) {
  1145. /*
  1146. .......... Derive strength from current gauge reading ...........
  1147. */
  1148. strength = Fixed_To_Cardinal(
  1149. (unsigned)CurrentObject[0]->Class_Of().MaxStrength,
  1150. (unsigned)HealthGauge->Get_Value());
  1151. /*
  1152. ........................... Clip to 1 ...........................
  1153. */
  1154. if (strength <= 0) {
  1155. strength = 1;
  1156. }
  1157. /*
  1158. ....................... Set new strength ........................
  1159. */
  1160. if (strength != CurrentObject[0]->Strength) {
  1161. CurrentObject[0]->Strength = strength;
  1162. HiddenPage.Clear();
  1163. Flag_To_Redraw(true);
  1164. Changed = 1;
  1165. }
  1166. /*
  1167. ....................... Update text label .......................
  1168. */
  1169. sprintf(HealthBuf,"%d",strength);
  1170. }
  1171. input = KN_NONE;
  1172. break;
  1173. /*---------------------------------------------------------------------
  1174. Object-Editing button: Facing
  1175. ---------------------------------------------------------------------*/
  1176. case (POPUP_FACINGDIAL | KN_BUTTON):
  1177. if (CurrentObject[0]->Is_Techno()) {
  1178. /*
  1179. ........................ Set new facing .........................
  1180. */
  1181. if (FacingDial->Get_Direction() !=
  1182. ((TechnoClass *)CurrentObject[0])->PrimaryFacing.Get()) {
  1183. /*
  1184. ..................... Set body's facing ......................
  1185. */
  1186. ((TechnoClass *)CurrentObject[0])->PrimaryFacing.Set(FacingDial->Get_Direction());
  1187. /*
  1188. ............. Set turret facing, if there is one .............
  1189. */
  1190. if (CurrentObject[0]->What_Am_I()==RTTI_UNIT) {
  1191. ((UnitClass *)CurrentObject[0])->SecondaryFacing.Set(FacingDial->Get_Direction());
  1192. }
  1193. HiddenPage.Clear();
  1194. Flag_To_Redraw(true);
  1195. Changed = 1;
  1196. }
  1197. }
  1198. input = KN_NONE;
  1199. break;
  1200. /*---------------------------------------------------------------------
  1201. Object-Editing button: Facing
  1202. ---------------------------------------------------------------------*/
  1203. case (POPUP_BASEPERCENT | KN_BUTTON):
  1204. if (BaseGauge->Get_Value() != BasePercent) {
  1205. BasePercent = BaseGauge->Get_Value();
  1206. Build_Base_To(BasePercent);
  1207. HiddenPage.Clear();
  1208. Flag_To_Redraw(true);
  1209. }
  1210. input = KN_NONE;
  1211. break;
  1212. case (KN_LMOUSE):
  1213. input = KN_NONE;
  1214. break;
  1215. default:
  1216. break;
  1217. }
  1218. /*
  1219. ------------------------ Call parent's AI routine ------------------------
  1220. */
  1221. MouseClass::AI(input, x, y);
  1222. }
  1223. /***************************************************************************
  1224. * MapEditClass::Draw_It -- overloaded Redraw routine *
  1225. * *
  1226. * INPUT: *
  1227. * *
  1228. * OUTPUT: *
  1229. * *
  1230. * WARNINGS: *
  1231. * *
  1232. * HISTORY: *
  1233. * 11/17/1994 BR : Created. *
  1234. *=========================================================================*/
  1235. void MapEditClass::Draw_It(bool forced)
  1236. {
  1237. char const *label;
  1238. char buf[40];
  1239. char const *tptr;
  1240. MouseClass::Draw_It(forced);
  1241. if (!Debug_Map) {
  1242. return;
  1243. }
  1244. //
  1245. // Erase scrags at top of screen
  1246. //
  1247. LogicPage->Fill_Rect(0, 0, 640, 16, BLACK);
  1248. /*
  1249. ** Display the total value of all Tiberium on the map.
  1250. */
  1251. Fancy_Text_Print("Tiberium=%ld ", 0, 0, CC_GREEN, BLACK,
  1252. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW, TotalValue);
  1253. /*------------------------------------------------------------------------
  1254. If there are no object controls displayed, just invoke parent's Redraw
  1255. and return.
  1256. ------------------------------------------------------------------------*/
  1257. if (!Buttons) {
  1258. return;
  1259. }
  1260. /*------------------------------------------------------------------------
  1261. Otherwise, if 'display' is set, invoke the parent's Redraw to refresh
  1262. the HIDPAGE; then, update the buttons & text labels onto HIDPAGE;
  1263. then invoke the parent's Redraw to blit the HIDPAGE to SEENPAGE.
  1264. ------------------------------------------------------------------------*/
  1265. if (forced) {
  1266. /*
  1267. ....................... Update the text labels ........................
  1268. */
  1269. if (CurrentObject.Count()) {
  1270. /*
  1271. ------------------ Display the object's name & ID ------------------
  1272. */
  1273. label = Text_String(CurrentObject[0]->Full_Name());
  1274. tptr = label;
  1275. sprintf(buf,"%s (%d)",tptr,CurrentObject[0]->As_Target());
  1276. /*
  1277. ......................... print the label ..........................
  1278. */
  1279. Fancy_Text_Print (buf, 320, 0, CC_TAN, TBLACK,
  1280. TPF_CENTER | TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL);
  1281. }
  1282. }
  1283. }
  1284. /***************************************************************************
  1285. * MapEditClass::Mouse_Moved -- checks for mouse motion *
  1286. * *
  1287. * Reports whether the mouse has moved or not. This varies based on the *
  1288. * type of object currently selected. If there's an infantry object *
  1289. * selected, mouse motion counts even within a cell; for all other types,*
  1290. * mouse motion counts only if the mouse changes cells. *
  1291. * *
  1292. * The reason this routine is needed is to prevent Paint-Mode from putting*
  1293. * gobs of trees and such into the same cell if the mouse moves just *
  1294. * a little bit. *
  1295. * *
  1296. * INPUT: *
  1297. * *
  1298. * OUTPUT: *
  1299. * *
  1300. * WARNINGS: *
  1301. * *
  1302. * HISTORY: *
  1303. * 11/08/1994 BR : Created. *
  1304. *=========================================================================*/
  1305. bool MapEditClass::Mouse_Moved(void)
  1306. {
  1307. static int old_mx = 0;
  1308. static int old_my = 0;
  1309. static CELL old_zonecell = 0;
  1310. const ObjectTypeClass * objtype = NULL;
  1311. bool retcode = false;
  1312. /*
  1313. -------------------------- Return if no motion ---------------------------
  1314. */
  1315. if (old_mx == Get_Mouse_X() && old_my == Get_Mouse_Y()) {
  1316. return(false);
  1317. }
  1318. /*
  1319. ---------------------- Get a ptr to ObjectTypeClass ----------------------
  1320. */
  1321. if (PendingObject) {
  1322. objtype = PendingObject;
  1323. } else {
  1324. if (GrabbedObject) {
  1325. objtype = &GrabbedObject->Class_Of();
  1326. } else {
  1327. old_mx = Get_Mouse_X();
  1328. old_my = Get_Mouse_Y();
  1329. old_zonecell = ZoneCell;
  1330. return(false);
  1331. }
  1332. }
  1333. /*
  1334. --------------------- Check for motion based on type ---------------------
  1335. */
  1336. /*
  1337. ............... Infantry: mouse moved if any motion at all ...............
  1338. */
  1339. if (objtype->What_Am_I() == RTTI_INFANTRYTYPE) {
  1340. retcode = true;
  1341. } else {
  1342. /*
  1343. ................ Others: mouse moved only if cell changed ................
  1344. */
  1345. if (old_zonecell!=ZoneCell) {
  1346. retcode = true;
  1347. } else {
  1348. retcode = false;
  1349. }
  1350. }
  1351. old_mx = Get_Mouse_X();
  1352. old_my = Get_Mouse_Y();
  1353. old_zonecell = ZoneCell;
  1354. return(retcode);
  1355. }
  1356. /***************************************************************************
  1357. * MapEditClass::Main_Menu -- main menu processor for map editor *
  1358. * *
  1359. * INPUT: *
  1360. * none. *
  1361. * *
  1362. * OUTPUT: *
  1363. * none. *
  1364. * *
  1365. * WARNINGS: *
  1366. * none. *
  1367. * *
  1368. * HISTORY: *
  1369. * 10/20/1994 BR : Created. *
  1370. *=========================================================================*/
  1371. void MapEditClass::Main_Menu(void)
  1372. {
  1373. char const *_menus[MAX_MAIN_MENU_NUM + 1];
  1374. int selection; // option the user picks
  1375. bool process; // menu stays up while true
  1376. int rc;
  1377. /*
  1378. --------------------------- Fill in menu items ---------------------------
  1379. */
  1380. _menus[0] = "New Scenario";
  1381. _menus[1] = "Load Scenario";
  1382. _menus[2] = "Save Scenario";
  1383. _menus[3] = "Size Map";
  1384. _menus[4] = "Add Game Object";
  1385. _menus[5] = "Scenario Options";
  1386. _menus[6] = "AI Options";
  1387. _menus[7] = "Play Scenario";
  1388. _menus[8] = NULL;
  1389. /*
  1390. ----------------------------- Main Menu loop -----------------------------
  1391. */
  1392. Override_Mouse_Shape(MOUSE_NORMAL); // display default mouse cursor
  1393. process = true;
  1394. while (process) {
  1395. /*
  1396. ................ Invoke game callback, to update music ................
  1397. */
  1398. Call_Back();
  1399. /*
  1400. ............................. Invoke menu .............................
  1401. */
  1402. Hide_Mouse(); // Do_Menu assumes the mouse is already hidden
  1403. selection = Do_Menu(&_menus[0], true);
  1404. Show_Mouse();
  1405. if (UnknownKey==KN_ESC || UnknownKey==KN_LMOUSE || UnknownKey==KN_RMOUSE) {
  1406. break;
  1407. }
  1408. /*
  1409. .......................... Process selection ..........................
  1410. */
  1411. switch (selection) {
  1412. /*
  1413. ........................... New scenario ...........................
  1414. */
  1415. case 0:
  1416. if (Changed) {
  1417. rc = CCMessageBox().Process("Save Changes?", TXT_YES, TXT_NO);
  1418. HiddenPage.Clear();
  1419. Flag_To_Redraw(true);
  1420. Render();
  1421. if (rc==0) {
  1422. if (Save_Scenario()!=0) {
  1423. break;
  1424. } else {
  1425. Changed = 0;
  1426. }
  1427. }
  1428. }
  1429. if (New_Scenario()==0) {
  1430. CarryOverMoney = 0;
  1431. Changed = 1;
  1432. }
  1433. process = false;
  1434. break;
  1435. /*
  1436. .......................... Load scenario ...........................
  1437. */
  1438. case 1:
  1439. if (Changed) {
  1440. rc = CCMessageBox().Process("Save Changes?", TXT_YES, TXT_NO);
  1441. HiddenPage.Clear();
  1442. Flag_To_Redraw(true);
  1443. Render();
  1444. if (rc==0) {
  1445. if (Save_Scenario()!=0) {
  1446. break;
  1447. } else {
  1448. Changed = 0;
  1449. }
  1450. }
  1451. }
  1452. if (Load_Scenario()==0) {
  1453. CarryOverMoney = 0;
  1454. Changed = 0;
  1455. }
  1456. process = false;
  1457. break;
  1458. /*
  1459. .......................... Save scenario ...........................
  1460. */
  1461. case 2:
  1462. if (Save_Scenario() == 0) {
  1463. Changed = 0;
  1464. }
  1465. process = false;
  1466. break;
  1467. /*
  1468. .......................... Edit map size ...........................
  1469. */
  1470. case 3:
  1471. if (Size_Map(MapCellX, MapCellY, MapCellWidth, MapCellHeight)==0) {
  1472. process = false;
  1473. Changed = 1;
  1474. }
  1475. break;
  1476. /*
  1477. .......................... Add an object ...........................
  1478. */
  1479. case 4:
  1480. if (Placement_Dialog() == 0) {
  1481. Start_Placement();
  1482. process = false;
  1483. }
  1484. break;
  1485. /*
  1486. ......................... Scenario options .........................
  1487. */
  1488. case 5:
  1489. if (Scenario_Dialog() == 0) {
  1490. Changed = 1;
  1491. process = false;
  1492. }
  1493. break;
  1494. /*
  1495. .......................... Other options ...........................
  1496. */
  1497. case 6:
  1498. AI_Menu();
  1499. process = false;
  1500. break;
  1501. /*
  1502. ...................... Test-drive this scenario ....................
  1503. */
  1504. case 7:
  1505. if (Changed) {
  1506. rc = CCMessageBox().Process("Save Changes?", TXT_YES, TXT_NO);
  1507. HiddenPage.Clear();
  1508. Flag_To_Redraw(true);
  1509. Render();
  1510. if (rc==0) {
  1511. if (Save_Scenario()!=0) {
  1512. break;
  1513. } else {
  1514. Changed = 0;
  1515. }
  1516. }
  1517. }
  1518. Changed = 0;
  1519. Debug_Map = false;
  1520. Start_Scenario(ScenarioName);
  1521. return;
  1522. }
  1523. }
  1524. /*------------------------------------------------------------------------
  1525. Restore the display:
  1526. - Clear HIDPAGE to erase any spurious drawing done by the menu system
  1527. - Invoke Flag_To_Redraw to tell DisplayClass to re-render the whole screen
  1528. - Invoke Redraw() to update the display
  1529. ------------------------------------------------------------------------*/
  1530. HiddenPage.Clear();
  1531. Flag_To_Redraw(true);
  1532. Render();
  1533. }
  1534. /***************************************************************************
  1535. * MapEditClass::AI_Menu -- menu of AI options *
  1536. * *
  1537. * INPUT: *
  1538. * *
  1539. * OUTPUT: *
  1540. * *
  1541. * WARNINGS: *
  1542. * *
  1543. * HISTORY: *
  1544. * 11/29/1994 BR : Created. *
  1545. *=========================================================================*/
  1546. void MapEditClass::AI_Menu(void)
  1547. {
  1548. int selection; // option the user picks
  1549. bool process; // menu stays up while true
  1550. char const *_menus[MAX_AI_MENU_NUM + 1];
  1551. /*
  1552. -------------------------- Fill in menu strings --------------------------
  1553. */
  1554. _menus[0] = "Pre-Build a Base";
  1555. _menus[1] = "Import Triggers";
  1556. _menus[2] = "Edit Triggers";
  1557. _menus[3] = "Import Teams";
  1558. _menus[4] = "Edit Teams";
  1559. _menus[5] = NULL;
  1560. /*
  1561. ----------------------------- Main Menu loop -----------------------------
  1562. */
  1563. Override_Mouse_Shape(MOUSE_NORMAL); // display default mouse cursor
  1564. process = true;
  1565. while (process) {
  1566. /*
  1567. ................ Invoke game callback, to update music ................
  1568. */
  1569. Call_Back();
  1570. /*
  1571. ............................. Invoke menu .............................
  1572. */
  1573. Hide_Mouse(); // Do_Menu assumes the mouse is already hidden
  1574. selection = Do_Menu(&_menus[0], true);
  1575. Show_Mouse();
  1576. if (UnknownKey==KN_ESC || UnknownKey==KN_LMOUSE || UnknownKey==KN_RMOUSE) {
  1577. break;
  1578. }
  1579. /*
  1580. .......................... Process selection ..........................
  1581. */
  1582. switch (selection) {
  1583. /*
  1584. ......................... Pre-Build a Base .........................
  1585. */
  1586. case 0:
  1587. Start_Base_Building();
  1588. process = false;
  1589. break;
  1590. /*
  1591. ......................... Import Triggers ..........................
  1592. */
  1593. case 1:
  1594. if (Import_Triggers()==0)
  1595. process = false;
  1596. break;
  1597. /*
  1598. ......................... Trigger Editing ..........................
  1599. */
  1600. case 2:
  1601. Handle_Triggers();
  1602. /*
  1603. ................ Go into trigger placement mode .................
  1604. */
  1605. if (CurTrigger) {
  1606. Start_Trigger_Placement();
  1607. }
  1608. process = false;
  1609. break;
  1610. /*
  1611. ........................... Import Teams ...........................
  1612. */
  1613. case 3:
  1614. if (Import_Teams()==0)
  1615. process = false;
  1616. break;
  1617. /*
  1618. ........................... Team Editing ...........................
  1619. */
  1620. case 4:
  1621. Handle_Teams("Teams");
  1622. process = false;
  1623. break;
  1624. }
  1625. }
  1626. }
  1627. /***************************************************************************
  1628. * MapEditClass::Verify_House -- is this objtype ownable by this house? *
  1629. * *
  1630. * INPUT: *
  1631. * house house to check *
  1632. * objtype ObjectTypeClass to check *
  1633. * *
  1634. * OUTPUT: *
  1635. * 0 = isn't ownable, 1 = it is *
  1636. * *
  1637. * WARNINGS: *
  1638. * none. *
  1639. * *
  1640. * HISTORY: *
  1641. * 11/16/1994 BR : Created. *
  1642. *=========================================================================*/
  1643. bool MapEditClass::Verify_House(HousesType house, ObjectTypeClass const *objtype)
  1644. {
  1645. /*
  1646. --------------- Verify that new house can own this object ----------------
  1647. */
  1648. return((objtype->Get_Ownable() & (1 << house)) != 0);
  1649. }
  1650. /***************************************************************************
  1651. * MapEditClass::Cycle_House -- finds next valid house for object type *
  1652. * *
  1653. * INPUT: *
  1654. * objtype ObjectTypeClass ptr to get house for *
  1655. * curhouse current house value to start with *
  1656. * *
  1657. * OUTPUT: *
  1658. * HousesType that's valid for this object type *
  1659. * *
  1660. * WARNINGS: *
  1661. * none. *
  1662. * *
  1663. * HISTORY: *
  1664. * 11/23/1994 BR : Created. *
  1665. *=========================================================================*/
  1666. HousesType MapEditClass::Cycle_House(HousesType curhouse,
  1667. ObjectTypeClass const *objtype)
  1668. {
  1669. HousesType count; // prevents an infinite loop
  1670. /*------------------------------------------------------------------------
  1671. Loop through all house types, starting with the one after 'curhouse';
  1672. return the first one that's valid
  1673. ------------------------------------------------------------------------*/
  1674. count = HOUSE_NONE;
  1675. while (1) {
  1676. /*
  1677. .......................... Go to next house ...........................
  1678. */
  1679. curhouse++;
  1680. if (curhouse == HOUSE_COUNT) {
  1681. curhouse = HOUSE_FIRST;
  1682. }
  1683. /*
  1684. ................ Count # iterations; don't go forever .................
  1685. */
  1686. count++;
  1687. if (count == HOUSE_COUNT) {
  1688. curhouse = HOUSE_NONE;
  1689. break;
  1690. }
  1691. /*
  1692. ................... Break if this is a valid house ....................
  1693. */
  1694. if (HouseClass::As_Pointer(curhouse) && Verify_House(curhouse,objtype)) {
  1695. break;
  1696. }
  1697. }
  1698. return(curhouse);
  1699. }
  1700. /***************************************************************************
  1701. * MapEditClass::Fatal -- exits with error message *
  1702. * *
  1703. * INPUT: *
  1704. * code tells which message to display; this minimizes the *
  1705. * use of character strings in the code. *
  1706. * *
  1707. * OUTPUT: *
  1708. * none. *
  1709. * *
  1710. * WARNINGS: *
  1711. * none. *
  1712. * *
  1713. * HISTORY: *
  1714. * 12/12/1994 BR : Created. *
  1715. *=========================================================================*/
  1716. void MapEditClass::Fatal(int txt)
  1717. {
  1718. Prog_End();
  1719. printf("%s\n",txt);
  1720. if (!RunningAsDLL) {
  1721. exit(EXIT_FAILURE);
  1722. }
  1723. }
  1724. bool MapEditClass::Scroll_Map(DirType facing, int & distance, bool really)
  1725. {
  1726. if (Debug_Map) {
  1727. /*
  1728. ** The popup gadgets require the entire map to be redrawn if we scroll.
  1729. */
  1730. if (really) {
  1731. Flag_To_Redraw(true);
  1732. }
  1733. }
  1734. return(MouseClass::Scroll_Map(facing, distance, really));
  1735. }
  1736. void MapEditClass::Detach(ObjectClass * object)
  1737. {
  1738. if (GrabbedObject == object) {
  1739. GrabbedObject = 0;
  1740. }
  1741. }
  1742. #endif
  1743. #include "mapedsel.cpp"