vendor.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. /*
  2. ** Command & Conquer Renegade(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. /***********************************************************************************************
  19. *** 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 ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Commmando *
  23. * *
  24. * $Archive:: /Commando/Code/Commando/vendor.cpp $*
  25. * *
  26. * Author:: Patrick Smith *
  27. * *
  28. * $Modtime:: 1/28/02 11:17a $*
  29. * *
  30. * $Revision:: 23 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "vendor.h"
  36. #include "gameobjmanager.h"
  37. #include "playerdata.h"
  38. #include "soldier.h"
  39. #include "playertype.h"
  40. #include "combat.h"
  41. #include "powerup.h"
  42. #include "refinerygameobj.h"
  43. #include "vehiclefactorygameobj.h"
  44. #include "definitionmgr.h"
  45. #include "vehicle.h"
  46. #include "combatchunkid.h"
  47. #include "cnetwork.h"
  48. #include "purchaserequestevent.h"
  49. #include "purchasesettings.h"
  50. #include "teampurchasesettings.h"
  51. #include "weaponbag.h"
  52. #include "weapons.h"
  53. #include "purchaseresponseevent.h"
  54. ////////////////////////////////////////////////////////////////
  55. // Namespaces
  56. ////////////////////////////////////////////////////////////////
  57. using namespace BuildingConstants;
  58. ////////////////////////////////////////////////////////////////
  59. //
  60. // Purchase_Vehicle
  61. //
  62. ////////////////////////////////////////////////////////////////
  63. VendorClass::PURCHASE_ERROR
  64. VendorClass::Purchase_Vehicle
  65. (
  66. BaseControllerClass * base,
  67. SoldierGameObj * player,
  68. int cost,
  69. int vehicle_id
  70. )
  71. {
  72. PURCHASE_ERROR retval = PERR_NOT_IN_STOCK;
  73. //
  74. // Check to see if this vehicle is available to build
  75. //
  76. VehicleGameObjDef *definition = NULL;
  77. definition = (VehicleGameObjDef *)DefinitionMgrClass::Find_Definition (vehicle_id);
  78. if (definition != NULL) {
  79. PlayerDataClass *player_data = NULL;
  80. bool has_funds = true;
  81. //
  82. // Check to see if the player has sufficient funds to purchase the vehicle
  83. //
  84. if (player != NULL && player->Get_Player_Data () != NULL) {
  85. player_data = player->Get_Player_Data ();
  86. has_funds = (player_data->Get_Money () >= cost);
  87. }
  88. if (has_funds) {
  89. retval = PERR_NO_FACTORY;
  90. //
  91. // Find our vehicle factory
  92. //
  93. BuildingGameObj *building = base->Find_Building (TYPE_VEHICLE_FACTORY);
  94. if (building != NULL) {
  95. VehicleFactoryGameObj *factory = building->As_VehicleFactoryGameObj ();
  96. //
  97. // If we have a vehicle factory that isn't busy, then start building the vehicle
  98. //
  99. if (factory->Is_Available ()) {
  100. float time = 5.0F * base->Get_Operation_Time_Factor ();
  101. factory->Request_Vehicle (vehicle_id, time, player);
  102. retval = PERR_SUCCESS;
  103. //
  104. // If a player is purcahsing the vehicle, then debit
  105. // the player's account
  106. //
  107. if (player_data != NULL) {
  108. player_data->Purchase_Item (cost);
  109. }
  110. }
  111. }
  112. } else {
  113. retval = PERR_NO_FUNDS;
  114. }
  115. }
  116. return retval;
  117. }
  118. ////////////////////////////////////////////////////////////////
  119. //
  120. // Purchase_Powerup
  121. //
  122. ////////////////////////////////////////////////////////////////
  123. VendorClass::PURCHASE_ERROR
  124. VendorClass::Purchase_Powerup
  125. (
  126. BaseControllerClass * base,
  127. SoldierGameObj * player,
  128. int cost,
  129. int powerup_id
  130. )
  131. {
  132. PURCHASE_ERROR retval = PERR_NO_FUNDS;
  133. //
  134. // Sanity check
  135. //
  136. if (player == NULL) {
  137. return retval;
  138. }
  139. //
  140. // Lookup the powerup's definition
  141. //
  142. DefinitionClass *definition = DefinitionMgrClass::Find_Definition (powerup_id);
  143. if (definition != NULL && definition->Get_Class_ID () == CLASSID_GAME_OBJECT_DEF_POWERUP) {
  144. PowerUpGameObjDef *powerup_def = reinterpret_cast<PowerUpGameObjDef *> (definition);
  145. //
  146. // If a player is purcahsing the powerup, then debit
  147. // the player's account
  148. //
  149. bool has_funds = false;
  150. PlayerDataClass *player_data = player->Get_Player_Data ();
  151. if (player_data != NULL) {
  152. //
  153. // Try to purchase the powerup
  154. //
  155. has_funds = player_data->Purchase_Item (cost);
  156. }
  157. //
  158. // If the player has the cash, then grant him the powerup
  159. //
  160. if (has_funds) {
  161. powerup_def->Grant (player);
  162. retval = PERR_SUCCESS;
  163. }
  164. } else {
  165. retval = PERR_NOT_IN_STOCK;
  166. }
  167. return retval;
  168. }
  169. ////////////////////////////////////////////////////////////////
  170. //
  171. // Purchase_Character
  172. //
  173. ////////////////////////////////////////////////////////////////
  174. VendorClass::PURCHASE_ERROR
  175. VendorClass::Purchase_Character
  176. (
  177. BaseControllerClass * base,
  178. SoldierGameObj * player,
  179. int cost,
  180. int definition_id
  181. )
  182. {
  183. PURCHASE_ERROR retval = PERR_NO_FUNDS;
  184. //
  185. // Sanity check
  186. //
  187. if (player == NULL) {
  188. return retval;
  189. }
  190. //
  191. // Check to see if the player has sufficient funds to purchase the upgrade
  192. //
  193. PlayerDataClass *player_data = player->Get_Player_Data ();
  194. bool has_funds = (player_data->Get_Money () >= cost);
  195. if (has_funds) {
  196. retval = PERR_NO_FACTORY;
  197. //
  198. // Check to see if our soldier factory is operational
  199. //
  200. BuildingGameObj *building = base->Find_Building (TYPE_SOLDIER_FACTORY);
  201. if ((building != NULL && building->Is_Destroyed () == false) || cost == 0) {
  202. //
  203. // Lookup the new definition for the soldier
  204. //
  205. DefinitionClass *definition = DefinitionMgrClass::Find_Definition (definition_id);
  206. if (definition != NULL && definition->Get_Class_ID () == CLASSID_GAME_OBJECT_DEF_SOLDIER) {
  207. //
  208. // Upgrade the player
  209. //
  210. SoldierGameObjDef *soldier_def = reinterpret_cast<SoldierGameObjDef *> (definition);
  211. player->Re_Init (*soldier_def);
  212. player->Post_Re_Init();
  213. retval = PERR_SUCCESS;
  214. //
  215. // Debit the player's account
  216. //
  217. player_data->Purchase_Item (cost);
  218. }
  219. }
  220. }
  221. return retval;
  222. }
  223. ////////////////////////////////////////////////////////////////
  224. //
  225. // Purchase_Powerup
  226. //
  227. ////////////////////////////////////////////////////////////////
  228. VendorClass::PURCHASE_ERROR
  229. VendorClass::Purchase_Item
  230. (
  231. SoldierGameObj * player,
  232. PURCHASE_TYPE type,
  233. int item_index,
  234. int alt_skin_index,
  235. bool is_from_server
  236. )
  237. {
  238. PURCHASE_ERROR retval = PERR_NO_FUNDS;
  239. //
  240. // Sanity check
  241. //
  242. if (player == NULL) {
  243. return retval;
  244. }
  245. if (CombatManager::I_Am_Server () == false) {
  246. //
  247. // Request this purchase from the server
  248. //
  249. cPurchaseRequestEvent *purchase_request = new cPurchaseRequestEvent;
  250. purchase_request->Init (type, item_index, alt_skin_index);
  251. //
  252. // Let the user know the operation is pending
  253. //
  254. retval = PERR_OPERATION_PENDING;
  255. } else {
  256. //
  257. // Determine which base controller to purchase from
  258. //
  259. BaseControllerClass *base = NULL;
  260. if (player->Get_Player_Type () == PLAYERTYPE_NOD) {
  261. base = BaseControllerClass::Find_Base ( PLAYERTYPE_NOD );
  262. } else {
  263. base = BaseControllerClass::Find_Base ( PLAYERTYPE_GDI );
  264. }
  265. //
  266. // Lookup information about this purchase
  267. //
  268. int cost = 0;
  269. int definition_id = 0;
  270. Get_Merchandise_Information (player, type, item_index, alt_skin_index, cost, definition_id);
  271. //
  272. // Cost is doubled if the base isn't powered
  273. //
  274. //if (base != NULL && base->Is_Base_Powered () == false) {
  275. if (type != TYPE_BEACON && base != NULL && base->Is_Base_Powered () == false) {
  276. cost = cost * 2;
  277. }
  278. if (type == TYPE_CHARACTER || type == TYPE_ENLISTED_CHARACTER || type == TYPE_SECRET_CHARACTER) {
  279. //
  280. // Purchase the character
  281. //
  282. retval = Purchase_Character (base, player, cost, definition_id);
  283. } else if (type == TYPE_VEHICLE || type == TYPE_SECRET_VEHICLE) {
  284. //
  285. // Purchase the vehicle
  286. //
  287. retval = Purchase_Vehicle (base, player, cost, definition_id);
  288. } else if (type == TYPE_BEACON) {
  289. //
  290. // Purchase the beacon powerup
  291. //
  292. retval = Purchase_Powerup (base, player, cost, definition_id);
  293. } else if (type == TYPE_SUPPLY) {
  294. //
  295. // Grant full health, armor and ammo
  296. //
  297. Grant_Supplies (player);
  298. retval = PERR_SUCCESS;
  299. }
  300. //
  301. // Send the response to the server locally as necessary
  302. //
  303. if (is_from_server) {
  304. cPurchaseResponseEvent *event = new cPurchaseResponseEvent;
  305. event->Init ((int)retval, cNetwork::Get_My_Id ());
  306. }
  307. }
  308. return retval;
  309. }
  310. ////////////////////////////////////////////////////////////////
  311. //
  312. // Grant_Supplies
  313. //
  314. ////////////////////////////////////////////////////////////////
  315. void
  316. VendorClass::Grant_Supplies (SoldierGameObj *player)
  317. {
  318. //
  319. // Grant ammo
  320. //
  321. WeaponBagClass *weapon_bag = player->Get_Weapon_Bag ();
  322. for (int weapon_index = 0; weapon_index < weapon_bag->Get_Count (); weapon_index ++) {
  323. WeaponClass *weapon = weapon_bag->Peek_Weapon (weapon_index);
  324. if (weapon != NULL && weapon->Get_Definition ()->CanReceiveGenericCnCAmmo) {
  325. //
  326. // Restore full ammo
  327. //
  328. weapon->Set_Inventory_Rounds (weapon->Get_Definition ()->MaxInventoryRounds);
  329. weapon->Set_Clip_Rounds (weapon->Get_Definition ()->ClipSize);
  330. }
  331. }
  332. //
  333. // Grant full health and armor
  334. //
  335. DefenseObjectClass *defense_obj = player->Get_Defense_Object ();
  336. defense_obj->Set_Health (defense_obj->Get_Health_Max ());
  337. defense_obj->Set_Shield_Strength (defense_obj->Get_Shield_Strength_Max ());
  338. return ;
  339. }
  340. ////////////////////////////////////////////////////////////////
  341. //
  342. // Get_Merchandise_Information
  343. //
  344. ////////////////////////////////////////////////////////////////
  345. void
  346. VendorClass::Get_Merchandise_Information
  347. (
  348. SoldierGameObj * player,
  349. PURCHASE_TYPE type,
  350. int item_index,
  351. int alt_skin_index,
  352. int & cost,
  353. int & definition_id
  354. )
  355. {
  356. //
  357. // Determine which team to use...
  358. //
  359. PurchaseSettingsDefClass::TEAM team = PurchaseSettingsDefClass::TEAM_GDI;
  360. if (player->Get_Player_Type () == PLAYERTYPE_NOD) {
  361. team = PurchaseSettingsDefClass::TEAM_NOD;
  362. }
  363. //
  364. // Lookup the definition
  365. //
  366. if (type == TYPE_CHARACTER || type == TYPE_VEHICLE) {
  367. //
  368. // Determine which purchase type to use
  369. //
  370. PurchaseSettingsDefClass::TYPE purchase_type = PurchaseSettingsDefClass::TYPE_CLASSES;
  371. if (type == TYPE_VEHICLE) {
  372. purchase_type = PurchaseSettingsDefClass::TYPE_VEHICLES;
  373. }
  374. //
  375. // Lookup the information from this purchase definition
  376. //
  377. PurchaseSettingsDefClass *definition = PurchaseSettingsDefClass::Find_Definition (purchase_type, team);
  378. if (definition != NULL) {
  379. cost = definition->Get_Cost (item_index);
  380. //
  381. // Either get the default skin or the alternate skin
  382. //
  383. if (alt_skin_index != -1) {
  384. definition_id = definition->Get_Alt_Definition (item_index, alt_skin_index);
  385. } else {
  386. definition_id = definition->Get_Definition (item_index);
  387. }
  388. }
  389. } else if (type == TYPE_SECRET_CHARACTER || type == TYPE_SECRET_VEHICLE) {
  390. //
  391. // Only allow cheats in non-laddered games!
  392. //
  393. if (The_Game()->IsLaddered.Is_False()) {
  394. //
  395. // Determine which purchase type to use
  396. //
  397. PurchaseSettingsDefClass::TYPE purchase_type = PurchaseSettingsDefClass::TYPE_SECRET_CLASSES;
  398. if (type == TYPE_SECRET_VEHICLE) {
  399. purchase_type = PurchaseSettingsDefClass::TYPE_SECRET_VEHICLES;
  400. }
  401. //
  402. // Lookup the information from this purchase definition
  403. //
  404. PurchaseSettingsDefClass *definition = PurchaseSettingsDefClass::Find_Definition (purchase_type, team);
  405. if (definition != NULL) {
  406. cost = definition->Get_Cost (item_index);
  407. definition_id = definition->Get_Definition (item_index);
  408. }
  409. }
  410. } else if (type == TYPE_ENLISTED_CHARACTER) {
  411. //
  412. // For enlisted characters, lookup the team purchase definition
  413. //
  414. cost = 0;
  415. TeamPurchaseSettingsDefClass *definition = TeamPurchaseSettingsDefClass::Get_Definition ((TeamPurchaseSettingsDefClass::TEAM)team);
  416. if (definition != NULL) {
  417. definition_id = definition->Get_Enlisted_Definition (item_index);
  418. }
  419. } else if (type == TYPE_BEACON) {
  420. //
  421. // For beacons, lookup the team purchase definition
  422. //
  423. TeamPurchaseSettingsDefClass *definition = TeamPurchaseSettingsDefClass::Get_Definition ((TeamPurchaseSettingsDefClass::TEAM)team);
  424. if (definition != NULL) {
  425. cost = definition->Get_Beacon_Cost ();
  426. definition_id = definition->Get_Beacon_Definition ();
  427. }
  428. }
  429. return ;
  430. }