PPC_Convoys.inc 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720
  1. // This include file holds all functions for doing convoys
  2. forward Convoy_Timer(Convoy);
  3. // This function is called only once and is used to setup the textdraws and default data for convoys
  4. Convoys_Init()
  5. {
  6. for (new i; i < MAX_CONVOYS; i++)
  7. {
  8. AConvoys[i][ConvoyTextLeader] = TextDrawCreate(320.0, 1.0, " "); // Create the textdraw for the leader
  9. TextDrawSetShadow(AConvoys[i][ConvoyTextLeader], 1); // Reduce the shadow to 1
  10. TextDrawAlignment(AConvoys[i][ConvoyTextLeader], 2); // Align the convoy-infobar to the center for the leader
  11. TextDrawUseBox(AConvoys[i][ConvoyTextLeader], 1); // Set the missiontext to display inside a box
  12. TextDrawBoxColor(AConvoys[i][ConvoyTextLeader] ,0x00000066); // Set the box color of the missiontext
  13. AConvoys[i][ConvoyTextMember] = TextDrawCreate(320.0, 1.0, " "); // Create the textdraw for the members
  14. TextDrawSetShadow(AConvoys[i][ConvoyTextLeader], 1); // Reduce the shadow to 1
  15. TextDrawAlignment(AConvoys[i][ConvoyTextMember], 2); // Align the convoy-infobar to the center for the members
  16. TextDrawUseBox(AConvoys[i][ConvoyTextMember], 1); // Set the missiontext to display inside a box
  17. TextDrawBoxColor(AConvoys[i][ConvoyTextMember] ,0x00000066); // Set the box color of the missiontext
  18. }
  19. }
  20. // This function is used when a player selected an empty convoy-slot (the player will start the convoy and become the leader)
  21. Convoy_Create(playerid, Convoy)
  22. {
  23. // Setup local variables
  24. new Name[24], Msg[128];
  25. // Get the name of the player
  26. GetPlayerName(playerid, Name, sizeof(Name));
  27. // Check if the player is allowed to create a convoy (he must be a trucker without a job and not part of a convoy yet)
  28. if (Convoy_PlayerAllowed(playerid))
  29. {
  30. // Set status of the convoy to "open"
  31. AConvoys[Convoy][Status] = CONVOY_OPEN;
  32. // Set the player as leader of the convoy
  33. AConvoys[Convoy][Members][0] = playerid;
  34. // Set the player as a member of a convoy
  35. APlayerData[playerid][InConvoy] = true;
  36. APlayerData[playerid][ConvoyID] = Convoy;
  37. // Set all other member-indices to "-1" (no player yet)
  38. for (new i = 1; i < CONVOY_MAX_MEMBERS; i++)
  39. AConvoys[Convoy][Members][i] = -1;
  40. // Start the convoy-timer (this timer updates and checks everything for the whole convoy), it runs every second
  41. AConvoys[Convoy][ConvoyTimer] = SetTimerEx("Convoy_Timer", 1000, true, "i", Convoy);
  42. // Let all players know that this player wants to start a convoy
  43. format(Msg, 128, TXT_PlayerStartsConvoy, Name);
  44. SendClientMessageToAll(0xFFFFFFFF, Msg);
  45. }
  46. }
  47. // This function is used to let another player join a convoy
  48. Convoy_Join(playerid, Convoy)
  49. {
  50. // Setup local variables
  51. new Name[24], Msg[128];
  52. // Get the name of the player
  53. GetPlayerName(playerid, Name, sizeof(Name));
  54. // Check if the player is allowed to join the convoy (he must be a trucker without a job and not part of a convoy yet)
  55. if (Convoy_PlayerAllowed(playerid))
  56. {
  57. // Check if the convoy isn't full already
  58. if (Convoy_CountMembers(Convoy) < CONVOY_MAX_MEMBERS)
  59. {
  60. // Inform all the members of the convoy that this player joined the convoy
  61. format(Msg, 128, TXT_PlayerJoinedConvoy, Name);
  62. Convoy_SendMessage(Convoy, Msg);
  63. // Inform the player that he joined the convoy
  64. SendClientMessage(playerid, 0xFFFFFFFF, TXT_YouJoinedConvoy);
  65. // Set the player as member of the convoy (find a free spot for this player)
  66. for (new i; i < CONVOY_MAX_MEMBERS; i++)
  67. {
  68. if (AConvoys[Convoy][Members][i] == -1) // Check if this member-spot is empty
  69. {
  70. AConvoys[Convoy][Members][i] = playerid; // Put the player in this member-spot
  71. break; // Stop the for-loop
  72. }
  73. }
  74. // Set the player as a member of a convoy
  75. APlayerData[playerid][InConvoy] = true;
  76. APlayerData[playerid][ConvoyID] = Convoy;
  77. // Set the convoystatus as "Full" if all member-spots are occupied
  78. if (Convoy_CountMembers(Convoy) == CONVOY_MAX_MEMBERS)
  79. AConvoys[Convoy][Status] = CONVOY_FULL;
  80. // Also update the player's missiontext to inform the player that he must wait for the leader to start a job
  81. TextDrawSetString(APlayerData[playerid][MissionText], TXT_WaitingLeaderJob);
  82. }
  83. else
  84. SendClientMessage(playerid, 0xFFFFFFFF, TXT_ConvoyFull);
  85. }
  86. }
  87. // This function is used to let a player leave a convoy (when he disconnects, finishes the convoy, when he dies, ...)
  88. Convoy_Leave(playerid)
  89. {
  90. // Setup local variables
  91. new Convoy, NumMembers, MemberID;
  92. // First theck if the player is part of a convoy
  93. if (APlayerData[playerid][InConvoy] == false)
  94. return 1; // Exit the function if the player isn't part of a convoy
  95. // Get the convoy-id from the player
  96. Convoy = APlayerData[playerid][ConvoyID];
  97. // Get the number of members in the convoy
  98. NumMembers = Convoy_CountMembers(Convoy);
  99. // If there is only 1 member in the convoy (convoy will have no members if this one leaves), cancel the convoy
  100. if (NumMembers == 1)
  101. {
  102. // Cancel the convoy
  103. Convoy_Cancel(Convoy);
  104. // Exit the function
  105. return 1;
  106. }
  107. // Remove the player from the convoy
  108. APlayerData[playerid][InConvoy] = false;
  109. APlayerData[playerid][ConvoyID] = 0;
  110. // Hide both convoy-textdraws (for leader and members) as the member leaves the convoy
  111. TextDrawHideForPlayer(playerid, AConvoys[Convoy][ConvoyTextLeader]);
  112. TextDrawHideForPlayer(playerid, AConvoys[Convoy][ConvoyTextMember]);
  113. // Also update the player's missiontext to inform the player that he can start a job now (if there isn't a job started)
  114. if (APlayerData[playerid][JobStarted] == false)
  115. TextDrawSetString(APlayerData[playerid][MissionText], Trucker_NoJobText);
  116. // If the player is the leader
  117. if (AConvoys[Convoy][Members][0] == playerid)
  118. {
  119. // Set another player as leader
  120. for (new j = 1; j < CONVOY_MAX_MEMBERS; j++)
  121. {
  122. // Get the playerid of the member
  123. MemberID = AConvoys[Convoy][Members][j];
  124. if (MemberID != -1) // If a valid playerid is found
  125. {
  126. // Hide the member-textdraw as the member just became the leader
  127. TextDrawHideForPlayer(MemberID, AConvoys[Convoy][ConvoyTextMember]);
  128. // Set this member as leader
  129. AConvoys[Convoy][Members][0] = MemberID;
  130. // Clear this index, or the player would be twice in the same convoy
  131. AConvoys[Convoy][Members][j] = -1;
  132. // Exit the function
  133. return 1;
  134. }
  135. }
  136. }
  137. else // The leaving player isn't the leader
  138. {
  139. // Find the player inside the convoy
  140. for (new i = 1; i < CONVOY_MAX_MEMBERS; i++)
  141. {
  142. // If the current player is this player
  143. if (AConvoys[Convoy][Members][i] == playerid)
  144. {
  145. // Reset the stored playerid in the convoy
  146. AConvoys[Convoy][Members][i] = -1;
  147. // Stop the job for this player (all data gets cleared, including the missiontext)
  148. Trucker_EndJob(playerid);
  149. return 1; // Exit the function
  150. }
  151. }
  152. }
  153. return 1;
  154. }
  155. // This function cancels the convoy, kicking every member in it
  156. Convoy_Cancel(Convoy)
  157. {
  158. // Setup local variables
  159. new MemberID;
  160. // Loop through all members
  161. for (new i; i < CONVOY_MAX_MEMBERS; i++)
  162. {
  163. // Get the member's playerid
  164. MemberID = AConvoys[Convoy][Members][i];
  165. // If a valid playerid is found
  166. if (MemberID != -1)
  167. {
  168. // Remove the player from the convoy
  169. APlayerData[MemberID][InConvoy] = false;
  170. APlayerData[MemberID][ConvoyID] = 0;
  171. // Hide both convoy-textdraws (for leader and members)
  172. TextDrawHideForPlayer(MemberID, AConvoys[Convoy][ConvoyTextLeader]);
  173. TextDrawHideForPlayer(MemberID, AConvoys[Convoy][ConvoyTextMember]);
  174. // Cancel the trucker-job
  175. Trucker_EndJob(MemberID);
  176. // Reset the stored playerid in the convoy
  177. AConvoys[Convoy][Members][i] = -1;
  178. // Send the member a message that the convoy was cancelled by the leader
  179. SendClientMessage(MemberID, 0xFFFFFFFF, TXT_LeaderCancelledConvoy);
  180. }
  181. }
  182. // Clear all the data of the convoy
  183. AConvoys[Convoy][LoadID] = 0;
  184. AConvoys[Convoy][Location1] = 0;
  185. AConvoys[Convoy][Location2] = 0;
  186. AConvoys[Convoy][Status] = CONVOY_EMPTY;
  187. AConvoys[Convoy][ConvoyStep] = 0;
  188. AConvoys[Convoy][TrailerModel] = 0;
  189. AConvoys[Convoy][LeaderInformedTrailers] = false;
  190. // Kill the convoy-timer
  191. KillTimer(AConvoys[Convoy][ConvoyTimer]);
  192. }
  193. // This function is called for every member when the leader of the convoy started a job (missiontext is updated, loading-checkpoint is created, ...
  194. Convoy_StartMemberJob(playerid, Convoy)
  195. {
  196. // Setup local variables
  197. new StartLoc[50], EndLoc[50], Load[50], RouteText[255], Float:x, Float:y, Float:z, LoadMsg[128];
  198. // Job has started
  199. APlayerData[playerid][JobStarted] = true;
  200. // Copy the convoy-data to this player
  201. APlayerData[playerid][LoadID] = AConvoys[Convoy][LoadID];
  202. APlayerData[playerid][JobLoc1] = AConvoys[Convoy][Location1];
  203. APlayerData[playerid][JobLoc2] = AConvoys[Convoy][Location2];
  204. // Store the vehicleID (required to be able to check if the player left his vehicle)
  205. APlayerData[playerid][VehicleID] = GetPlayerVehicleID(playerid);
  206. // Store the trailerID (required to be able to check if the player lost his trailer)
  207. APlayerData[playerid][TrailerID] = GetVehicleTrailer(GetPlayerVehicleID(playerid));
  208. // Set jobstep to 1 (going to load the goods)
  209. APlayerData[playerid][JobStep] = 1;
  210. // Get the startlocation, endlocation and the load texts
  211. format(StartLoc, 50, ALocations[APlayerData[playerid][JobLoc1]][LocationName]);
  212. format(EndLoc, 50, ALocations[APlayerData[playerid][JobLoc2]][LocationName]);
  213. format(Load, 50, ALoads[APlayerData[playerid][LoadID]][LoadName]);
  214. // Combine it all into a string for the TextDraw (the player can see this all the time) to describe the mission
  215. format(RouteText, 255, TXT_HaulingCargoFromToPickup, Load, StartLoc, EndLoc);
  216. // Set the TextDraw so the player can see it
  217. TextDrawSetString(APlayerData[playerid][MissionText], RouteText);
  218. // Grab the x, y, z positions for the first location
  219. x = ALocations[APlayerData[playerid][JobLoc1]][LocX];
  220. y = ALocations[APlayerData[playerid][JobLoc1]][LocY];
  221. z = ALocations[APlayerData[playerid][JobLoc1]][LocZ];
  222. // Create a checkpoint where the player should load the goods
  223. SetPlayerCheckpoint(playerid, x, y, z, 7);
  224. // Set the job-fail-time for the global vehicle-timer
  225. APlayerData[playerid][VehicleTimerTime] = Job_TimeToFailMission;
  226. // Inform the player that he must load his goods
  227. format(LoadMsg, 128, TXT_PickupCargoAt, Load, StartLoc);
  228. SendClientMessage(playerid, 0xFFFFFFFF, LoadMsg);
  229. SendClientMessage(playerid, 0xFFFFFFFF, TXT_MeetOtherConvoyMembers);
  230. }
  231. // This function is called when all convoy-members have loaded their cargo (it updates the missiontext and creates the unload-checkpoint)
  232. Convoy_UpdateMemberJob(playerid)
  233. {
  234. // Setup local variables
  235. new StartLoc[50], EndLoc[50], Load[50], RouteText[255], Float:x, Float:y, Float:z, UnloadMsg[128];
  236. // Set the jobstep to 3 (going to unload the cargo at the destination)
  237. APlayerData[playerid][JobStep] = 3;
  238. // Get the startlocation, endlocation and the load texts
  239. format(StartLoc, 50, ALocations[APlayerData[playerid][JobLoc1]][LocationName]);
  240. format(EndLoc, 50, ALocations[APlayerData[playerid][JobLoc2]][LocationName]);
  241. format(Load, 50, ALoads[APlayerData[playerid][LoadID]][LoadName]);
  242. // Update the missiontext
  243. format(RouteText, 255, TXT_HaulingCargoFromToDeliver, Load, StartLoc, EndLoc);
  244. // Set the TextDraw so the player can see it
  245. TextDrawSetString(APlayerData[playerid][MissionText], RouteText);
  246. // Grab the x, y, z positions for the second location (to unload the goods)
  247. x = ALocations[APlayerData[playerid][JobLoc2]][LocX];
  248. y = ALocations[APlayerData[playerid][JobLoc2]][LocY];
  249. z = ALocations[APlayerData[playerid][JobLoc2]][LocZ];
  250. // Create a checkpoint where the player should unload the goods
  251. SetPlayerCheckpoint(playerid, x, y, z, 7);
  252. // Inform the player that he must unload his goods
  253. format(UnloadMsg, 128, TXT_DeliverCargoTo, Load, EndLoc);
  254. SendClientMessage(playerid, 0xFFFFFFFF, UnloadMsg);
  255. }
  256. // This is the timer used by every convoy (it updates and checks everything), is executed every 2.5 seconds
  257. public Convoy_Timer(Convoy)
  258. {
  259. // Setup local variables
  260. new LeaderID, MemberID;
  261. // Update the textdraws for all convoy members
  262. Convoy_UpdateTextDraws(Convoy);
  263. // Get the leader-id
  264. LeaderID = AConvoys[Convoy][Members][0];
  265. // Check the jobstep for the entire convoy
  266. switch (AConvoys[Convoy][ConvoyStep])
  267. {
  268. case 0: // Convoy has just been created, but a job hasn't started yet by the leader
  269. {
  270. new bool:AllSameTrailer = true;
  271. // Keep checking if the leader has started a job already
  272. if (APlayerData[LeaderID][JobStarted] == true)
  273. {
  274. // Copy the job-data from the leader to the convoy
  275. AConvoys[Convoy][LoadID] = APlayerData[LeaderID][LoadID];
  276. AConvoys[Convoy][Location1] = APlayerData[LeaderID][JobLoc1];
  277. AConvoys[Convoy][Location2] = APlayerData[LeaderID][JobLoc2];
  278. // Set the trailer-model required by all members to the convoy
  279. AConvoys[Convoy][TrailerModel] = GetVehicleModel(GetVehicleTrailer(GetPlayerVehicleID(LeaderID)));
  280. // First check if the leader has a trailer attached or not
  281. if (AConvoys[Convoy][TrailerModel] != 0)
  282. {
  283. // First check if all players have the correct trailer (except for the leader)
  284. for (new i = 1; i < CONVOY_MAX_MEMBERS; i++)
  285. {
  286. MemberID = AConvoys[Convoy][Members][i]; // Get the member-id from this member-spot
  287. if (MemberID != -1) // Check if the member-id is a valid playerid
  288. {
  289. // Check if the player has the same trailer-model attached to his vehicle as the convoy requires
  290. if (GetVehicleModel(GetVehicleTrailer(GetPlayerVehicleID(MemberID))) != AConvoys[Convoy][TrailerModel])
  291. {
  292. // Inform the player that he hasn't got the correct trailer
  293. switch (AConvoys[Convoy][TrailerModel])
  294. {
  295. case VehicleTrailerCargo, VehicleTrailerCargo2: TextDrawSetString(APlayerData[MemberID][MissionText], TXT_MemberNeedsCargoTrailer);
  296. case VehicleTrailerOre: TextDrawSetString(APlayerData[MemberID][MissionText], TXT_MemberNeedsOreTrailer);
  297. case VehicleTrailerFluids: TextDrawSetString(APlayerData[MemberID][MissionText], TXT_MemberNeedsFluidsTrailer);
  298. }
  299. // Not everyone has the same trailer
  300. AllSameTrailer = false;
  301. }
  302. }
  303. }
  304. }
  305. else // Leader has no trailer attached, so check for the vehiclemodel
  306. {
  307. // First check if all players have the correct trailer (except for the leader)
  308. for (new i = 1; i < CONVOY_MAX_MEMBERS; i++)
  309. {
  310. MemberID = AConvoys[Convoy][Members][i]; // Get the member-id from this member-spot
  311. if (MemberID != -1) // Check if the member-id is a valid playerid
  312. {
  313. // Get the vehiclemodel of the member
  314. new vModel = GetVehicleModel(GetPlayerVehicleID(MemberID));
  315. // Check if the member has a valid trucking vehicle (flatbed or DFT30)
  316. switch (vModel)
  317. {
  318. case VehicleFlatbed, VehicleDFT30: AllSameTrailer = true;
  319. default:
  320. {
  321. TextDrawSetString(APlayerData[MemberID][MissionText], "You need a Flatbed or DFT-30");
  322. AllSameTrailer = false;
  323. }
  324. }
  325. }
  326. }
  327. }
  328. // If all members have the same trailer
  329. if (AllSameTrailer == true)
  330. {
  331. // Inform the leader that everyone has the same trailer
  332. SendClientMessage(LeaderID, 0xFFFFFFFF, TXT_AllMembersSameTrailer);
  333. // Start the same job for every member if they all have the same trailer
  334. for (new i = 1; i < CONVOY_MAX_MEMBERS; i++)
  335. {
  336. MemberID = AConvoys[Convoy][Members][i]; // Get the member-id from this member-spot
  337. if (MemberID != -1) // Check if the member-id is a valid playerid
  338. Convoy_StartMemberJob(MemberID, Convoy); // Start the job for the member
  339. }
  340. // Select the next step for the convoy (all members are now en-route to the loading-point)
  341. AConvoys[Convoy][ConvoyStep] = 1;
  342. // Also close the convoy so no more members can join
  343. AConvoys[Convoy][Status] = CONVOY_CLOSED;
  344. }
  345. else
  346. {
  347. // Check if the leader has been informed already that not all members have the same trailer
  348. if (AConvoys[Convoy][LeaderInformedTrailers] == false)
  349. {
  350. // Inform the leader that not every member has the same trailer, convoy cannot start yet
  351. SendClientMessage(LeaderID, 0xFFFFFFFF, TXT_AllMembersNotSameTrailer);
  352. AConvoys[Convoy][LeaderInformedTrailers] = true; // Leader is informed now
  353. }
  354. }
  355. }
  356. }
  357. case 1: // Everyone has received their job-data (but haven't loaded their cargo yet)
  358. {
  359. new bool:AllMembersLoaded = true;
  360. // Check if everyone has loaded their cargo before moving on to convoystep 2
  361. for (new i; i < CONVOY_MAX_MEMBERS; i++)
  362. {
  363. MemberID = AConvoys[Convoy][Members][i]; // Get the playerid of the member
  364. if (MemberID != -1) // Check if the memberid is a valid id
  365. if (APlayerData[MemberID][JobStep] != 2) // Check if the player hasn't loaded his cargo yet
  366. AllMembersLoaded = false; // Not all members have loaded their cargo yet
  367. }
  368. // Check if everyone has loaded their cargo
  369. if (AllMembersLoaded == true)
  370. {
  371. // Inform the leader that everyone has the same trailer
  372. SendClientMessage(LeaderID, 0xFFFFFFFF, TXT_AllMembersLoadedCargo);
  373. // Update the job for every member if they all have loaded their cargo
  374. for (new i; i < CONVOY_MAX_MEMBERS; i++)
  375. {
  376. MemberID = AConvoys[Convoy][Members][i]; // Get the member-id from this member-spot
  377. if (MemberID != -1) // Check if the member-id is a valid playerid
  378. Convoy_UpdateMemberJob(MemberID); // Start the job for the member
  379. }
  380. // Select the next step for the convoy (all members are now en-route to the unloading-point)
  381. AConvoys[Convoy][ConvoyStep] = 2;
  382. }
  383. }
  384. case 2: // Everybody has loaded their cargo and all members have their job updated, all members are en-route to the destination
  385. {
  386. // Check if everyone is staying close to the leader and check if all members have unloaded their cargo
  387. new bool:AllMembersUnloaded = true;
  388. // Also check if all players have delivered their load
  389. for (new i; i < CONVOY_MAX_MEMBERS; i++)
  390. {
  391. MemberID = AConvoys[Convoy][Members][i]; // Get the playerid of the member
  392. if (MemberID != -1) // Check if the memberid is a valid id
  393. if (APlayerData[MemberID][JobStep] != 4) // Check if the player hasn't unloaded his cargo yet
  394. AllMembersUnloaded = false; // Not all members have unloaded their cargo yet
  395. }
  396. if (AllMembersUnloaded == true) // Check if all members have unloaded their cargo (nobody cleared this variable)
  397. AConvoys[Convoy][ConvoyStep] = 3; // Set the jobstep for the entire convoy to 3 (everybody unloaded their cargo, but jobs must still be payed out)
  398. }
  399. case 3: // Everybody has unloaded their cargo (now it's time to pay all members and finish the job)
  400. {
  401. // Setup local variables
  402. new Float:x1, Float:y1, Float:x2, Float:y2, Float:Distance, Message[128], Payment, Bonus, NumMembers, Name[24], BonusMsg[128];
  403. // Count the number of members in the convoy
  404. NumMembers = Convoy_CountMembers(Convoy);
  405. // Get the name of the convoy-leader
  406. GetPlayerName(LeaderID, Name, sizeof(Name));
  407. // Grab the x, y, z positions for the first location (to load the goods)
  408. x1 = ALocations[APlayerData[LeaderID][JobLoc1]][LocX];
  409. y1 = ALocations[APlayerData[LeaderID][JobLoc1]][LocY];
  410. // Grab the x, y, z positions for the second location (to unload the goods)
  411. x2 = ALocations[APlayerData[LeaderID][JobLoc2]][LocX];
  412. y2 = ALocations[APlayerData[LeaderID][JobLoc2]][LocY];
  413. // Calculate the distance between both points
  414. Distance = floatsqroot(((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1)));
  415. // Calculate the payment for the player
  416. Payment = floatround((Distance * ALoads[APlayerData[LeaderID][LoadID]][PayPerUnit]), floatround_floor);
  417. // Check if the convoy has done the bonus mission
  418. if (RandomBonusMission[MissionFinished] == false)
  419. {
  420. // Check all paramters (load, startlocation and end-location)
  421. if (RandomBonusMission[RandomLoad] == APlayerData[LeaderID][LoadID])
  422. if (RandomBonusMission[RandomStartLoc] == APlayerData[LeaderID][JobLoc1])
  423. if (RandomBonusMission[RandomEndLoc] == APlayerData[LeaderID][JobLoc2])
  424. {
  425. Payment = Payment * 2; // Double the payment is the player was the first to do the bonus mission
  426. RandomBonusMission[MissionFinished] = true; // Only one player/convoy can do the bonus mission, a new one is chosen next
  427. format(BonusMsg, 128, "{00BBFF}Convoy with leader {FFBB00}%s{00BBFF} has finished the bonus mission", Name);
  428. SendClientMessageToAll(0xFFFFFFFF, BonusMsg);
  429. }
  430. }
  431. // Calculate convoy-bonus (standard payment of 100% and 25% extra for each convoy-member)
  432. Bonus = (NumMembers * 25) + 100; // For every member, 25% bonus is added to the payment, on top of the standard payment
  433. // Calculate total payment for each member
  434. Payment = (Payment * Bonus) / 100;
  435. // Pay every member and finish their mission
  436. for (new i; i < CONVOY_MAX_MEMBERS; i++)
  437. {
  438. MemberID = AConvoys[Convoy][Members][i]; // Get the playerid of the member
  439. if (MemberID != -1) // Check if the memberid is a valid id
  440. {
  441. // Reward the player (give cash and points)
  442. RewardPlayer(MemberID, Payment, 5);
  443. // Increase the stats for completing a trucking job while in a convoy
  444. APlayerData[MemberID][StatsConvoyJobs]++;
  445. // Also save the data (in case the server crashes, progress would be lost)
  446. PlayerFile_Save(MemberID);
  447. // End the member's job
  448. Trucker_EndJob(MemberID);
  449. // Send a message to let the player know he finished his mission and got paid
  450. format(Message, 128, TXT_FinishedConvoy, Payment);
  451. SendClientMessage(MemberID, 0xFFFFFFFF, Message);
  452. // Also update the player's missiontext to inform the player that he must wait for the leader to start a job
  453. if (i != 0) // Skip this if the current index is the leader (the leader doesn't have to wait for a new job)
  454. TextDrawSetString(APlayerData[MemberID][MissionText], TXT_WaitingLeaderJob);
  455. }
  456. }
  457. // Clear the data in the convoy
  458. AConvoys[Convoy][LoadID] = 0; // Clear the load-id
  459. AConvoys[Convoy][Location1] = 0; // Clear the loadingpoint id
  460. AConvoys[Convoy][Location2] = 0; // Clear the unloading point id
  461. AConvoys[Convoy][Status] = CONVOY_OPEN; // Set status to "open" again, so new members can join
  462. AConvoys[Convoy][ConvoyStep] = 0; // Set convoystep to 0 (wait for a new job to be started by the leader)
  463. AConvoys[Convoy][TrailerModel] = 0; // Clear trailer model (the next job can be for another trailer)
  464. AConvoys[Convoy][LeaderInformedTrailers] = false; // Allow the leader to be informed again if not all members have the correct trailer
  465. }
  466. }
  467. return 1;
  468. }
  469. // This function is used to update the textdraws for the leader and all members (used by the convoy-timer)
  470. Convoy_UpdateTextDraws(Convoy)
  471. {
  472. // Setup local variables
  473. new LeaderID, MemberID, LeaderName[24], NumMembers, TextLeader[128], TextMember[128], LastMember[24], LastMemberID, Float:Distance;
  474. // Get the leader-id
  475. LeaderID = AConvoys[Convoy][Members][0];
  476. // Get the name of the convoy-leader
  477. GetPlayerName(LeaderID, LeaderName, sizeof(LeaderName));
  478. // Get the number of members of the convoy
  479. NumMembers = Convoy_CountMembers(Convoy);
  480. // Check if there members besides the leader
  481. if (NumMembers > 1)
  482. {
  483. LastMemberID = Convoy_GetFurthestMember(Convoy); // Get the playerid of the member who is furthest away from the leader
  484. GetPlayerName(LastMemberID, LastMember, sizeof(LastMember)); // Get the name of the furthest member
  485. Distance = PlayerToPlayer(LeaderID, LastMemberID); // Get the distance to the last member
  486. }
  487. else // No other members are in the convoy yet
  488. {
  489. format(LastMember, 24, " - ");
  490. Distance = 0.0;
  491. }
  492. // Update the convoy-textdraw for the leader
  493. format(TextLeader, 128, TXT_LeaderInfoBar, NumMembers, LastMember, Distance);
  494. TextDrawSetString(AConvoys[Convoy][ConvoyTextLeader], TextLeader);
  495. // Enable the convoy-textDraw for the leader
  496. TextDrawShowForPlayer(LeaderID, AConvoys[Convoy][ConvoyTextLeader]);
  497. // Update the convoy-textdraw for every member
  498. for (new i = 1; i < CONVOY_MAX_MEMBERS; i++)
  499. {
  500. MemberID = AConvoys[Convoy][Members][i]; // Get the playerid of the member
  501. if (MemberID != -1) // Check if the memberid is a valid id
  502. {
  503. // Calculate the distance to the leader
  504. Distance = PlayerToPlayer(LeaderID, MemberID);
  505. // Update the textdraw for the members
  506. format(TextMember, 128, TXT_MemberInfoBar, LeaderName, Distance, NumMembers);
  507. TextDrawSetString(AConvoys[Convoy][ConvoyTextMember], TextMember);
  508. TextDrawShowForPlayer(MemberID, AConvoys[Convoy][ConvoyTextMember]);
  509. }
  510. }
  511. }
  512. // This function counts the members in the convoy
  513. Convoy_CountMembers(Convoy)
  514. {
  515. // Setup local variables
  516. new NumMembers;
  517. // Loop through all members
  518. for (new i; i < CONVOY_MAX_MEMBERS; i++)
  519. {
  520. // Check if there is a valid member-id stored (playerid)
  521. if (AConvoys[Convoy][Members][i] != -1)
  522. NumMembers++; // Increase the number of members
  523. }
  524. // Return the number of members to the calling routine
  525. return NumMembers;
  526. }
  527. // This function checks the player and determines if he's a valid trucker who's able to create or join a convoy
  528. Convoy_PlayerAllowed(playerid)
  529. {
  530. // Make sure that the leader is a trucker
  531. if (APlayerData[playerid][PlayerClass] == ClassTruckDriver)
  532. {
  533. // Check if the player isn't a member of a convoy already
  534. if (APlayerData[playerid][InConvoy] == false)
  535. {
  536. // Make sure that the player hasn't started a job
  537. if (APlayerData[playerid][JobStarted] == false)
  538. return true; // The player is allowed to create or join a convoy
  539. else
  540. SendClientMessage(playerid, 0xFFFFFFFF, TXT_CannotJoinJobStarted);
  541. }
  542. else
  543. SendClientMessage(playerid, 0xFFFFFFFF, TXT_ConvoyAllreadyJoined);
  544. }
  545. else
  546. SendClientMessage(playerid, 0xFFFFFFFF, TXT_ConvoyNeedsTruckerClass);
  547. // If any condition wasn't true, the player isn't allowed to create or join a convoy
  548. return false;
  549. }
  550. // This function sends the given message to all members of the convoy
  551. Convoy_SendMessage(Convoy, Message[])
  552. {
  553. // Setup local variables
  554. new MemberID;
  555. // Loop through all members
  556. for (new i; i < CONVOY_MAX_MEMBERS; i++)
  557. {
  558. MemberID = AConvoys[Convoy][Members][i]; // Get the member-id on this index
  559. if (MemberID != -1) // Check if this member has a valid playerid
  560. {
  561. SendClientMessage(MemberID, 0xFFFFFFFF, Message); // Send the given message to the member
  562. }
  563. }
  564. }
  565. // This function returns "true" is the given player is the leader of the convoy
  566. stock Convoy_IsLeader(playerid, Convoy)
  567. {
  568. // Check if the player is part of a convoy
  569. if ((APlayerData[playerid][InConvoy] == true) && (AConvoys[Convoy][Members][0] = playerid))
  570. return true; // Player is in a convoy AND he's the leader of it
  571. else
  572. return false; // Player is a member of the convoy (or not in the same convoy)
  573. }
  574. // This function returns true if the player is a member of the given convoy
  575. stock Convoy_IsMember(playerid, Convoy)
  576. {
  577. // Loop through all members (excluding the leader)
  578. for (new i = 1; i < CONVOY_MAX_MEMBERS; i++)
  579. if (AConvoys[Convoy][Members][i] == playerid) // Check if this member is the given player
  580. return true; // Return true (the player is a member of the convoy)
  581. // If the given playerid wasn't found among the members, return false
  582. return false;
  583. }
  584. // A function that returns the member of a convoy that's the furthest away from the leader
  585. Convoy_GetFurthestMember(Convoy)
  586. {
  587. // Setup local variables
  588. new Float:distance = 0.0, Float:distance2 = 0.0, LeaderID, MemberID, result = -1;
  589. // Get the leader-id
  590. LeaderID = AConvoys[Convoy][Members][0];
  591. // Loop through all members (excluding the leader)
  592. for(new i = 1; i < CONVOY_MAX_MEMBERS; i++)
  593. {
  594. MemberID = AConvoys[Convoy][Members][i]; // Get the playerid of the member
  595. if (MemberID != -1) // Check if the memberid is a valid id
  596. {
  597. // Get the distance between leader and member
  598. distance2 = PlayerToPlayer(LeaderID, MemberID);
  599. // Check if the distance is bigger than the previous distance
  600. if(distance2 > distance)
  601. {
  602. // Store the distance
  603. distance = distance2;
  604. // Store the member-id
  605. result = MemberID;
  606. }
  607. }
  608. }
  609. // Return the vehicle-id of the closest vehicle
  610. return result;
  611. }
  612. // Get the distance between the two players
  613. PlayerToPlayer(player1, player2)
  614. {
  615. // Setup local variables
  616. new Float:pX, Float:pY, Float:pZ, Float:cX, Float:cY, Float:cZ, Float:distance;
  617. // Get the player1 position
  618. GetPlayerPos(player1, pX, pY, pZ);
  619. // Get the player2 position
  620. GetPlayerPos(player2, cX, cY, cZ);
  621. // Calculate the distance
  622. distance = floatsqroot(floatpower(floatabs(floatsub(cX, pX)), 2) + floatpower(floatabs(floatsub(cY, pY)), 2) + floatpower(floatabs(floatsub(cZ, pZ)), 2));
  623. // Return the distance to the calling routine
  624. return floatround(distance);
  625. }