EVENT.CPP 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050
  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/EVENT.CPP 1 3/03/97 10:24a 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 : EVENT.CPP *
  26. * *
  27. * Programmer : Joe L. Bostic *
  28. * *
  29. * Start Date : 12/09/94 *
  30. * *
  31. * Last Update : November 10, 1995 [BRR] *
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * Functions: *
  35. * EventClass::EventClass -- Construct an id and cell based event. *
  36. * EventClass::EventClass -- Construct simple target type event. *
  37. * EventClass::EventClass -- Constructor for mission change events. *
  38. * EventClass::EventClass -- Constructor for navigation computer events. *
  39. * EventClass::EventClass -- Constructor for object types affecting cells event. *
  40. * EventClass::EventClass -- Constructor for sidebar build events. *
  41. * EventClass::EventClass -- Constructs event to transfer special flags. *
  42. * EventClass::EventClass -- Default constructor for event objects. *
  43. * EventClass::EventClass -- Event for sequencing animations. *
  44. * EventClass::EventClass -- Megamission assigned to unit. *
  45. * EventClass::Execute -- Execute a queued command. *
  46. * EventClass::EventClass -- construct a variable-sized event *
  47. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  48. #include "function.h"
  49. #ifdef WIN32
  50. #include "ccdde.h"
  51. #endif //WIN32
  52. #ifdef FIXIT_VERSION_3 // Stalemate games.
  53. #include "WolStrng.h"
  54. #endif
  55. /***************************************************************************
  56. ** Table of what data is really used in the EventClass struct for different
  57. ** events. This table must be kept current with the EventType enum.
  58. */
  59. unsigned char EventClass::EventLength[EventClass::LAST_EVENT] = {
  60. 0, // EMPTY
  61. size_of(EventClass, Data.General ), // ALLY
  62. size_of(EventClass, Data.MegaMission ), // MEGAMISSION
  63. size_of(EventClass, Data.MegaMission_F ), // MEGAMISSION_F
  64. size_of(EventClass, Data.Target ), // IDLE
  65. size_of(EventClass, Data.Target ), // SCATTER
  66. 0, // DESTRUCT
  67. 0, // DEPLOY
  68. size_of(EventClass, Data.Place ), // PLACE
  69. 0, // OPTIONS
  70. size_of(EventClass, Data.General ), // GAMESPEED
  71. size_of(EventClass, Data.Specific ), // PRODUCE
  72. size_of(EventClass, Data.Specific.Type ), // SUSPEND
  73. size_of(EventClass, Data.Specific.Type ), // ABANDON
  74. size_of(EventClass, Data.Target ), // PRIMARY
  75. size_of(EventClass, Data.Special ), // SPECIAL_PLACE
  76. 0, // EXIT
  77. size_of(EventClass, Data.Anim ), // ANIMATION
  78. size_of(EventClass, Data.Target ), // REPAIR
  79. size_of(EventClass, Data.Target ), // SELL
  80. size_of(EventClass, Data.SellCell), // SELLCELL
  81. size_of(EventClass, Data.Options ), // SPECIAL
  82. 0, // FRAMESYNC
  83. 0, // MESSAGE
  84. size_of(EventClass, Data.FrameInfo.Delay ), // RESPONSE_TIME
  85. size_of(EventClass, Data.FrameInfo ), // FRAMEINFO
  86. 0, // SAVEGAME
  87. size_of(EventClass, Data.NavCom ), // ARCHIVE
  88. size_of(EventClass, Data.Variable.Size), // ADDPLAYER
  89. size_of(EventClass, Data.Timing ), // TIMING
  90. size_of(EventClass, Data.ProcessTime ), // PROCESS_TIME
  91. #ifdef FIXIT_VERSION_3 // Stalemate games.
  92. 0, // PROPOSE_DRAW
  93. 0, // RETRACT_DRAW
  94. #endif
  95. };
  96. char * EventClass::EventNames[EventClass::LAST_EVENT] = {
  97. "EMPTY",
  98. "ALLY",
  99. "MEGAMISSION",
  100. "MEGAMISSION_F",
  101. "IDLE",
  102. "SCATTER",
  103. "DESTRUCT",
  104. "DEPLOY",
  105. "PLACE",
  106. "OPTIONS",
  107. "GAMESPEED",
  108. "PRODUCE",
  109. "SUSPEND",
  110. "ABANDON",
  111. "PRIMARY",
  112. "SPECIAL_PLACE",
  113. "EXIT",
  114. "ANIMATION",
  115. "REPAIR",
  116. "SELL",
  117. "SELLCELL",
  118. "SPECIAL",
  119. "FRAMESYNC",
  120. "MESSAGE",
  121. "RESPONSE_TIME",
  122. "FRAMEINFO",
  123. "SAVEGAME",
  124. "ARCHIVE",
  125. "ADDPLAYER",
  126. "TIMING",
  127. "PROCESS_TIME",
  128. #ifdef FIXIT_VERSION_3 // Stalemate games.
  129. "PROPOSE_DRAW",
  130. "RETRACT_DRAW",
  131. #endif
  132. };
  133. /***********************************************************************************************
  134. * EventClass::EventClass -- Constructs event to transfer special flags. *
  135. * *
  136. * This constructs an event that will transfer the special flags. *
  137. * *
  138. * INPUT: data -- The special flags to be transported to all linked computers. *
  139. * *
  140. * OUTPUT: none *
  141. * *
  142. * WARNINGS: none *
  143. * *
  144. * HISTORY: *
  145. * 06/25/1995 JLB : Created. *
  146. *=============================================================================================*/
  147. EventClass::EventClass(SpecialClass data)
  148. {
  149. ID = PlayerPtr->ID;
  150. Type = SPECIAL;
  151. Frame = ::Frame;
  152. Data.Options.Data = data;
  153. }
  154. /***********************************************************************************************
  155. * EventClass::EventClass -- Construct simple target type event. *
  156. * *
  157. * This will construct a generic event that needs only a target parameter. The actual *
  158. * event and target values are specified as parameters. *
  159. * *
  160. * INPUT: type -- The event type to construct. *
  161. * *
  162. * target-- The target value that this event is to apply to. *
  163. * *
  164. * OUTPUT: none *
  165. * *
  166. * WARNINGS: none *
  167. * *
  168. * HISTORY: *
  169. * 06/25/1995 JLB : Created. *
  170. *=============================================================================================*/
  171. EventClass::EventClass(EventType type, TargetClass target)
  172. {
  173. ID = PlayerPtr->ID;
  174. Type = type;
  175. Frame = ::Frame;
  176. Data.Target.Whom = target;
  177. }
  178. EventClass::EventClass(EventType type, CELL cell)
  179. {
  180. ID = PlayerPtr->ID;
  181. Type = type;
  182. Frame = ::Frame;
  183. Data.SellCell.Cell = cell;
  184. }
  185. /***********************************************************************************************
  186. * EventClass::EventClass -- Default constructor for event objects. *
  187. * *
  188. * This constructs a simple event object that requires no parameters other than the *
  189. * type of event it is. *
  190. * *
  191. * INPUT: type -- The type of event to construct. *
  192. * *
  193. * OUTPUT: none *
  194. * *
  195. * WARNINGS: none *
  196. * *
  197. * HISTORY: *
  198. * 12/27/1994 JLB : Created. *
  199. *=============================================================================================*/
  200. EventClass::EventClass(EventType type)
  201. {
  202. ID = PlayerPtr->ID;
  203. Type = type;
  204. Frame = ::Frame;
  205. }
  206. /***********************************************************************************************
  207. * EventClass::EventClass -- Constructor for general-purpose-data events. *
  208. * *
  209. * INPUT: type -- The type of event to construct. *
  210. * val -- data value *
  211. * *
  212. * OUTPUT: none *
  213. * *
  214. * WARNINGS: none *
  215. * *
  216. * HISTORY: *
  217. * 12/27/1994 JLB : Created. *
  218. *=============================================================================================*/
  219. EventClass::EventClass(EventType type, int val)
  220. {
  221. ID = PlayerPtr->ID;
  222. Type = type;
  223. Data.General.Value = val;
  224. Frame = ::Frame;
  225. }
  226. /***********************************************************************************************
  227. * EventClass::EventClass -- Constructor for navigation computer events. *
  228. * *
  229. * Constructor for events that are used to assign the navigation computer. *
  230. * *
  231. * INPUT: type -- The type of event (this constructor can be used by other navigation *
  232. * type events). *
  233. * *
  234. * src -- The object that the event should apply to. *
  235. * *
  236. * dest -- The destination (or target) that the event needs to complete. *
  237. * *
  238. * OUTPUT: none *
  239. * *
  240. * WARNINGS: none *
  241. * *
  242. * HISTORY: *
  243. * 12/27/1994 JLB : Created. *
  244. *=============================================================================================*/
  245. EventClass::EventClass(EventType type, TargetClass src, TargetClass dest)
  246. {
  247. ID = PlayerPtr->ID;
  248. Type = type;
  249. Frame = ::Frame;
  250. Data.NavCom.Whom = src;
  251. Data.NavCom.Where = TargetClass(dest);
  252. }
  253. /***********************************************************************************************
  254. * EventClass::EventClass -- Event for sequencing animations. *
  255. * *
  256. * This constructor is used for animations that must be created through the event system. *
  257. * *
  258. * INPUT: anim -- The animation that will be created. *
  259. * *
  260. * coord -- The location where the animation is to be created. *
  261. * *
  262. * OUTPUT: none *
  263. * *
  264. * WARNINGS: none *
  265. * *
  266. * HISTORY: *
  267. * 05/19/1995 JLB : Created. *
  268. *=============================================================================================*/
  269. EventClass::EventClass(AnimType anim, HousesType owner, COORDINATE coord)
  270. {
  271. ID = PlayerPtr->ID;
  272. Type = ANIMATION;
  273. Frame = ::Frame;
  274. Data.Anim.What = anim;
  275. Data.Anim.Owner = owner;
  276. Data.Anim.Where = coord;
  277. }
  278. /***********************************************************************************************
  279. * EventClass::EventClass -- Megamission assigned to unit. *
  280. * *
  281. * This is the event that is used to assign most missions to units. It combines both the *
  282. * mission and the target (navcom and tarcom). *
  283. * *
  284. * INPUT: src -- The object that this mission is to apply to. *
  285. * *
  286. * mission -- The mission to assign to this object. *
  287. * *
  288. * target -- The target to assign to this object's TarCom. *
  289. * *
  290. * destination -- The destination to assign to this object's NavCom. *
  291. * *
  292. * OUTPUT: none *
  293. * *
  294. * WARNINGS: none *
  295. * *
  296. * HISTORY: *
  297. * 05/18/1995 JLB : Created. *
  298. *=============================================================================================*/
  299. EventClass::EventClass(TargetClass src, MissionType mission, TargetClass target, TargetClass destination)
  300. {
  301. ID = PlayerPtr->ID;
  302. Type = MEGAMISSION;
  303. Frame = ::Frame;
  304. Data.MegaMission.Whom = src;
  305. Data.MegaMission.Mission = mission;
  306. Data.MegaMission.Target = target;
  307. Data.MegaMission.Destination = destination;
  308. }
  309. /***********************************************************************************************
  310. * EventClass::EventClass -- Megamission assigned to unit. *
  311. * *
  312. * This is the event that is used to assign most missions to units. It combines both the *
  313. * mission and the target (navcom and tarcom). This variation is used for formation moves. *
  314. * *
  315. * INPUT: src -- The object that this mission is to apply to. *
  316. * *
  317. * mission -- The mission to assign to this object. *
  318. * *
  319. * target -- The target to assign to this object's TarCom. *
  320. * *
  321. * destination -- The destination to assign to this object's NavCom. *
  322. * *
  323. * speed -- The formation override speed for this move. *
  324. * *
  325. * maxspeed -- The formation override maximum speed for this move. *
  326. * *
  327. * OUTPUT: none *
  328. * *
  329. * WARNINGS: none *
  330. * *
  331. * HISTORY: *
  332. * 05/18/1995 JLB : Created. *
  333. *=============================================================================================*/
  334. EventClass::EventClass(TargetClass src, MissionType mission, TargetClass target, TargetClass destination, SpeedType speed, MPHType maxspeed)
  335. {
  336. ID = PlayerPtr->ID;
  337. Type = MEGAMISSION_F;
  338. Frame = ::Frame;
  339. Data.MegaMission_F.Whom = src;
  340. Data.MegaMission_F.Mission = mission;
  341. Data.MegaMission_F.Target = TargetClass(target);
  342. Data.MegaMission_F.Destination = TargetClass(destination);
  343. Data.MegaMission_F.Speed = speed;
  344. Data.MegaMission_F.MaxSpeed = maxspeed;
  345. }
  346. /***********************************************************************************************
  347. * EventClass::EventClass -- Constructor for sidebar build events. *
  348. * *
  349. * This constructor is used for events that deal with an object type and an object ID. *
  350. * Typically, this is used exclusively by the sidebar. *
  351. * *
  352. * INPUT: type -- The event type of this object. *
  353. * *
  354. * object -- The object type number. *
  355. * *
  356. * id -- The object sub-type number. *
  357. * *
  358. * OUTPUT: none *
  359. * *
  360. * WARNINGS: none *
  361. * *
  362. * HISTORY: *
  363. * 05/18/1995 JLB : Created. *
  364. *=============================================================================================*/
  365. EventClass::EventClass(EventType type, RTTIType object, int id)
  366. {
  367. ID = PlayerPtr->ID;
  368. Type = type;
  369. Frame = ::Frame;
  370. Data.Specific.Type = object;
  371. Data.Specific.ID = id;
  372. }
  373. /***********************************************************************************************
  374. * EventClass::EventClass -- Constructor for object types affecting cells event. *
  375. * *
  376. * This constructor is used for those events that have an object type and associated cell. *
  377. * Typically, this is for building placement after construction has completed. *
  378. * *
  379. * INPUT: type -- The event type for this object. *
  380. * *
  381. * object -- The object type number (actual object is probably inferred from the *
  382. * sidebar data). *
  383. * *
  384. * cell -- The cell location where this event is to occur. *
  385. * *
  386. * OUTPUT: none *
  387. * *
  388. * WARNINGS: none *
  389. * *
  390. * HISTORY: *
  391. * 05/18/1995 JLB : Created. *
  392. *=============================================================================================*/
  393. EventClass::EventClass(EventType type, RTTIType object, CELL cell)
  394. {
  395. ID = PlayerPtr->ID;
  396. Type = type;
  397. Frame = ::Frame;
  398. Data.Place.Type = object;
  399. Data.Place.Cell = cell;
  400. }
  401. /***********************************************************************************************
  402. * EventClass::EventClass -- Construct an id and cell based event. *
  403. * *
  404. * This constructor is used for those events that require an ID number and a cell location. *
  405. * *
  406. * INPUT: type -- The event type this will be. *
  407. * *
  408. * id -- The arbitrary id number to assign. *
  409. * *
  410. * cell -- The location for this event. *
  411. * *
  412. * OUTPUT: none *
  413. * *
  414. * WARNINGS: none *
  415. * *
  416. * HISTORY: *
  417. * 05/18/1995 JLB : Created. *
  418. *=============================================================================================*/
  419. EventClass::EventClass(EventType type, int id, CELL cell)
  420. {
  421. ID = PlayerPtr->ID;
  422. Type = type;
  423. Frame = ::Frame;
  424. Data.Special.ID = id;
  425. Data.Special.Cell = cell;
  426. }
  427. /***********************************************************************************************
  428. * EventClass::EventClass -- construct a variable-sized event *
  429. * *
  430. * INPUT: *
  431. * ptr ptr to data associated with this event *
  432. * *
  433. * OUTPUT: *
  434. * none. *
  435. * *
  436. * WARNINGS: *
  437. * none. *
  438. * *
  439. * HISTORY: *
  440. * 11/10/1995 BRR : Created. *
  441. *=============================================================================================*/
  442. EventClass::EventClass(EventType type, void * ptr, unsigned long size)
  443. {
  444. ID = PlayerPtr->ID;
  445. Type = type;
  446. Frame = ::Frame;
  447. Data.Variable.Pointer = ptr;
  448. Data.Variable.Size = size;
  449. }
  450. /***********************************************************************************************
  451. * EventClass::Execute -- Execute a queued command. *
  452. * *
  453. * This routine executes an event. The even must already have been confirmed by any *
  454. * remote machine before calling this routine. *
  455. * *
  456. * INPUT: none *
  457. * *
  458. * OUTPUT: none *
  459. * *
  460. * WARNINGS: none *
  461. * *
  462. * HISTORY: *
  463. * 12/27/1994 JLB : Created. *
  464. *=============================================================================================*/
  465. void EventClass::Execute(void)
  466. {
  467. TechnoClass * techno;
  468. AnimClass * anim = 0;
  469. HouseClass * house = 0;
  470. // CELL cell = 0;
  471. char txt[80];
  472. bool formation = false;
  473. // RTTIType rt;
  474. if (Debug_Print_Events) {
  475. printf("(%d) Executing %s ID:%d Frame:%d ",
  476. ::Frame, EventNames[Type], ID, Frame);
  477. }
  478. switch (Type) {
  479. /*
  480. ** Update the archive target for this building.
  481. */
  482. case ARCHIVE:
  483. techno = Data.NavCom.Whom.As_Techno();
  484. if (techno && techno->IsActive) {
  485. techno->ArchiveTarget = Data.NavCom.Where;
  486. }
  487. break;
  488. /*
  489. ** Make or break alliance.
  490. */
  491. case ALLY:
  492. house = Houses.Raw_Ptr(Data.General.Value);
  493. if (Houses.Raw_Ptr(ID)->Is_Ally(house)) {
  494. Houses.Raw_Ptr(ID)->Make_Enemy((HousesType)Data.General.Value);
  495. } else {
  496. Houses.Raw_Ptr(ID)->Make_Ally((HousesType)Data.General.Value);
  497. }
  498. break;
  499. /*
  500. ** Special self destruct action requested. This is active in the multiplayer mode.
  501. */
  502. case DESTRUCT:
  503. Houses.Raw_Ptr(ID)->Flag_To_Die();
  504. break;
  505. /*
  506. ** Update the special control flags. This is necessary so that in a multiplay
  507. ** game, all machines will agree on the rules. If these options change during
  508. ** game play, then all players are informed that options have changed.
  509. */
  510. case SPECIAL:
  511. {
  512. Special = Data.Options.Data;
  513. HouseClass * house = Houses.Raw_Ptr(ID);
  514. sprintf(txt, Text_String(TXT_SPECIAL_WARNING), house->Name);
  515. Session.Messages.Add_Message(NULL, 0, txt,
  516. house->RemapColor,
  517. TPF_6PT_GRAD|TPF_USE_GRAD_PAL|TPF_FULLSHADOW, 1200);
  518. Map.Flag_To_Redraw(false);
  519. }
  520. break;
  521. /*
  522. ** Starts or stops repair on the specified object. This event is triggered by the
  523. ** player clicking the repair wrench on a building.
  524. */
  525. case REPAIR:
  526. techno = Data.Target.Whom.As_Techno();
  527. if (techno && techno->IsActive) {
  528. techno->Repair(-1);
  529. }
  530. break;
  531. /*
  532. ** Tells a building/unit to sell. This event is triggered by the player clicking the
  533. ** sell animating cursor over the building or unit.
  534. */
  535. case SELL:
  536. techno = Data.Target.Whom.As_Techno();
  537. if (techno && techno->IsActive && techno->House == Houses.Raw_Ptr(ID)) {
  538. if (techno->What_Am_I() == RTTI_BUILDING || (techno->What_Am_I() == RTTI_UNIT && Map[techno->Center_Coord()].Cell_Building() != 0)) {
  539. techno->Sell_Back(-1);
  540. }
  541. } else {
  542. // if (Is_Target_Cell(Data.Target.Whom)) {
  543. // Houses.Raw_Ptr(ID)->Sell_Wall(As_Cell(Data.Target.Whom));
  544. // }
  545. }
  546. break;
  547. /*
  548. ** Tells the wall at the specified location to sell off.
  549. */
  550. case SELLCELL:
  551. // cell = Data.SellCell.Cell;
  552. Houses.Raw_Ptr(ID)->Sell_Wall(Data.SellCell.Cell);
  553. break;
  554. /*
  555. ** This even is used to trigger an animation that is generated as a direct
  556. ** result of player intervention.
  557. */
  558. case ANIMATION:
  559. anim = new AnimClass(Data.Anim.What, Data.Anim.Where);
  560. if (anim) {
  561. if (Data.Anim.Owner != HOUSE_NONE && PlayerPtr->Class->House != Data.Anim.Owner) {
  562. anim->Make_Invisible();
  563. }
  564. }
  565. break;
  566. /*
  567. ** This event will place the specified object at the specified location.
  568. ** The event is used to place newly constructed buildings down on the map. The
  569. ** object type is specified. From this object type, the house can determine the
  570. ** exact factory and real object pointer to use.
  571. */
  572. case PLACE:
  573. Houses.Raw_Ptr(ID)->Place_Object(Data.Place.Type, Data.Place.Cell);
  574. break;
  575. /*
  576. ** This event starts production of the specified object type. The house can
  577. ** determine from the type and ID value, what object to begin production on and
  578. ** what factory to use.
  579. */
  580. case PRODUCE:
  581. Houses.Raw_Ptr(ID)->Begin_Production(Data.Specific.Type, Data.Specific.ID);
  582. break;
  583. /*
  584. ** This event is generated when the player puts production on hold. From the
  585. ** object type, the factory can be inferred.
  586. */
  587. case SUSPEND:
  588. Houses.Raw_Ptr(ID)->Suspend_Production(Data.Specific.Type);
  589. break;
  590. /*
  591. ** This event is generated when the player cancels production of the specified
  592. ** object type. From the object type, the exact factory can be inferred.
  593. */
  594. case ABANDON:
  595. Houses.Raw_Ptr(ID)->Abandon_Production(Data.Specific.Type);
  596. break;
  597. /*
  598. ** Toggles the primary factory state of the specified building.
  599. */
  600. case PRIMARY:
  601. {
  602. BuildingClass * building = Data.Target.Whom.As_Building();
  603. if (building && building->IsActive) {
  604. building->Toggle_Primary();
  605. }
  606. }
  607. break;
  608. /*
  609. ** This is the general purpose mission control event. Most player
  610. ** action routes through this event. It sets a unit's mission, TarCom,
  611. ** and NavCom to the values specified.
  612. */
  613. case MEGAMISSION_F:
  614. techno = Data.MegaMission_F.Whom.As_Techno();
  615. if (techno && techno->IsActive && techno->Is_Foot()) {
  616. ((FootClass *)techno)->IsFormationMove = true;
  617. ((FootClass *)techno)->FormationSpeed = Data.MegaMission_F.Speed;
  618. ((FootClass *)techno)->FormationMaxSpeed = Data.MegaMission_F.MaxSpeed;
  619. FormMove = true;
  620. FormSpeed = Data.MegaMission_F.Speed;
  621. FormMaxSpeed = Data.MegaMission_F.MaxSpeed;
  622. formation = true;
  623. }
  624. // Fall thru to next case...
  625. case MEGAMISSION:
  626. if (Debug_Print_Events) {
  627. printf("Whom:%x Tgt:%x Dest:%x ",
  628. Data.MegaMission.Whom.As_TARGET(),
  629. Data.MegaMission.Target.As_TARGET(),
  630. Data.MegaMission.Destination.As_TARGET());
  631. }
  632. techno = Data.MegaMission.Whom.As_Techno();
  633. if (techno != NULL && techno->IsActive && techno->Strength > 0 && !techno->IsInLimbo) {
  634. /*
  635. ** Fetch a pointer to the object of the mission. If there is an error with
  636. ** this object, such as it is dead, then bail.
  637. */
  638. ObjectClass * object = NULL;
  639. if (Data.MegaMission.Target.Is_Valid()) {
  640. object = Data.MegaMission.Target.As_Object();
  641. if (object != NULL && (!object->IsActive || object->Strength == 0 || object->IsInLimbo)) {
  642. break;
  643. // object = NULL;
  644. // Data.MegaMission.Target.Invalidate();
  645. }
  646. }
  647. /*
  648. ** If the destination target is invalid because the object is dead, then
  649. ** bail from processing this mega mission.
  650. */
  651. if (Data.MegaMission.Destination.Is_Valid()) {
  652. object = Data.MegaMission.Destination.As_Object();
  653. if (object != NULL && (!object->IsActive || object->Strength == 0 || object->IsInLimbo)) {
  654. break;
  655. // object = NULL;
  656. // Data.MegaMission.Destination.Invalidate();
  657. }
  658. }
  659. /*
  660. ** Break any existing tether or team contact, since it is now invalid.
  661. */
  662. if (!techno->IsTethered) {
  663. techno->Transmit_Message(RADIO_OVER_OUT);
  664. }
  665. if (techno->Is_Foot()) {
  666. if (!formation) ((FootClass *)techno)->IsFormationMove = false;
  667. if (((FootClass *)techno)->Team) {
  668. ((FootClass *)techno)->Team->Remove((FootClass *)techno);
  669. }
  670. }
  671. if (object != NULL) {
  672. if (PlayerPtr->Is_Ally(techno)) {
  673. object->Clicked_As_Target();
  674. }
  675. }
  676. /*
  677. ** Test to see if the navigation target should really be queued rather
  678. ** than assigned to the object. This would be the case if this is a
  679. ** special queued move mission and there is already a valid navigation
  680. ** target for this unit.
  681. */
  682. bool q = (Data.MegaMission.Mission == MISSION_QMOVE);
  683. techno->Assign_Mission(Data.MegaMission.Mission);
  684. if (techno->Is_Foot()) {
  685. ((FootClass*)techno)->SuspendedNavCom = TARGET_NONE;
  686. }
  687. techno->SuspendedTarCom = TARGET_NONE;
  688. /*
  689. ** Guard area mode is handled with care. The specified target is actually
  690. ** assigned as the location that should be guarded. In addition, the
  691. ** movement destination is immediately set to this new location.
  692. */
  693. if (Data.MegaMission.Mission == MISSION_GUARD_AREA && techno->Is_Foot()) {
  694. techno->Assign_Target(TARGET_NONE);
  695. techno->Assign_Destination(Data.MegaMission.Target.As_TARGET());
  696. techno->ArchiveTarget = Data.MegaMission.Target.As_TARGET();
  697. } else {
  698. if (q && techno->Is_Foot()) {
  699. ((FootClass *)techno)->Queue_Navigation_List(Data.MegaMission.Destination.As_TARGET());
  700. } else {
  701. if (techno->Is_Foot()) {
  702. ((FootClass *)techno)->Clear_Navigation_List();
  703. }
  704. techno->Assign_Target(Data.MegaMission.Target.As_TARGET());
  705. techno->Assign_Destination(Data.MegaMission.Destination.As_TARGET());
  706. }
  707. }
  708. //
  709. // Special case for ship repairing: If the assigned mission is to
  710. // move, and 'techno' is a Vessel:
  711. // If the destination is a shipyard or sub pen, set the IsToSelfRepair flag
  712. // Otherwise, clear both IsToSelfRepair and IsSelfRepairing
  713. //
  714. RTTIType rt = techno->What_Am_I();
  715. // rt = Data.MegaMission.Whom;
  716. if (rt == RTTI_VESSEL && techno != NULL && techno->What_Am_I() == RTTI_VESSEL && Data.MegaMission.Mission == MISSION_MOVE) {
  717. VesselClass *ship = (VesselClass *)techno;
  718. if (object != NULL) {
  719. if (object->What_Am_I() == RTTI_BUILDING &&
  720. // if ((RTTIType)Data.MegaMission.Destination == RTTI_BUILDING &&
  721. (((BuildingClass *)object)->Class->Type == STRUCT_SHIP_YARD ||
  722. ((BuildingClass *)object)->Class->Type == STRUCT_SUB_PEN)) {
  723. ship->IsToSelfRepair = true;
  724. } else {
  725. ship->IsToSelfRepair = false;
  726. ship->IsSelfRepairing = false;
  727. }
  728. } else {
  729. ship->IsToSelfRepair = false;
  730. ship->IsSelfRepairing = false;
  731. }
  732. }
  733. #ifdef NEVER
  734. if ((techno->What_Am_I() == RTTI_UNIT || techno->What_Am_I() == RTTI_INFANTRY) &&
  735. Data.MegaMission.Mission == MISSION_GUARD_AREA) {
  736. ((FootClass *)techno)->ArchiveTarget = Data.MegaMission.Destination;
  737. }
  738. #endif
  739. }
  740. break;
  741. /*
  742. ** Request that the unit/infantry/aircraft go into idle mode.
  743. */
  744. case IDLE:
  745. techno = Data.Target.Whom.As_Techno();
  746. if (techno != NULL && techno->IsActive && !techno->IsInLimbo && !techno->IsTethered && techno->What_Am_I() != RTTI_BUILDING) {
  747. techno->Transmit_Message(RADIO_OVER_OUT);
  748. techno->Assign_Destination(TARGET_NONE);
  749. techno->Assign_Target(TARGET_NONE);
  750. techno->Enter_Idle_Mode();
  751. if (techno->Is_Foot()) {
  752. ((FootClass *)techno)->Clear_Navigation_List();
  753. }
  754. }
  755. break;
  756. /*
  757. ** Request that the unit/infantry/aircraft scatter from its current location.
  758. */
  759. case SCATTER:
  760. techno = Data.Target.Whom.As_Techno();
  761. if (techno != NULL && techno->Is_Foot() && techno->IsActive && !techno->IsInLimbo && !techno->IsTethered) {
  762. ((FootClass *)techno)->IsScattering = true;
  763. techno->Scatter(0, true, false);
  764. }
  765. break;
  766. /*
  767. ** If we are placing down the ion cannon blast then lets take
  768. ** care of it.
  769. */
  770. case SPECIAL_PLACE:
  771. Houses.Raw_Ptr(ID)->Place_Special_Blast((SpecialWeaponType)Data.Special.ID, Data.Special.Cell);
  772. break;
  773. /*
  774. ** Exit the game.
  775. ** Give parting message while palette is fading to black.
  776. */
  777. case EXIT:
  778. Theme.Queue_Song(THEME_NONE);
  779. Stop_Speaking();
  780. Speak(VOX_CONTROL_EXIT);
  781. while (Is_Speaking()) {
  782. Call_Back();
  783. }
  784. GameActive = false;
  785. break;
  786. /*
  787. ** Process the options menu, unless we're playing back a recording.
  788. */
  789. case OPTIONS:
  790. if (!Session.Play) {
  791. SpecialDialog = SDLG_OPTIONS;
  792. }
  793. break;
  794. /*
  795. ** Process the options Game Speed
  796. */
  797. case GAMESPEED:
  798. Options.GameSpeed = Data.General.Value;
  799. break;
  800. /*
  801. ** Adjust connection timing for multiplayer games
  802. */
  803. case RESPONSE_TIME:
  804. Session.MaxAhead = Data.FrameInfo.Delay;
  805. break;
  806. /*
  807. ** Save a multiplayer game (this event is only generated in multiplayer mode)
  808. */
  809. case SAVEGAME:
  810. /*
  811. ** Show the user what's going on with a message box (but only if
  812. ** we're not already inside a dialog box routine!)
  813. */
  814. if (SpecialDialog == SDLG_NONE) {
  815. CDTimerClass<SystemTimerClass> timer;
  816. //timer.Start();
  817. timer = TICKS_PER_SECOND * 4;
  818. WWMessageBox().Process(TXT_SAVING_GAME, TXT_NONE);
  819. Save_Game (-1, (char *)Text_String(TXT_MULTIPLAYER_GAME));
  820. while (timer > 0) {
  821. Call_Back();
  822. }
  823. HidPage.Clear();
  824. Map.Flag_To_Redraw(true);
  825. Map.Render();
  826. }
  827. else {
  828. Save_Game (-1, (char *)Text_String(TXT_MULTIPLAYER_GAME));
  829. }
  830. break;
  831. /*
  832. ** Add a new player to the game:
  833. ** - Form a network connection to him
  834. ** - Add his name, ID, House etc to our list of players
  835. ** - Re-sort the ID array
  836. ** - Place his units on the map
  837. */
  838. case ADDPLAYER:
  839. int i;
  840. printf("ADDPLAYER EVENT!\n");
  841. for (i=0;i<Data.Variable.Size;i++) {
  842. printf("%d\n", ((char *)Data.Variable.Pointer)[i]);
  843. }
  844. if (ID != PlayerPtr->ID) {
  845. delete [] Data.Variable.Pointer;
  846. }
  847. break;
  848. //
  849. // This event tells all systems to use new timing values. It's like
  850. // RESPONSE_TIME, only it works. It's only used with the
  851. // COMM_MULTI_E_COMP protocol.
  852. //
  853. case TIMING:
  854. #if(TIMING_FIX)
  855. //
  856. // If MaxAhead is about to increase, we're vulnerable to a Packet-
  857. // Received-Too-Late error, if any system generates an event after
  858. // this TIMING event, but before it executes. So, record the
  859. // period of vulnerability's frame start & end values, so we
  860. // can reschedule these events to execute after it's over.
  861. //
  862. if (Data.Timing.MaxAhead > Session.MaxAhead) {
  863. NewMaxAheadFrame1 = Frame;
  864. NewMaxAheadFrame2 = Frame + Data.Timing.MaxAhead;
  865. }
  866. #endif
  867. Session.DesiredFrameRate = Data.Timing.DesiredFrameRate;
  868. Session.MaxAhead = Data.Timing.MaxAhead;
  869. #ifndef WOLAPI_INTEGRATION
  870. /*
  871. ** If spawned from WChat then we should be getting poked every minute. If not then
  872. ** deliberately break the max ahead value
  873. */
  874. #ifdef WIN32
  875. if (Special.IsFromWChat) {
  876. Session.MaxAhead += DDEServer.Time_Since_Heartbeat()/(70*60);
  877. }
  878. #endif //WIN32
  879. #endif // !WOLAPI_INTEGRATION
  880. if (Debug_Print_Events) {
  881. printf("DesiredFrameRate:%d MaxAhead:%d ",
  882. Session.DesiredFrameRate,
  883. Session.MaxAhead);
  884. }
  885. break;
  886. //
  887. // This event tells all systems what the other systems' process
  888. // timing requirements are; it's used to compute a desired frame rate
  889. // for the game.
  890. //
  891. case PROCESS_TIME:
  892. for (i = 0; i < Session.Players.Count(); i++) {
  893. if (ID == Session.Players[i]->Player.ID) {
  894. Session.Players[i]->Player.ProcessTime = Data.ProcessTime.AverageTicks;
  895. break;
  896. }
  897. }
  898. break;
  899. #ifdef FIXIT_VERSION_3 // Stalemate games.
  900. case PROPOSE_DRAW:
  901. if( ID == PlayerPtr->ID )
  902. {
  903. if( Scen.bOtherProposesDraw )
  904. {
  905. // Both sides agree to draw. Game will end in a tie.
  906. Scen.bLocalProposesDraw = true;
  907. break;
  908. }
  909. Scen.bLocalProposesDraw = true;
  910. Session.Messages.Add_Message( NULL, 0, TXT_WOL_DRAW_PROPOSED_LOCAL, PCOLOR_GOLD, TPF_6PT_GRAD|TPF_USE_GRAD_PAL|TPF_FULLSHADOW, Rule.MessageDelay * TICKS_PER_MINUTE );
  911. }
  912. else
  913. {
  914. if( Scen.bLocalProposesDraw )
  915. {
  916. // Both sides agree to draw. Game will end in a tie.
  917. Scen.bOtherProposesDraw = true;
  918. break;
  919. }
  920. char szMessage[ 100 ];
  921. for (i = 0; i < Session.Players.Count(); i++)
  922. {
  923. if (ID == Session.Players[i]->Player.ID)
  924. {
  925. sprintf( szMessage, TXT_WOL_DRAW_PROPOSED_OTHER, Session.Players[i]->Name );
  926. break;
  927. }
  928. }
  929. Scen.bOtherProposesDraw = true;
  930. Session.Messages.Add_Message( NULL, 0, szMessage, PCOLOR_GOLD, TPF_6PT_GRAD|TPF_USE_GRAD_PAL|TPF_FULLSHADOW, Rule.MessageDelay * TICKS_PER_MINUTE );
  931. }
  932. Sound_Effect( VOC_INCOMING_MESSAGE );
  933. break;
  934. case RETRACT_DRAW:
  935. if( ID == PlayerPtr->ID )
  936. {
  937. Scen.bLocalProposesDraw = false;
  938. Session.Messages.Add_Message( NULL, 0, TXT_WOL_DRAW_RETRACTED_LOCAL, PCOLOR_GOLD, TPF_6PT_GRAD|TPF_USE_GRAD_PAL|TPF_FULLSHADOW, Rule.MessageDelay * TICKS_PER_MINUTE );
  939. }
  940. else
  941. {
  942. char szMessage[ 100 ];
  943. for (i = 0; i < Session.Players.Count(); i++)
  944. {
  945. if (ID == Session.Players[i]->Player.ID)
  946. {
  947. sprintf( szMessage, TXT_WOL_DRAW_RETRACTED_OTHER, Session.Players[i]->Name );
  948. break;
  949. }
  950. }
  951. Scen.bOtherProposesDraw = false;
  952. Session.Messages.Add_Message( NULL, 0, szMessage, PCOLOR_GOLD, TPF_6PT_GRAD|TPF_USE_GRAD_PAL|TPF_FULLSHADOW, Rule.MessageDelay * TICKS_PER_MINUTE );
  953. }
  954. Sound_Effect( VOC_INCOMING_MESSAGE );
  955. break;
  956. #endif
  957. /*
  958. ** Default: do nothing.
  959. */
  960. default:
  961. break;
  962. }
  963. if (Debug_Print_Events) {
  964. printf("\n");
  965. }
  966. }