MAPEDPLC.CPP 58 KB

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