EVENT.CPP 47 KB

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