MAPEDPLC.CPP 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821
  1. //
  2. // Copyright 2020 Electronic Arts Inc.
  3. //
  4. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
  5. // software: you can redistribute it and/or modify it under the terms of
  6. // the GNU General Public License as published by the Free Software Foundation,
  7. // either version 3 of the License, or (at your option) any later version.
  8. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
  9. // in the hope that it will be useful, but with permitted additional restrictions
  10. // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
  11. // distributed with this program. You should have received a copy of the
  12. // GNU General Public License along with permitted additional restrictions
  13. // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
  14. /* $Header: /CounterStrike/MAPEDPLC.CPP 1 3/03/97 10:25a 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 : MAPEDPLC.CPP *
  22. * *
  23. * Programmer : Bill Randolph *
  24. * *
  25. * Start Date : November 18, 1994 *
  26. * *
  27. * Last Update : May 12, 1996 [JLB] *
  28. * *
  29. *-------------------------------------------------------------------------*
  30. * Object-placement routines *
  31. *-------------------------------------------------------------------------*
  32. * Functions: *
  33. * MapEditClass::Build_Base_To -- builds the AI base to the given percent*
  34. * MapEditClass::Cancel_Base_Building -- stops base-building mode *
  35. * MapEditClass::Cancel_Placement -- cancels placement mode *
  36. * MapEditClass::Place_Home -- homes the placement object *
  37. * MapEditClass::Place_Next -- while placing object, goes to next *
  38. * MapEditClass::Place_Next_Category -- places next object category *
  39. * MapEditClass::Place_Object -- attempts to place the current object *
  40. * MapEditClass::Place_Prev -- while placing object, goes to previous *
  41. * MapEditClass::Place_Prev_Category -- places previous object category *
  42. * MapEditClass::Place_Trigger -- assigns trigger to object or cell *
  43. * MapEditClass::Placement_Dialog -- adds an object to the scenario *
  44. * MapEditClass::Set_House_Buttons -- toggles house buttons for btn list *
  45. * MapEditClass::Start_Base_Building -- starts base-building mode *
  46. * MapEditClass::Start_Placement -- enters placement mode *
  47. * MapEditClass::Start_Trigger_Placement -- enters trigger placement mode*
  48. * MapEditClass::Stop_Trigger_Placement -- exits trigger placement mode *
  49. * MapEditClass::Toggle_House -- toggles current placement object's house*
  50. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  51. #include "function.h"
  52. #ifdef SCENARIO_EDITOR
  53. /***************************************************************************
  54. * MapEditClass::Placement_Dialog -- adds an object to the scenario *
  55. * *
  56. * This function sets LastChoice & LastHouse to the values chosen *
  57. * by the user. It's up to the caller to call Start_Placement to enter *
  58. * placement mode. *
  59. * This routine does not modify PendingObject or PendingHouse. *
  60. * *
  61. * ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ *
  62. * ³ [GDI] [NOD] [Neutral] ³ *
  63. * ³ ³ *
  64. * ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ *
  65. * ³ ³ ³ [Template] ³ *
  66. * ³ ³ ³ [Overlay ] ³ *
  67. * ³ ³ ³ [Smudge ] ³ *
  68. * ³ ³ ³ [Terrain ] ³ *
  69. * ³ ³ (Object picture) ³ [Unit ] ³ *
  70. * ³ ³ ³ [Infantry] ³ *
  71. * ³ ³ ³ [Aircraft] ³ *
  72. * ³ ³ ³ [Building] ³ *
  73. * ³ ³ ³ ³ *
  74. * ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÚÄÄÄÄÄÄ¿ ³ *
  75. * ³ [<-] [->] ³(Grid)³ ³ *
  76. * ³ ³ ³ ³ *
  77. * ³ [OK] [Cancel] ÀÄÄÄÄÄÄÙ ³ *
  78. * ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ *
  79. * *
  80. * INPUT: *
  81. * none. *
  82. * *
  83. * OUTPUT: *
  84. * 0 = OK, -1 = cancel *
  85. * *
  86. * WARNINGS: *
  87. * none. *
  88. * *
  89. * HISTORY: *
  90. * 10/21/1994 BR : Created. *
  91. * 12/13/1995 JLB : Fixed house buttons to handle expanded house list. *
  92. * 05/12/1996 JLB : Handles hi-res. *
  93. *=========================================================================*/
  94. int MapEditClass::Placement_Dialog(void)
  95. {
  96. HousesType house;
  97. RemapControlType * scheme = GadgetClass::Get_Color_Scheme();
  98. /*
  99. ** Dialog & button dimensions
  100. */
  101. enum {
  102. D_DIALOG_W = 400,
  103. D_DIALOG_H = 180,
  104. D_DIALOG_X = 0,
  105. D_DIALOG_Y = 0,
  106. D_DIALOG_CX = D_DIALOG_X + (D_DIALOG_W / 2),
  107. D_TXT8_H = 11,
  108. D_MARGIN = 7,
  109. D_PICTURE_W = 152, // must be divisible by 8!
  110. D_PICTURE_H = 105,
  111. D_PICTURE_X = D_DIALOG_X + 35, // must start on a byte boundary!
  112. D_PICTURE_Y = D_DIALOG_Y + D_MARGIN + D_TXT8_H + D_MARGIN,
  113. D_PICTURE_CX = D_PICTURE_X + D_PICTURE_W / 2,
  114. D_GDI_W = 65,
  115. D_GDI_H = 9,
  116. D_GDI_X = D_PICTURE_X+D_PICTURE_W+5,
  117. D_GDI_Y = D_PICTURE_Y,
  118. D_LEFT_W = 45,
  119. D_LEFT_H = 9,
  120. D_LEFT_X = D_PICTURE_CX - 5 - D_LEFT_W,
  121. D_LEFT_Y = D_PICTURE_Y + D_PICTURE_H + D_MARGIN,
  122. D_RIGHT_W = 45,
  123. D_RIGHT_H = 9,
  124. D_RIGHT_X = D_PICTURE_CX + 5,
  125. D_RIGHT_Y = D_PICTURE_Y + D_PICTURE_H + D_MARGIN,
  126. D_TEMPLATE_W = 70,
  127. D_TEMPLATE_H = 9,
  128. D_TEMPLATE_X = D_DIALOG_X + D_DIALOG_W - D_MARGIN - D_TEMPLATE_W - 30,
  129. D_TEMPLATE_Y = D_PICTURE_Y,
  130. D_OVERLAY_W = 70,
  131. D_OVERLAY_H = 9,
  132. D_OVERLAY_X = D_DIALOG_X + D_DIALOG_W - D_MARGIN - D_OVERLAY_W - 30,
  133. D_OVERLAY_Y = D_TEMPLATE_Y + D_TEMPLATE_H,
  134. D_SMUDGE_W = 70,
  135. D_SMUDGE_H = 9,
  136. D_SMUDGE_X = D_DIALOG_X + D_DIALOG_W - D_MARGIN - D_SMUDGE_W - 30,
  137. D_SMUDGE_Y = D_OVERLAY_Y + D_OVERLAY_H,
  138. D_TERRAIN_W = 70,
  139. D_TERRAIN_H = 9,
  140. D_TERRAIN_X = D_DIALOG_X + D_DIALOG_W - D_MARGIN - D_TERRAIN_W - 30,
  141. D_TERRAIN_Y = D_SMUDGE_Y + D_SMUDGE_H,
  142. D_UNIT_W = 70,
  143. D_UNIT_H = 9,
  144. D_UNIT_X = D_DIALOG_X + D_DIALOG_W - D_MARGIN - D_UNIT_W - 30,
  145. D_UNIT_Y = D_TERRAIN_Y + D_TERRAIN_H,
  146. D_INFANTRY_W = 70,
  147. D_INFANTRY_H = 9,
  148. D_INFANTRY_X = D_DIALOG_X + D_DIALOG_W - D_MARGIN - D_INFANTRY_W - 30,
  149. D_INFANTRY_Y = D_UNIT_Y + D_UNIT_H,
  150. D_AIRCRAFT_W = 70,
  151. D_AIRCRAFT_H = 9,
  152. D_AIRCRAFT_X = D_DIALOG_X + D_DIALOG_W - D_MARGIN - D_AIRCRAFT_W - 30,
  153. D_AIRCRAFT_Y = D_INFANTRY_Y + D_INFANTRY_H,
  154. D_BUILDING_W = 70,
  155. D_BUILDING_H = 9,
  156. D_BUILDING_X = D_DIALOG_X + D_DIALOG_W - D_MARGIN - D_BUILDING_W - 30,
  157. D_BUILDING_Y = D_AIRCRAFT_Y + D_AIRCRAFT_H,
  158. D_AIR_W = 70,
  159. D_AIR_H = 9,
  160. D_AIR_X = D_DIALOG_X + D_DIALOG_W - D_MARGIN - D_AIR_W - 30,
  161. D_AIR_Y = D_BUILDING_Y + D_BUILDING_H,
  162. D_OK_W = 45,
  163. D_OK_H = 9,
  164. D_OK_X = D_PICTURE_CX - D_OK_W - 5,
  165. D_OK_Y = D_DIALOG_Y + D_DIALOG_H - D_OK_H - D_MARGIN - 15,
  166. D_CANCEL_W = 45,
  167. D_CANCEL_H = 9,
  168. D_CANCEL_X = D_PICTURE_CX + 5,
  169. D_CANCEL_Y = D_DIALOG_Y + D_DIALOG_H - D_CANCEL_H - D_MARGIN - 15,
  170. GRIDSIZE = 10,
  171. GRIDBLOCK_W = 3,
  172. GRIDBLOCK_H = 3,
  173. D_GRID_X = D_DIALOG_X + D_DIALOG_W - (GRIDSIZE * GRIDBLOCK_W) - D_MARGIN - 35,
  174. D_GRID_Y = D_DIALOG_Y + D_DIALOG_H - (GRIDSIZE * GRIDBLOCK_H) - D_MARGIN - 35,
  175. };
  176. /*
  177. ** Button enumerations:
  178. */
  179. enum {
  180. BUTTON_GDI=100,
  181. BUTTON_HOUSE,
  182. BUTTON_NEXT,
  183. BUTTON_PREV,
  184. BUTTON_OK,
  185. BUTTON_CANCEL,
  186. BUTTON_TEMPLATE,
  187. BUTTON_OVERLAY,
  188. BUTTON_SMUDGE,
  189. BUTTON_TERRAIN,
  190. BUTTON_UNIT,
  191. BUTTON_INFANTRY,
  192. BUTTON_AIRCRAFT,
  193. BUTTON_BUILDING,
  194. BUTTON_AIR,
  195. };
  196. /*
  197. ** Dialog variables
  198. */
  199. bool cancel = false; // true = user cancels
  200. const ObjectTypeClass * curobj; // Working object pointer.
  201. int x,y; // for drawing the grid
  202. KeyNumType input; // user input
  203. short const * occupy; // ptr into object's OccupyList
  204. int cell; // cell index for parsing OccupyList
  205. int i;
  206. int typeindex; // index of class type
  207. /*
  208. ** Buttons
  209. */
  210. ControlClass * commands;
  211. ListClass housebtn(BUTTON_HOUSE,
  212. D_GDI_X, D_GDI_Y, 60, 8*16,
  213. TPF_EFNT | TPF_NOSHADOW,
  214. MFCD::Retrieve("EBTN-UP.SHP"),
  215. MFCD::Retrieve("EBTN-DN.SHP"));
  216. for (house = HOUSE_FIRST; house < HOUSE_COUNT; house++) {
  217. housebtn.Add_Item(HouseTypeClass::As_Reference(house).IniName);
  218. }
  219. house = HOUSE_FIRST;
  220. TextButtonClass nextbtn(BUTTON_NEXT, TXT_RIGHT, TPF_EBUTTON, D_RIGHT_X, D_RIGHT_Y, D_RIGHT_W, D_RIGHT_H);
  221. TextButtonClass prevbtn(BUTTON_PREV, TXT_LEFT, TPF_EBUTTON, D_LEFT_X, D_LEFT_Y, D_LEFT_W, D_LEFT_H);
  222. TextButtonClass okbtn(BUTTON_OK, "OK", TPF_EBUTTON, D_OK_X, D_OK_Y, D_OK_W, D_OK_H);
  223. TextButtonClass cancelbtn(BUTTON_CANCEL, "Cancel", TPF_EBUTTON, D_CANCEL_X, D_CANCEL_Y, D_CANCEL_W, D_CANCEL_H);
  224. TextButtonClass templatebtn(BUTTON_TEMPLATE, "Template", TPF_EBUTTON, D_TEMPLATE_X, D_TEMPLATE_Y, D_TEMPLATE_W, D_TEMPLATE_H);
  225. TextButtonClass overlaybtn(BUTTON_OVERLAY, "Overlay", TPF_EBUTTON, D_OVERLAY_X, D_OVERLAY_Y, D_OVERLAY_W, D_OVERLAY_H);
  226. TextButtonClass smudgebtn(BUTTON_SMUDGE, "Smudge", TPF_EBUTTON, D_SMUDGE_X, D_SMUDGE_Y, D_SMUDGE_W, D_SMUDGE_H);
  227. TextButtonClass terrainbtn(BUTTON_TERRAIN, "Terrain", TPF_EBUTTON, D_TERRAIN_X, D_TERRAIN_Y, D_TERRAIN_W, D_TERRAIN_H);
  228. TextButtonClass unitbtn(BUTTON_UNIT, "Unit", TPF_EBUTTON, D_UNIT_X, D_UNIT_Y, D_UNIT_W, D_UNIT_H);
  229. TextButtonClass infantrybtn(BUTTON_INFANTRY, "Infantry", TPF_EBUTTON, D_INFANTRY_X, D_INFANTRY_Y, D_INFANTRY_W, D_INFANTRY_H);
  230. TextButtonClass aircraftbtn(BUTTON_AIRCRAFT, "Ships", TPF_EBUTTON, D_AIRCRAFT_X, D_AIRCRAFT_Y, D_AIRCRAFT_W, D_AIRCRAFT_H);
  231. TextButtonClass buildingbtn(BUTTON_BUILDING, "Building", TPF_EBUTTON, D_BUILDING_X, D_BUILDING_Y, D_BUILDING_W, D_BUILDING_H);
  232. TextButtonClass airbtn(BUTTON_AIR, "Aircraft", TPF_EBUTTON, D_AIR_X, D_AIR_Y, D_AIR_W, D_AIR_H);
  233. /*
  234. ** Initialize addable objects list; we must do this every time in case one
  235. ** of the object pools has become exhausted; that object won't be available
  236. ** for adding. (Skip aircraft, since they won't be used in the editor.)
  237. */
  238. Clear_List();
  239. TemplateTypeClass::Prep_For_Add();
  240. OverlayTypeClass::Prep_For_Add();
  241. SmudgeTypeClass::Prep_For_Add();
  242. TerrainTypeClass::Prep_For_Add();
  243. UnitTypeClass::Prep_For_Add();
  244. InfantryTypeClass::Prep_For_Add();
  245. VesselTypeClass::Prep_For_Add();
  246. BuildingTypeClass::Prep_For_Add();
  247. AircraftTypeClass::Prep_For_Add();
  248. /*
  249. ** Compute offset of each class type in the Objects array
  250. */
  251. TypeOffset[0] = 0;
  252. for (i = 1; i < NUM_EDIT_CLASSES; i++) {
  253. TypeOffset[i] = TypeOffset[i-1] + NumType[i-1];
  254. }
  255. /*
  256. ** Return if no objects to place
  257. */
  258. if (!ObjCount) {
  259. return(-1);
  260. }
  261. /*
  262. ** Initialize
  263. */
  264. Set_Logic_Page(SeenBuff);
  265. if (LastChoice >= ObjCount) {
  266. LastChoice = 0;
  267. }
  268. curobj = Objects[LastChoice]; // current object to choose
  269. commands = &nextbtn;
  270. housebtn.Add_Tail(*commands);
  271. prevbtn.Add_Tail(*commands);
  272. okbtn.Add_Tail(*commands);
  273. cancelbtn.Add_Tail(*commands);
  274. templatebtn.Add_Tail(*commands);
  275. overlaybtn.Add_Tail(*commands);
  276. smudgebtn.Add_Tail(*commands);
  277. terrainbtn.Add_Tail(*commands);
  278. unitbtn.Add_Tail(*commands);
  279. infantrybtn.Add_Tail(*commands);
  280. aircraftbtn.Add_Tail(*commands);
  281. buildingbtn.Add_Tail(*commands);
  282. airbtn.Add_Tail(*commands);
  283. /*
  284. ** Make sure the recorded house selection matches the house list
  285. ** box selection.
  286. */
  287. LastHouse = HousesType(housebtn.Current_Index());
  288. /*
  289. ** Main processing loop
  290. */
  291. bool display = true;
  292. bool process = true;
  293. while (process) {
  294. /*
  295. ** Invoke game callback
  296. */
  297. Call_Back();
  298. /*
  299. ** Refresh display if needed
  300. */
  301. if (display) {
  302. /*
  303. ** Display the dialog box
  304. */
  305. Hide_Mouse();
  306. Dialog_Box(D_DIALOG_X, D_DIALOG_Y, D_DIALOG_W, D_DIALOG_H);
  307. Draw_Caption(TXT_PLACE_OBJECT, D_DIALOG_X, D_DIALOG_Y, D_DIALOG_W);
  308. /*
  309. ** Display the current object:
  310. ** - save the current window dimensions
  311. ** - adjust the window size to the actual drawable area
  312. ** - draw the shape
  313. ** - reset the window dimensions
  314. */
  315. WindowList[WINDOW_EDITOR][WINDOWX] = D_PICTURE_X;
  316. WindowList[WINDOW_EDITOR][WINDOWY] = D_PICTURE_Y;
  317. WindowList[WINDOW_EDITOR][WINDOWWIDTH] = D_PICTURE_W;
  318. WindowList[WINDOW_EDITOR][WINDOWHEIGHT] = D_PICTURE_H;
  319. Change_Window((int)WINDOW_EDITOR);
  320. Draw_Box(D_PICTURE_X, D_PICTURE_Y, D_PICTURE_W, D_PICTURE_H, BOXSTYLE_DOWN, false);
  321. curobj->Display(WinW/2, WinH>>1, WINDOW_EDITOR, LastHouse);
  322. // curobj->Display(WinW<<2, WinH>>1, WINDOW_EDITOR, LastHouse);
  323. /*
  324. ** Erase the grid
  325. */
  326. LogicPage->Fill_Rect(D_GRID_X - GRIDBLOCK_W * 2, D_GRID_Y,
  327. D_GRID_X + GRIDSIZE * GRIDBLOCK_W,
  328. D_GRID_Y + GRIDSIZE * GRIDBLOCK_H, BLACK);
  329. /*
  330. ** Draw a box for every cell occupied
  331. */
  332. occupy = curobj->Occupy_List();
  333. while ( (*occupy) != REFRESH_EOL) {
  334. cell = (*occupy);
  335. occupy++;
  336. x = D_GRID_X + ((cell % MAP_CELL_W) * GRIDBLOCK_W);
  337. y = D_GRID_Y + ((cell / MAP_CELL_W) * GRIDBLOCK_H);
  338. LogicPage->Fill_Rect(x, y, x + GRIDBLOCK_W - 1, y + GRIDBLOCK_H - 1, scheme->Bright);
  339. }
  340. /*
  341. ** Draw the grid itself
  342. */
  343. for (y = 0; y <= GRIDSIZE; y++) {
  344. for (x = 0; x <= GRIDSIZE; x++) {
  345. LogicPage->Draw_Line(D_GRID_X + x * GRIDBLOCK_W, D_GRID_Y,
  346. D_GRID_X + x * GRIDBLOCK_W,
  347. D_GRID_Y + GRIDSIZE * GRIDBLOCK_H, scheme->Shadow);
  348. }
  349. LogicPage->Draw_Line(D_GRID_X, D_GRID_Y + y * GRIDBLOCK_H,
  350. D_GRID_X + GRIDSIZE * GRIDBLOCK_W, D_GRID_Y + y * GRIDBLOCK_H,
  351. scheme->Shadow);
  352. }
  353. /*
  354. ** Print the object's label from the class's Full_Name().
  355. ** Warning: Text_String returns an EMS pointer, so standard string
  356. ** functions won't work!
  357. */
  358. Fancy_Text_Print (curobj->Full_Name(),
  359. D_PICTURE_CX, D_PICTURE_Y + D_MARGIN, scheme, TBLACK,
  360. TPF_CENTER | TPF_EFNT | TPF_NOSHADOW);
  361. /*
  362. ** Redraw buttons
  363. ** Figure out which class category we're in & highlight that button
  364. ** This updates 'typeindex', which is used below, and it also updates
  365. ** the category button states.
  366. */
  367. i = 0;
  368. for (typeindex = 0; typeindex < NUM_EDIT_CLASSES; typeindex++) {
  369. i += NumType[typeindex];
  370. if (LastChoice < i) break;
  371. }
  372. templatebtn.Turn_Off();
  373. overlaybtn.Turn_Off();
  374. smudgebtn.Turn_Off();
  375. terrainbtn.Turn_Off();
  376. unitbtn.Turn_Off();
  377. infantrybtn.Turn_Off();
  378. aircraftbtn.Turn_Off();
  379. airbtn.Turn_Off();
  380. buildingbtn.Turn_Off();
  381. switch (typeindex + BUTTON_TEMPLATE) {
  382. case BUTTON_TEMPLATE:
  383. templatebtn.Turn_On();
  384. break;
  385. case BUTTON_OVERLAY:
  386. overlaybtn.Turn_On();
  387. break;
  388. case BUTTON_SMUDGE:
  389. smudgebtn.Turn_On();
  390. break;
  391. case BUTTON_TERRAIN:
  392. terrainbtn.Turn_On();
  393. break;
  394. case BUTTON_UNIT:
  395. unitbtn.Turn_On();
  396. break;
  397. case BUTTON_INFANTRY:
  398. infantrybtn.Turn_On();
  399. break;
  400. case BUTTON_AIRCRAFT:
  401. aircraftbtn.Turn_On();
  402. break;
  403. case BUTTON_AIR:
  404. airbtn.Turn_On();
  405. break;
  406. case BUTTON_BUILDING:
  407. buildingbtn.Turn_On();
  408. break;
  409. }
  410. /*
  411. ** Redraw buttons
  412. */
  413. commands->Draw_All();
  414. Show_Mouse();
  415. display = false;
  416. }
  417. /*
  418. ** Get user input
  419. */
  420. input = commands->Input();
  421. /*
  422. ** Process user input
  423. */
  424. switch (input) {
  425. /*
  426. ** GDI House
  427. */
  428. case (BUTTON_HOUSE | KN_BUTTON):
  429. house = HousesType(housebtn.Current_Index());
  430. /*
  431. ** Set flags & buttons
  432. */
  433. LastHouse = house;
  434. display = true;
  435. break;
  436. /*
  437. ** Next in list
  438. */
  439. case (KN_RIGHT):
  440. case (BUTTON_NEXT | KN_BUTTON):
  441. /*
  442. ** Increment to next obj
  443. */
  444. LastChoice++;
  445. if (LastChoice == ObjCount) {
  446. LastChoice = 0;
  447. }
  448. curobj = Objects[LastChoice];
  449. nextbtn.Turn_Off();
  450. display = true;
  451. break;
  452. /*
  453. ** Previous in list
  454. */
  455. case (KN_LEFT):
  456. case (BUTTON_PREV | KN_BUTTON):
  457. /*
  458. ** Decrement to prev obj
  459. */
  460. LastChoice--;
  461. if (LastChoice < 0) {
  462. LastChoice = ObjCount-1;
  463. }
  464. curobj = Objects[LastChoice];
  465. prevbtn.Turn_Off();
  466. display = true;
  467. break;
  468. /*
  469. ** Select a class type
  470. */
  471. case (BUTTON_TEMPLATE | KN_BUTTON):
  472. case (BUTTON_OVERLAY | KN_BUTTON):
  473. case (BUTTON_SMUDGE | KN_BUTTON):
  474. case (BUTTON_TERRAIN | KN_BUTTON):
  475. case (BUTTON_UNIT | KN_BUTTON):
  476. case (BUTTON_INFANTRY | KN_BUTTON):
  477. case (BUTTON_AIRCRAFT | KN_BUTTON):
  478. case (BUTTON_BUILDING | KN_BUTTON):
  479. case (BUTTON_AIR | KN_BUTTON):
  480. /*
  481. ** Find index of class
  482. */
  483. typeindex = input - (BUTTON_TEMPLATE | KN_BUTTON);
  484. /*
  485. ** If no objects of that type, do nothing
  486. */
  487. if (NumType[typeindex]==0) {
  488. display = true;
  489. break;
  490. }
  491. /*
  492. ** Set current object
  493. */
  494. LastChoice = TypeOffset[typeindex];
  495. curobj = Objects[LastChoice];
  496. display = true;
  497. break;
  498. /*
  499. ** Next category
  500. */
  501. case KN_PGDN:
  502. typeindex++;
  503. if (typeindex==NUM_EDIT_CLASSES) {
  504. typeindex = 0;
  505. }
  506. /*
  507. ** Set current object
  508. */
  509. LastChoice = TypeOffset[typeindex];
  510. curobj = Objects[LastChoice];
  511. display = true;
  512. break;
  513. /*
  514. ** Previous category
  515. */
  516. case KN_PGUP:
  517. typeindex--;
  518. if (typeindex < 0) {
  519. typeindex = NUM_EDIT_CLASSES - 1;
  520. }
  521. /*
  522. ** Set current object
  523. */
  524. LastChoice = TypeOffset[typeindex];
  525. curobj = Objects[LastChoice];
  526. display = true;
  527. break;
  528. /*
  529. ** Jump to 1st choice
  530. */
  531. case KN_HOME:
  532. LastChoice = 0;
  533. /*
  534. ** Set current object
  535. */
  536. curobj = Objects[LastChoice];
  537. display = true;
  538. break;
  539. /*
  540. ** OK
  541. */
  542. case (KN_RETURN):
  543. case (BUTTON_OK | KN_BUTTON):
  544. cancel = false;
  545. process = false;
  546. break;
  547. /*
  548. ** Cancel
  549. */
  550. case (KN_ESC):
  551. case (BUTTON_CANCEL | KN_BUTTON):
  552. cancel = true;
  553. process = false;
  554. break;
  555. default:
  556. break;
  557. }
  558. }
  559. /*
  560. ** Redraw the display
  561. */
  562. HidPage.Clear();
  563. Flag_To_Redraw(true);
  564. Render();
  565. if (cancel) {
  566. return(-1);
  567. }
  568. return(0);
  569. }
  570. /***************************************************************************
  571. * MapEditClass::Start_Placement -- enters placement mode *
  572. * *
  573. * INPUT: *
  574. * none. *
  575. * *
  576. * OUTPUT: *
  577. * none. *
  578. * *
  579. * WARNINGS: *
  580. * none. *
  581. * *
  582. * HISTORY: *
  583. * 11/04/1994 BR : Created. *
  584. *=========================================================================*/
  585. void MapEditClass::Start_Placement(void)
  586. {
  587. /*
  588. ** Initialize addable objects list; we must do this every time in case one
  589. ** of the object pools has become exhausted; that object won't be available
  590. ** for adding. These must be added in the same order expected by the
  591. ** object selection dialog (same as button order).
  592. */
  593. Clear_List();
  594. TemplateTypeClass::Prep_For_Add();
  595. OverlayTypeClass::Prep_For_Add();
  596. SmudgeTypeClass::Prep_For_Add();
  597. TerrainTypeClass::Prep_For_Add();
  598. UnitTypeClass::Prep_For_Add();
  599. InfantryTypeClass::Prep_For_Add();
  600. VesselTypeClass::Prep_For_Add();
  601. BuildingTypeClass::Prep_For_Add();
  602. AircraftTypeClass::Prep_For_Add();
  603. /*
  604. ** Compute offset of each class type in the Objects array
  605. */
  606. TypeOffset[0] = 0;
  607. for (int i = 1; i < NUM_EDIT_CLASSES; i++) {
  608. TypeOffset[i] = TypeOffset[i-1] + NumType[i-1];
  609. }
  610. /*
  611. ** Create the placement object:
  612. ** - For normal placement mode, use the last-used index into Objects
  613. ** (LastChoice), and the last-used house (LastHouse).
  614. ** - For base-building mode, force the object to be a building, and use the
  615. ** House specified in the Base object
  616. */
  617. if (!BaseBuilding) {
  618. if (LastChoice >= ObjCount) {
  619. LastChoice = ObjCount - 1;
  620. }
  621. PendingObject = Objects[LastChoice];
  622. PendingHouse = LastHouse;
  623. PendingObjectPtr = PendingObject->Create_One_Of(HouseClass::As_Pointer(LastHouse));
  624. } else {
  625. if (LastChoice < TypeOffset[7]) {
  626. LastChoice = TypeOffset[7];
  627. }
  628. if (LastChoice >= ObjCount) {
  629. LastChoice = ObjCount - 1;
  630. }
  631. PendingObject = Objects[LastChoice];
  632. PendingHouse = LastHouse = Base.House;
  633. PendingObjectPtr = PendingObject->Create_One_Of(HouseClass::As_Pointer(LastHouse));
  634. }
  635. /*
  636. ** Error if no more objects available
  637. */
  638. if (!PendingObjectPtr) {
  639. WWMessageBox().Process("No more objects of this type available.");
  640. HidPage.Clear();
  641. Flag_To_Redraw(true);
  642. Render();
  643. PendingObject = NULL;
  644. if (BaseBuilding) {
  645. Cancel_Base_Building();
  646. }
  647. return;
  648. }
  649. /*
  650. ** Set the placement cursor
  651. */
  652. Set_Cursor_Pos();
  653. Set_Cursor_Shape(PendingObject->Occupy_List());
  654. }
  655. /***************************************************************************
  656. * MapEditClass::Place_Object -- attempts to place the current object *
  657. * *
  658. * Placement of "real" objects is simply checked via their Unlimbo routine.*
  659. * Placement of templates is more complex: *
  660. * - for every cell in the template's OccupyList, check for objects *
  661. * already in that cell by looking at the cell's OccupyList & *
  662. * OverlapList *
  663. * - "lift" all the objects in the cell by Mark'ing them *
  664. * - temporarily place the template in that cell *
  665. * - try to Unlimbo all the objects that were in the cell. If any *
  666. * objects fail to Unlimbo onto that template, the template cannot *
  667. * be placed here *
  668. * *
  669. * It is assumed that the object being placed is a "new" object; the *
  670. * object's strength & mission are not set during Unlimbo. *
  671. * *
  672. * INPUT: *
  673. * none. *
  674. * *
  675. * OUTPUT: *
  676. * 0 = OK, -1 = unable to place *
  677. * *
  678. * WARNINGS: *
  679. * none. *
  680. * *
  681. * HISTORY: *
  682. * 11/04/1994 BR : Created. *
  683. *=========================================================================*/
  684. int MapEditClass::Place_Object(void)
  685. {
  686. CELL template_cell; // cell being checked for template
  687. COORDINATE obj_coord; // coord of occupier object
  688. int okflag; // OK to place a template?
  689. short const * occupy; // ptr into template's OccupyList
  690. ObjectClass * occupier; // occupying object
  691. TemplateType save_ttype; // for saving cell's TType
  692. unsigned char save_ticon; // for saving cell's TIcon
  693. // BaseNodeClass node; // for adding to an AI Base
  694. /*
  695. ** Placing a template:
  696. ** - first lift up any objects in the cell
  697. ** - place the template, and try to replace the objects; if they won't go
  698. ** back, the template can't go there
  699. */
  700. //ScenarioInit++;
  701. if (PendingObject->What_Am_I() == RTTI_TEMPLATETYPE) {
  702. /*
  703. ** Loop through all cells this template will occupy
  704. */
  705. okflag = true;
  706. occupy = PendingObject->Occupy_List();
  707. while ((*occupy) != REFRESH_EOL) {
  708. /*
  709. ** Check this cell for an occupier
  710. */
  711. template_cell = (ZoneCell+ZoneOffset) + (*occupy);
  712. if ((*this)[template_cell].Cell_Occupier()) {
  713. occupier = (*this)[template_cell].Cell_Occupier();
  714. /*
  715. ** Save object's coordinates
  716. */
  717. obj_coord = occupier->Coord;
  718. /*
  719. ** Place the object in limbo
  720. */
  721. occupier->Mark(MARK_UP);
  722. /*
  723. ** Set the cell's template values
  724. */
  725. save_ttype = (*this)[template_cell].TType;
  726. save_ticon = (*this)[template_cell].TIcon;
  727. (*this)[template_cell].TType =
  728. ((TemplateTypeClass *)PendingObject)->Type;
  729. (*this)[template_cell].TIcon = Cell_X(*occupy) + Cell_Y(*occupy) *
  730. ((TemplateTypeClass *)PendingObject)->Width;
  731. (*this)[template_cell].Recalc_Attributes();
  732. /*
  733. ** Try to put the object back down
  734. */
  735. if (occupier->Can_Enter_Cell(Coord_Cell(obj_coord)) != MOVE_OK) {
  736. okflag = false;
  737. }
  738. /*
  739. ** Put everything back the way it was
  740. */
  741. (*this)[template_cell].TType = save_ttype;
  742. (*this)[template_cell].TIcon = save_ticon;
  743. (*this)[template_cell].Recalc_Attributes();
  744. /*
  745. ** Major error if can't replace the object now
  746. */
  747. occupier->Mark(MARK_DOWN);
  748. }
  749. occupy++;
  750. }
  751. /*
  752. ** If it's still OK after ALL THAT, place the template
  753. */
  754. if (okflag) {
  755. if (PendingObjectPtr->Unlimbo(Cell_Coord(ZoneCell + ZoneOffset))) {
  756. /*
  757. ** Loop through all cells occupied by this template, and clear the
  758. ** smudge & overlay.
  759. */
  760. occupy = PendingObject->Occupy_List();
  761. while ((*occupy) != REFRESH_EOL) {
  762. /*
  763. ** Get cell for this occupy item
  764. */
  765. template_cell = (ZoneCell+ZoneOffset) + (*occupy);
  766. /*
  767. ** Clear smudge & overlay
  768. */
  769. (*this)[template_cell].Overlay = OVERLAY_NONE;
  770. (*this)[template_cell].OverlayData = 0;
  771. (*this)[template_cell].Smudge = SMUDGE_NONE;
  772. /*
  773. ** make adjacent cells recalc attrib's
  774. */
  775. (*this)[template_cell].Recalc_Attributes();
  776. (*this)[template_cell].Wall_Update();
  777. (*this)[template_cell].Concrete_Calc();
  778. occupy++;
  779. }
  780. /*
  781. ** Set flags etc
  782. */
  783. PendingObjectPtr = 0;
  784. PendingObject = 0;
  785. PendingHouse = HOUSE_NONE;
  786. Set_Cursor_Shape(0);
  787. //ScenarioInit--;
  788. TotalValue = Overpass();
  789. Flag_To_Redraw(false);
  790. return(0);
  791. }
  792. /*
  793. ** Failure to deploy results in a returned failure code.
  794. */
  795. //ScenarioInit--;
  796. return(-1);
  797. }
  798. /*
  799. ** Not OK; return error
  800. */
  801. //ScenarioInit--;
  802. return(-1);
  803. }
  804. /*
  805. ** Placing infantry: Infantry can go into cell sub-positions, so find the
  806. ** sub-position closest to the mouse & put him there
  807. */
  808. if (PendingObject->What_Am_I() == RTTI_INFANTRYTYPE) {
  809. /*
  810. ** Find cell sub-position
  811. */
  812. if (Is_Spot_Free(Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y()))) {
  813. obj_coord = Closest_Free_Spot(Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y()));
  814. } else {
  815. obj_coord = NULL;
  816. }
  817. /*
  818. ** No free spots; don't place the object
  819. */
  820. if (obj_coord == NULL) {
  821. //ScenarioInit--;
  822. return(-1);
  823. }
  824. /*
  825. ** Unlimbo the object
  826. */
  827. if (PendingObjectPtr->Unlimbo(obj_coord)) {
  828. ((InfantryClass *)PendingObjectPtr)->Set_Occupy_Bit(obj_coord);
  829. // Map[obj_coord].Flag.Composite |=
  830. // (1 << CellClass::Spot_Index(obj_coord));
  831. PendingObjectPtr = 0;
  832. PendingObject = 0;
  833. PendingHouse = HOUSE_NONE;
  834. Set_Cursor_Shape(0);
  835. //ScenarioInit--;
  836. return(0);
  837. }
  838. //ScenarioInit--;
  839. return(-1);
  840. }
  841. /*
  842. ** Placing an object
  843. */
  844. if (PendingObjectPtr->Unlimbo(Cell_Coord(ZoneCell + ZoneOffset))) {
  845. /*
  846. ** Update the Tiberium computation if we're placing an overlay
  847. */
  848. if (PendingObject->What_Am_I() == RTTI_OVERLAYTYPE &&
  849. ((OverlayTypeClass *)PendingObject)->IsTiberium) {
  850. TotalValue = Overpass();
  851. Flag_To_Redraw(false);
  852. }
  853. /*
  854. ** If we're building a base, add this building to the base's Node list.
  855. */
  856. if (BaseBuilding && PendingObject->What_Am_I() == RTTI_BUILDINGTYPE) {
  857. // node.Type = ((BuildingTypeClass *)PendingObject)->Type;
  858. // node.Cell = Coord_Cell(PendingObjectPtr->Coord);
  859. Base.Nodes.Add(BaseNodeClass(((BuildingTypeClass *)PendingObject)->Type, Coord_Cell(PendingObjectPtr->Coord)));
  860. }
  861. PendingObjectPtr = 0;
  862. PendingObject = 0;
  863. PendingHouse = HOUSE_NONE;
  864. Set_Cursor_Shape(0);
  865. //ScenarioInit--;
  866. return(0);
  867. }
  868. return(-1);
  869. }
  870. /***************************************************************************
  871. * MapEditClass::Cancel_Placement -- cancels placement mode *
  872. * *
  873. * INPUT: *
  874. * none. *
  875. * *
  876. * OUTPUT: *
  877. * none. *
  878. * *
  879. * WARNINGS: *
  880. * none. *
  881. * *
  882. * HISTORY: *
  883. * 11/04/1994 BR : Created. *
  884. *=========================================================================*/
  885. void MapEditClass::Cancel_Placement(void)
  886. {
  887. /*
  888. ** Delete the placement object
  889. */
  890. delete PendingObjectPtr;
  891. PendingObject = 0;
  892. PendingObjectPtr = 0;
  893. PendingHouse = HOUSE_NONE;
  894. /*
  895. ** Restore cursor shape
  896. */
  897. Set_Cursor_Shape(0);
  898. /*
  899. ** Redraw the map to erase old leftovers
  900. */
  901. HidPage.Clear();
  902. Flag_To_Redraw(true);
  903. Render();
  904. }
  905. /***************************************************************************
  906. * MapEditClass::Place_Next -- while placing object, goes to next *
  907. * *
  908. * - Deletes the current 'PendingObjectPtr' *
  909. * - Increments LastChoice *
  910. * - Tries to create a new 'PendingObjectPtr'; if fails, keeps *
  911. * incrementing until it gets it *
  912. * *
  913. * INPUT: *
  914. * none. *
  915. * *
  916. * OUTPUT: *
  917. * none. *
  918. * *
  919. * WARNINGS: *
  920. * none. *
  921. * *
  922. * HISTORY: *
  923. * 11/03/1994 BR : Created. *
  924. *=========================================================================*/
  925. void MapEditClass::Place_Next(void)
  926. {
  927. delete PendingObjectPtr;
  928. PendingObjectPtr = NULL;
  929. PendingObject = NULL;
  930. /*
  931. ** Loop until we create a valid object
  932. */
  933. while (!PendingObjectPtr) {
  934. /*
  935. ** Go to next object in Objects list
  936. */
  937. LastChoice++;
  938. if (LastChoice == ObjCount) {
  939. /*
  940. ** If we're in normal placement mode, wrap to the 1st object;
  941. ** if we're in base-building mode, wrap to the 1st building
  942. */
  943. if (!BaseBuilding) {
  944. LastChoice = 0;
  945. } else {
  946. LastChoice = TypeOffset[7];
  947. }
  948. }
  949. /*
  950. ** Create placement object
  951. */
  952. PendingObject = Objects[LastChoice];
  953. PendingHouse = LastHouse;
  954. PendingObjectPtr = PendingObject->Create_One_Of(HouseClass::As_Pointer(PendingHouse));
  955. if (!PendingObjectPtr) {
  956. PendingObject = NULL;
  957. }
  958. }
  959. /*
  960. ** Set the new cursor shape
  961. */
  962. Set_Cursor_Pos();
  963. Set_Cursor_Shape(0);
  964. Set_Cursor_Shape(PendingObject->Occupy_List());
  965. /*
  966. ** Redraw the map to erase old leftovers
  967. */
  968. HidPage.Clear();
  969. Flag_To_Redraw(true);
  970. Render();
  971. }
  972. /***************************************************************************
  973. * MapEditClass::Place_Prev -- while placing object, goes to previous *
  974. * *
  975. * - Deletes the current 'PendingObjectPtr' *
  976. * - Decrements LastChoice *
  977. * - Tries to create a new 'PendingObjectPtr'; if fails, keeps *
  978. * decrementing until it gets it *
  979. * *
  980. * INPUT: *
  981. * none. *
  982. * *
  983. * OUTPUT: *
  984. * none. *
  985. * *
  986. * WARNINGS: *
  987. * none. *
  988. * *
  989. * HISTORY: *
  990. * 11/03/1994 BR : Created. *
  991. *=========================================================================*/
  992. void MapEditClass::Place_Prev(void)
  993. {
  994. delete PendingObjectPtr;
  995. PendingObjectPtr = NULL;
  996. PendingObject = NULL;
  997. /*
  998. ** Loop until we create a valid object
  999. */
  1000. while (!PendingObjectPtr) {
  1001. /*
  1002. ** Go to prev object in Objects list
  1003. */
  1004. LastChoice--;
  1005. /*
  1006. ** If we're in normal placement mode, wrap at the 1st object.
  1007. ** If we're building a base, wrap at the 1st building.
  1008. */
  1009. if (!BaseBuilding) {
  1010. if (LastChoice < 0) {
  1011. LastChoice = ObjCount - 1;
  1012. }
  1013. } else {
  1014. if (LastChoice < TypeOffset[7]) {
  1015. LastChoice = ObjCount - 1;
  1016. }
  1017. }
  1018. /*
  1019. ** Create placement object
  1020. */
  1021. PendingObject = Objects[LastChoice];
  1022. PendingHouse = LastHouse;
  1023. PendingObjectPtr = PendingObject->Create_One_Of(HouseClass::As_Pointer(PendingHouse));
  1024. if (!PendingObjectPtr) {
  1025. PendingObject = NULL;
  1026. }
  1027. }
  1028. /*
  1029. ** Set the new cursor shape
  1030. */
  1031. Set_Cursor_Pos();
  1032. Set_Cursor_Shape(0);
  1033. Set_Cursor_Shape(PendingObject->Occupy_List());
  1034. /*
  1035. ** Redraw the map to erase old leftovers
  1036. */
  1037. HidPage.Clear();
  1038. Flag_To_Redraw(true);
  1039. Render();
  1040. }
  1041. /***************************************************************************
  1042. * MapEditClass::Place_Next_Category -- places next category of object *
  1043. * *
  1044. * INPUT: *
  1045. * none. *
  1046. * *
  1047. * OUTPUT: *
  1048. * none. *
  1049. * *
  1050. * WARNINGS: *
  1051. * none. *
  1052. * *
  1053. * HISTORY: *
  1054. * 11/03/1994 BR : Created. *
  1055. *=========================================================================*/
  1056. void MapEditClass::Place_Next_Category(void)
  1057. {
  1058. int i;
  1059. /*
  1060. ** Don't allow this command if we're building a base; the only valid
  1061. ** category for base-building is buildings.
  1062. */
  1063. if (BaseBuilding) {
  1064. return;
  1065. }
  1066. delete PendingObjectPtr;
  1067. PendingObjectPtr = NULL;
  1068. PendingObject = NULL;
  1069. /*
  1070. ** Go to next category in Objects list
  1071. */
  1072. i = LastChoice;
  1073. while (Objects[i]->What_Am_I() == Objects[LastChoice]->What_Am_I()) {
  1074. i++;
  1075. if (i == ObjCount) {
  1076. i = 0;
  1077. }
  1078. }
  1079. LastChoice = i;
  1080. /*
  1081. ** Loop until we create a valid object
  1082. */
  1083. while (!PendingObjectPtr) {
  1084. /*
  1085. ** Get house for this object type
  1086. */
  1087. // if (!Verify_House(LastHouse, Objects[LastChoice])) {
  1088. // LastHouse = Cycle_House(LastHouse, Objects[LastChoice]);
  1089. // }
  1090. /*
  1091. ** Create placement object
  1092. */
  1093. PendingObject = Objects[LastChoice];
  1094. PendingHouse = LastHouse;
  1095. PendingObjectPtr = PendingObject->Create_One_Of(HouseClass::As_Pointer(PendingHouse));
  1096. /*
  1097. ** If this one failed, try the next
  1098. */
  1099. if (!PendingObjectPtr) {
  1100. PendingObject = NULL;
  1101. LastChoice++;
  1102. if (LastChoice == ObjCount) {
  1103. LastChoice = 0;
  1104. }
  1105. }
  1106. }
  1107. /*
  1108. ** Set the new cursor shape
  1109. */
  1110. Set_Cursor_Pos();
  1111. Set_Cursor_Shape(0);
  1112. Set_Cursor_Shape(PendingObject->Occupy_List());
  1113. /*
  1114. ** Redraw the map to erase old leftovers
  1115. */
  1116. HidPage.Clear();
  1117. Flag_To_Redraw(true);
  1118. Render();
  1119. }
  1120. /***************************************************************************
  1121. * MapEditClass::Place_Prev_Category -- places previous category of object *
  1122. * *
  1123. * INPUT: *
  1124. * none. *
  1125. * *
  1126. * OUTPUT: *
  1127. * none. *
  1128. * *
  1129. * WARNINGS: *
  1130. * none. *
  1131. * *
  1132. * HISTORY: *
  1133. * 11/03/1994 BR : Created. *
  1134. *=========================================================================*/
  1135. void MapEditClass::Place_Prev_Category(void)
  1136. {
  1137. int i;
  1138. /*
  1139. ** Don't allow this command if we're building a base; the only valid
  1140. ** category for base-building is buildings.
  1141. */
  1142. if (BaseBuilding) {
  1143. return;
  1144. }
  1145. delete PendingObjectPtr;
  1146. PendingObjectPtr = NULL;
  1147. PendingObject = NULL;
  1148. /*
  1149. ** Go to prev category in Objects list
  1150. */
  1151. i = LastChoice;
  1152. /*
  1153. ** Scan for start of this category
  1154. */
  1155. while (Objects[i]->What_Am_I() == Objects[LastChoice]->What_Am_I()) {
  1156. i--;
  1157. if (i < 0) {
  1158. i = ObjCount - 1;
  1159. }
  1160. }
  1161. i--;
  1162. if (i < 0) i = ObjCount-1;
  1163. LastChoice = i;
  1164. /*
  1165. ** Scan for the previous category
  1166. */
  1167. while (Objects[i]->What_Am_I() == Objects[LastChoice]->What_Am_I()) {
  1168. i--;
  1169. if (i < 0) {
  1170. i = ObjCount - 1;
  1171. }
  1172. }
  1173. i++;
  1174. if (i >= ObjCount) i = 0;
  1175. LastChoice = i;
  1176. /*
  1177. ** Loop until we create a valid object
  1178. */
  1179. while (!PendingObjectPtr) {
  1180. /*
  1181. ** Get house for this object type
  1182. */
  1183. // if (!Verify_House(LastHouse, Objects[LastChoice])) {
  1184. // LastHouse = Cycle_House(LastHouse, Objects[LastChoice]);
  1185. // }
  1186. /*
  1187. ** Create placement object
  1188. */
  1189. PendingObject = Objects[LastChoice];
  1190. PendingHouse = LastHouse;
  1191. PendingObjectPtr = PendingObject->Create_One_Of(HouseClass::As_Pointer(PendingHouse));
  1192. /*
  1193. ** If this one failed, try the next
  1194. */
  1195. if (!PendingObjectPtr) {
  1196. PendingObject = NULL;
  1197. LastChoice--;
  1198. if (LastChoice < 0) {
  1199. LastChoice = ObjCount - 1;
  1200. }
  1201. }
  1202. }
  1203. /*
  1204. ** Set the new cursor shape
  1205. */
  1206. Set_Cursor_Pos();
  1207. Set_Cursor_Shape(0);
  1208. Set_Cursor_Shape(PendingObject->Occupy_List());
  1209. /*
  1210. ** Redraw the map to erase old leftovers
  1211. */
  1212. HidPage.Clear();
  1213. Flag_To_Redraw(true);
  1214. Render();
  1215. }
  1216. /***************************************************************************
  1217. * MapEditClass::Place_Home -- homes the placement object *
  1218. * *
  1219. * INPUT: *
  1220. * none. *
  1221. * *
  1222. * OUTPUT: *
  1223. * none. *
  1224. * *
  1225. * WARNINGS: *
  1226. * none. *
  1227. * *
  1228. * HISTORY: *
  1229. * 11/03/1994 BR : Created. *
  1230. *=========================================================================*/
  1231. void MapEditClass::Place_Home(void)
  1232. {
  1233. delete PendingObjectPtr;
  1234. PendingObjectPtr = NULL;
  1235. PendingObject = NULL;
  1236. /*
  1237. ** Don't allow this command if we're building a base; the only valid
  1238. ** category for base-building is buildings.
  1239. */
  1240. if (BaseBuilding) {
  1241. return;
  1242. }
  1243. /*
  1244. ** Loop until we create a valid object
  1245. */
  1246. LastChoice = 0;
  1247. while (!PendingObjectPtr) {
  1248. /*
  1249. ** Get house for this object type
  1250. */
  1251. if (!Verify_House(LastHouse, Objects[LastChoice])) {
  1252. LastHouse = Cycle_House(LastHouse, Objects[LastChoice]);
  1253. }
  1254. /*
  1255. ** Create placement object
  1256. */
  1257. PendingObject = Objects[LastChoice];
  1258. PendingHouse = LastHouse;
  1259. PendingObjectPtr = PendingObject->Create_One_Of(HouseClass::As_Pointer(PendingHouse));
  1260. /*
  1261. ** If this one failed, try the next
  1262. */
  1263. if (!PendingObjectPtr) {
  1264. PendingObject = NULL;
  1265. LastChoice++;
  1266. if (LastChoice == ObjCount) {
  1267. LastChoice = 0;
  1268. }
  1269. }
  1270. }
  1271. /*
  1272. ** Set the new cursor shape
  1273. */
  1274. Set_Cursor_Pos();
  1275. Set_Cursor_Shape(0);
  1276. Set_Cursor_Shape(PendingObject->Occupy_List());
  1277. /*
  1278. ** Redraw the map to erase old leftovers
  1279. */
  1280. HidPage.Clear();
  1281. Flag_To_Redraw(true);
  1282. Render();
  1283. }
  1284. /***************************************************************************
  1285. * MapEditClass::Toggle_House -- toggles current placement object's house *
  1286. * *
  1287. * INPUT: *
  1288. * *
  1289. * OUTPUT: *
  1290. * *
  1291. * WARNINGS: *
  1292. * *
  1293. * HISTORY: *
  1294. * 11/04/1994 BR : Created. *
  1295. *=========================================================================*/
  1296. void MapEditClass::Toggle_House(void)
  1297. {
  1298. TechnoClass *tp;
  1299. /*
  1300. ** Don't allow this command if we're building a base; the only valid
  1301. ** house for base-building is the one assigned to the base.
  1302. */
  1303. if (BaseBuilding) {
  1304. return;
  1305. }
  1306. /*
  1307. ** Only techno objects can be owned by a house; return if not a techno
  1308. */
  1309. if (!PendingObjectPtr->Is_Techno()) {
  1310. return;
  1311. }
  1312. /*
  1313. ** Select the house that will own this object
  1314. */
  1315. LastHouse = Cycle_House(PendingObjectPtr->Owner(), PendingObject);
  1316. /*
  1317. ** Change the house
  1318. */
  1319. tp = (TechnoClass *)PendingObjectPtr;
  1320. tp->House = HouseClass::As_Pointer(LastHouse);
  1321. /*
  1322. ** Set house variables to new house
  1323. */
  1324. PendingHouse = LastHouse;
  1325. }
  1326. /***************************************************************************
  1327. * MapEditClass::Set_House_Buttons -- toggles house buttons for btn list *
  1328. * *
  1329. * Looks in the given button list for the given GDI, NOD & Neutral button *
  1330. * id's. Sets the On/Off state of the buttons based on the given house, *
  1331. * only if that button is found in the list. *
  1332. * *
  1333. * INPUT: *
  1334. * house house to set buttons to *
  1335. * btnlist ptr to button list to search *
  1336. * base_id button ID for GDI; assumes other id's are sequential*
  1337. * *
  1338. * OUTPUT: *
  1339. * none. *
  1340. * *
  1341. * WARNINGS: *
  1342. * none. *
  1343. * *
  1344. * HISTORY: *
  1345. * 11/23/1994 BR : Created. *
  1346. * 01/26/1996 JLB : Uses new house selection list method. *
  1347. *=========================================================================*/
  1348. void MapEditClass::Set_House_Buttons(HousesType house, GadgetClass *, int )
  1349. //void MapEditClass::Set_House_Buttons(HousesType house, GadgetClass * btnlist, int base_id)
  1350. {
  1351. HouseList->Set_Selected_Index(house);
  1352. #ifdef NEVER
  1353. HousesType h;
  1354. int id;
  1355. TextButtonClass * btn;
  1356. /*
  1357. ** Loop through all houses, searching the button list for each one.
  1358. */
  1359. for (h = HOUSE_FIRST; h < HOUSE_COUNT; h++) {
  1360. /*
  1361. ** Compute the desired button ID; get a pointer to the button
  1362. */
  1363. id = (int)h + base_id;
  1364. btn = (TextButtonClass *)btnlist->Extract_Gadget(id);
  1365. if (btn) {
  1366. /*
  1367. ** If this house value is the desired one, turn the button on;
  1368. ** otherwise, turn it off.
  1369. */
  1370. if (h == house) {
  1371. btn->Turn_On();
  1372. } else {
  1373. btn->Turn_Off();
  1374. }
  1375. }
  1376. }
  1377. #endif
  1378. }
  1379. /***************************************************************************
  1380. * MapEditClass::Start_Trigger_Placement -- enters trigger placement mode *
  1381. * *
  1382. * INPUT: *
  1383. * *
  1384. * OUTPUT: *
  1385. * *
  1386. * WARNINGS: *
  1387. * *
  1388. * HISTORY: *
  1389. * 12/01/1994 BR : Created. *
  1390. *=========================================================================*/
  1391. void MapEditClass::Start_Trigger_Placement(void)
  1392. {
  1393. Set_Default_Mouse(MOUSE_CAN_MOVE);
  1394. Override_Mouse_Shape(MOUSE_CAN_MOVE);
  1395. }
  1396. /***************************************************************************
  1397. * MapEditClass::Stop_Trigger_Placement -- exits trigger placement mode *
  1398. * *
  1399. * INPUT: *
  1400. * none. *
  1401. * *
  1402. * OUTPUT: *
  1403. * none. *
  1404. * *
  1405. * WARNINGS: *
  1406. * none. *
  1407. * *
  1408. * HISTORY: *
  1409. * 12/01/1994 BR : Created. *
  1410. *=========================================================================*/
  1411. void MapEditClass::Stop_Trigger_Placement(void)
  1412. {
  1413. CurTrigger = NULL;
  1414. Set_Default_Mouse(MOUSE_NORMAL);
  1415. Override_Mouse_Shape(MOUSE_NORMAL);
  1416. }
  1417. /***************************************************************************
  1418. * MapEditClass::Place_Trigger -- assigns trigger to object or cell *
  1419. * *
  1420. * INPUT: *
  1421. * none. *
  1422. * *
  1423. * OUTPUT: *
  1424. * none. *
  1425. * *
  1426. * WARNINGS: *
  1427. * none. *
  1428. * *
  1429. * HISTORY: *
  1430. * 12/01/1994 BR : Created. *
  1431. *=========================================================================*/
  1432. void MapEditClass::Place_Trigger(void)
  1433. {
  1434. ObjectClass * object=NULL; // Generic object clicked on.
  1435. int x,y;
  1436. CELL cell; // Cell that was selected.
  1437. /*
  1438. ** See if an object was clicked on
  1439. */
  1440. x = Keyboard->MouseQX;
  1441. y = Keyboard->MouseQY;
  1442. /*
  1443. ** Get cell for x,y
  1444. */
  1445. cell = Click_Cell_Calc(x, y);
  1446. /*
  1447. ** Convert x,y to offset from cell upper-left
  1448. */
  1449. x = (x-TacPixelX) % ICON_PIXEL_W;
  1450. y = (y-TacPixelY) % ICON_PIXEL_H;
  1451. /*
  1452. ** Get object at that x,y
  1453. */
  1454. object = Cell_Object(cell, x, y);
  1455. /*
  1456. ** Assign trigger to an object
  1457. */
  1458. AttachType a1 = CurTrigger->Attaches_To();
  1459. if (object && (a1 & ATTACH_OBJECT) != 0) {
  1460. if (CurTrigger) {
  1461. TriggerClass * tt = Find_Or_Make(CurTrigger);
  1462. if (tt) {
  1463. object->Trigger = tt;
  1464. }
  1465. }
  1466. } else {
  1467. /*
  1468. ** Assign trigger to a cell
  1469. */
  1470. if ((a1 & ATTACH_CELL) != 0) {
  1471. if (CurTrigger) {
  1472. TriggerClass * tt = Find_Or_Make(CurTrigger);
  1473. Map[cell].Trigger = tt;
  1474. }
  1475. // CellTriggers[cell] = CurTrigger;
  1476. }
  1477. }
  1478. /*
  1479. ** Force map to redraw
  1480. */
  1481. HidPage.Clear();
  1482. Flag_To_Redraw(true);
  1483. }
  1484. /***************************************************************************
  1485. * MapEditClass::Start_Base_Building -- starts base-building mode *
  1486. * *
  1487. * INPUT: *
  1488. * none. *
  1489. * *
  1490. * OUTPUT: *
  1491. * none. *
  1492. * *
  1493. * WARNINGS: *
  1494. * none. *
  1495. * *
  1496. * HISTORY: *
  1497. * 12/01/1994 BR : Created. *
  1498. *=========================================================================*/
  1499. void MapEditClass::Start_Base_Building(void)
  1500. {
  1501. /*
  1502. ** Fully build the base so the user can edit it
  1503. */
  1504. Build_Base_To(100);
  1505. /*
  1506. ** Start placement mode
  1507. */
  1508. BaseBuilding = true;
  1509. Start_Placement();
  1510. /*
  1511. ** Force map to redraw
  1512. */
  1513. HidPage.Clear();
  1514. Flag_To_Redraw(true);
  1515. }
  1516. /***************************************************************************
  1517. * MapEditClass::Cancel_Base_Building -- stops base-building mode *
  1518. * *
  1519. * INPUT: *
  1520. * none. *
  1521. * *
  1522. * OUTPUT: *
  1523. * none. *
  1524. * *
  1525. * WARNINGS: *
  1526. * none. *
  1527. * *
  1528. * HISTORY: *
  1529. * 12/01/1994 BR : Created. *
  1530. *=========================================================================*/
  1531. void MapEditClass::Cancel_Base_Building(void)
  1532. {
  1533. /*
  1534. ** Build the base to the proper amount
  1535. */
  1536. Build_Base_To(Scen.Percent);
  1537. /*
  1538. ** Cancel placement mode
  1539. */
  1540. Cancel_Placement();
  1541. BaseBuilding = false;
  1542. /*
  1543. ** Force map to redraw
  1544. */
  1545. HidPage.Clear();
  1546. Flag_To_Redraw(true);
  1547. }
  1548. /***************************************************************************
  1549. * MapEditClass::Build_Base_To -- builds the AI base to the given percent *
  1550. * *
  1551. * INPUT: *
  1552. * percent percentage to build base to *
  1553. * *
  1554. * OUTPUT: *
  1555. * none. *
  1556. * *
  1557. * WARNINGS: *
  1558. * none. *
  1559. * *
  1560. * HISTORY: *
  1561. * 12/01/1994 BR : Created. *
  1562. *=========================================================================*/
  1563. void MapEditClass::Build_Base_To(int percent)
  1564. {
  1565. int i;
  1566. int num_buildings;
  1567. BuildingTypeClass const * objtype;
  1568. BuildingClass * obj;
  1569. //ScenarioInit++;
  1570. /*
  1571. ** Completely dismantle the base, so we start at a known point
  1572. */
  1573. for (i = 0; i < Base.Nodes.Count(); i++) {
  1574. if (Base.Is_Built(i)) {
  1575. obj = Base.Get_Building(i);
  1576. delete obj;
  1577. }
  1578. }
  1579. /*
  1580. ** Compute number of buildings to build
  1581. */
  1582. num_buildings = (Base.Nodes.Count() * percent) / 100;
  1583. /*
  1584. ** Build the base to the desired amount
  1585. */
  1586. for (i = 0; i < num_buildings; i++) {
  1587. /*
  1588. ** Get a ptr to the type of building to build, create one, and unlimbo it.
  1589. */
  1590. objtype = &BuildingTypeClass::As_Reference(Base.Nodes[i].Type);
  1591. obj = (BuildingClass *)objtype->Create_One_Of(HouseClass::As_Pointer(Base.House));
  1592. /*
  1593. ** If unlimbo fails, error out
  1594. */
  1595. ScenarioInit++;
  1596. if (!obj->Unlimbo(Cell_Coord(Base.Nodes[i].Cell))) {
  1597. delete obj;
  1598. WWMessageBox().Process("Unable to build base!");
  1599. ScenarioInit--;
  1600. return;
  1601. }
  1602. ScenarioInit--;
  1603. }
  1604. //ScenarioInit--;
  1605. }
  1606. #endif