impl.inc 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478
  1. /**--------------------------------------------------------------------------**\
  2. ==============================
  3. y_hooks - Hook any callback!
  4. ==============================
  5. Description:
  6. Automatically hooks any callbacks with a very simple syntax.
  7. Legal:
  8. Version: MPL 1.1
  9. The contents of this file are subject to the Mozilla Public License Version
  10. 1.1 (the "License"); you may not use this file except in compliance with
  11. the License. You may obtain a copy of the License at
  12. http://www.mozilla.org/MPL/
  13. Software distributed under the License is distributed on an "AS IS" basis,
  14. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  15. for the specific language governing rights and limitations under the
  16. License.
  17. The Original Code is the SA:MP callback hooks include.
  18. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  19. Portions created by the Initial Developer are Copyright (C) 2008
  20. the Initial Developer. All Rights Reserved.
  21. Contributors:
  22. ZeeX, koolk, JoeBullet/Google63, g_aSlice/Slice
  23. Thanks:
  24. JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
  25. Peter, Cam - Support.
  26. ZeeX, g_aSlice/Slice, Popz, others - Very productive conversations.
  27. koolk - IsPlayerinAreaEx code.
  28. TheAlpha - Danish translation.
  29. breadfish - German translation.
  30. Fireburn - Dutch translation.
  31. yom - French translation.
  32. 50p - Polish translation.
  33. Zamaroht - Spanish translation.
  34. Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes
  35. for me to strive to better.
  36. Pixels^ - Running XScripters where the idea was born.
  37. Matite - Pestering me to release it and using it.
  38. Very special thanks to:
  39. Thiadmer - PAWN, whose limits continue to amaze me!
  40. Kye/Kalcor - SA:MP.
  41. SA:MP Team past, present and future - SA:MP.
  42. Version:
  43. 2.0
  44. Changelog:
  45. 27/03/13:
  46. Ported to the new YSI version.
  47. 09/01/08:
  48. Added a fix for IsPlayerInRaceCheckpoint.
  49. 11/10/07:
  50. Added race start count option.
  51. 03/08/07:
  52. Updated timer system.
  53. 02/08/07:
  54. Fixed repeating races.
  55. 31/07/07:
  56. Added tracking support.
  57. 21/06/07:
  58. Added restart option to races to not destroy them.
  59. 02/05/07:
  60. Added YSI_ prefix to all globals.
  61. 01/05/07:
  62. First version.
  63. \**--------------------------------------------------------------------------**/
  64. #define MAX_RACE_WINNERS 3
  65. #if !defined MAX_RACE_CHECKPOINTS
  66. #define MAX_RACE_CHECKPOINTS 1024
  67. #endif
  68. #if !defined MAX_RACE_STARTS
  69. #define MAX_RACE_STARTS 32
  70. #endif
  71. #define NO_RACE -1
  72. #define RACE_NO_CHECKPOINT -1
  73. #define RACE_LOOP_GRANULARITY 5
  74. #define RACE_PLAYER_OUT 0x80000000
  75. enum e_RACE_FLAGS (<<= 1)
  76. {
  77. e_RACE_FLAGS_NONE = 0,
  78. e_RACE_FLAGS_EXIT_TIME = 0xFFFF,
  79. e_RACE_FLAGS_ACTIVE = 0x10000,
  80. e_RACE_FLAGS_ARIAL,
  81. e_RACE_FLAGS_REL_WIN,
  82. e_RACE_FLAGS_STARTED,
  83. e_RACE_FLAGS_RACING,
  84. e_RACE_FLAGS_CD_JOIN,
  85. e_RACE_FLAGS_RESTART
  86. }
  87. enum E_RACE
  88. {
  89. e_RACE_FLAGS:E_RACE_FLAGS,
  90. E_RACE_LAPS,
  91. E_RACE_CHECKPOINTS,
  92. E_RACE_CP_START,
  93. E_RACE_RACER_COUNT,
  94. E_RACE_RACER_MAX,
  95. E_RACE_COUNTDOWN,
  96. E_RACE_FINISHED,
  97. E_RACE_ENTRY,
  98. E_RACE_VW,
  99. E_RACE_INT,
  100. E_RACE_PRIZES[MAX_RACE_WINNERS]
  101. }
  102. enum E_RACE_PLAYER
  103. {
  104. E_RACE_PLAYER_RACE,
  105. E_RACE_PLAYER_LAP,
  106. E_RACE_PLAYER_CP,
  107. E_RACE_PLAYER_TIME,
  108. #if defined RACE_POSITION
  109. E_RACE_PLAYER_POSITION,
  110. #endif
  111. E_RACE_PLAYER_TOUT,
  112. Float:E_RACE_PLAYER_X,
  113. Float:E_RACE_PLAYER_Y,
  114. Float:E_RACE_PLAYER_Z,
  115. Float:E_RACE_PLAYER_A,
  116. E_RACE_PLAYER_INT,
  117. E_RACE_PLAYER_WORLD
  118. }
  119. #define RACE_POS_DONE 0x80000000
  120. enum E_RACE_POS
  121. {
  122. E_RACE_POS_CP,
  123. Float:E_RACE_POS_TOGO
  124. }
  125. _Y_RACES_STATIC stock
  126. PlayerArray:YSI_g_sRacers[MAX_RACES]<MAX_PLAYERS>,
  127. YSI_g_sRaceData[MAX_RACES][E_RACE],
  128. Float:YSI_g_sRaceCheckpoints[MAX_RACE_CHECKPOINTS][3],
  129. YSI_g_sPlayerRace[MAX_PLAYERS][E_RACE_PLAYER],
  130. Float:YSI_g_sRaceStarts[MAX_RACES][MAX_RACE_STARTS][4],
  131. YSI_g_sCPIndex,
  132. Iterator:YSI_g_sRacePeople[MAX_RACES]<MAX_PLAYERS>;
  133. forward Race_Countdown(race, time);
  134. forward Race_Timeout(playerid);
  135. loadtext core[ysi_race];
  136. /*----------------------------------------------------------------------------*-
  137. Function:
  138. RaceArray_IndexShift
  139. Params:
  140. from - Which slot to start shifting up.
  141. add - How to adjust the slots.
  142. Return:
  143. -
  144. Notes:
  145. Find all races whose checkpoint blocks start above the current index and
  146. increment them.
  147. -*----------------------------------------------------------------------------*/
  148. _Y_RACES_STATIC stock RaceArray_IndexShift(from, add)
  149. {
  150. for (new i = 0; i != MAX_RACES; ++i)
  151. {
  152. if (YSI_g_sRaceData[i][E_RACE_CP_START] >= from) YSI_g_sRaceData[i][E_RACE_CP_START] += add;
  153. }
  154. }
  155. /*----------------------------------------------------------------------------*-
  156. Function:
  157. RaceArray_Shift
  158. Params:
  159. from - Which slot to start shifting up.
  160. &end - Slot to end the shifting on.
  161. to - Slot to shift to.
  162. Return:
  163. -
  164. Notes:
  165. Shifts checkpoints up in the main array to make room for new ones.
  166. -*----------------------------------------------------------------------------*/
  167. _Y_RACES_STATIC stock RaceArray_Shift(from, &end, to)
  168. {
  169. // Fast version.
  170. end -= from;
  171. if (end + to >= MAX_RACE_CHECKPOINTS)
  172. {
  173. return false;
  174. }
  175. memcpy(_:YSI_g_sRaceCheckpoints[to], _:YSI_g_sRaceCheckpoints[from], 0, end * 4 * 3, end * 3);
  176. //++to;
  177. end += to;
  178. return true;
  179. }
  180. /*----------------------------------------------------------------------------*-
  181. Function:
  182. RaceArray_Add
  183. Params:
  184. slot - Slot to add to.
  185. Float:x - Position data.
  186. Float:y - Position data.
  187. Float:z - Position data.
  188. Return:
  189. -
  190. Notes:
  191. Adds a new checkpoint to the checkpoints array.
  192. -*----------------------------------------------------------------------------*/
  193. _Y_RACES_STATIC stock RaceArray_Add(slot, Float:x, Float:y, Float:z)
  194. {
  195. if (slot < YSI_g_sCPIndex)
  196. {
  197. if (!RaceArray_Shift(slot, YSI_g_sCPIndex, slot + 1)) return false;
  198. RaceArray_IndexShift(slot, 1);
  199. }
  200. YSI_g_sRaceCheckpoints[slot][0] = x;
  201. YSI_g_sRaceCheckpoints[slot][1] = y;
  202. YSI_g_sRaceCheckpoints[slot][2] = z;
  203. return true;
  204. }
  205. /*----------------------------------------------------------------------------*-
  206. Function:
  207. Race__IsActive
  208. Params:
  209. raceid - Race to check.
  210. Return:
  211. -
  212. Notes:
  213. Checks a race is active.
  214. -*----------------------------------------------------------------------------*/
  215. #define Race__IsActive(%1) \
  216. (YSI_g_sRaceData[(%1)][E_RACE_FLAGS] & e_RACE_FLAGS_ACTIVE)
  217. /*----------------------------------------------------------------------------*-
  218. Function:
  219. Race_IsValid
  220. Params:
  221. raceid - Race to check.
  222. Return:
  223. -
  224. Notes:
  225. Checks an id is valid and active.
  226. -*----------------------------------------------------------------------------*/
  227. #define Race_IsValid(%1) \
  228. (0 <= (%1) < MAX_RACES && Race__IsActive((%1)))
  229. /*----------------------------------------------------------------------------*-
  230. Function:
  231. Races_SetupGroups
  232. Params:
  233. -
  234. Return:
  235. -
  236. Notes:
  237. Disables default group settings when groups are used.
  238. -*----------------------------------------------------------------------------*/
  239. stock Races_SetupGroups() <YSI_has_groups:n>
  240. {
  241. }
  242. stock Races_SetupGroups() <>
  243. {
  244. }
  245. /*----------------------------------------------------------------------------*-
  246. Function:
  247. Race_Create
  248. Params:
  249. laps - Number of laps to race for.
  250. entry - Cost of entry.
  251. countdown - Time to count down from for start.
  252. bool:arial - Use arial checkpoints instead.
  253. bool:fixedPrize - Set prize amounts manually.
  254. exitTime - Time allowed out a vehicle before fail.
  255. interior - The interior of the race.
  256. world - The world of the race.
  257. bool:restart - Don't destroy the race on completion.
  258. Return:
  259. raceid - ID of the race for reference or -1.
  260. Notes:
  261. Finds an empty slot and sets the race up for use. All
  262. parameters are optional and can be set separately aswell.
  263. -*----------------------------------------------------------------------------*/
  264. foreign _Race_Create(l,e,c,a,f,x,i,w,r);
  265. stock Race_Create(laps = 0, entry = 0, countdown = 3, bool:arial = false, bool:fixedPrize = true, exitTime = 0, interior = 0, world = 0, bool:restart = false)
  266. {
  267. return _Race_Create(laps, entry, countdown, _:arial, _:fixedPrize, exitTime, interior, world, _:restart);
  268. }
  269. global _Race_Create(l,e,c,a,f,x,i,w,r)
  270. {
  271. new
  272. raceid;
  273. for (raceid = 0; raceid < MAX_RACES; raceid++) if (!Race__IsActive(raceid)) break;
  274. if (raceid == MAX_RACES) return NO_RACE;
  275. YSI_g_sRaceData[raceid][E_RACE_FLAGS] = e_RACE_FLAGS_ACTIVE |
  276. (f ? e_RACE_FLAGS_NONE : e_RACE_FLAGS_REL_WIN) |
  277. (a ? e_RACE_FLAGS_ARIAL : e_RACE_FLAGS_NONE ) |
  278. (r ? e_RACE_FLAGS_RESTART : e_RACE_FLAGS_NONE ) |
  279. (e_RACE_FLAGS:x & e_RACE_FLAGS_EXIT_TIME);
  280. //
  281. // Old functions.
  282. //
  283. //Race_SetLaps(raceid, l);
  284. YSI_g_sRaceData[raceid][E_RACE_LAPS] = l;
  285. //Race_SetEntry(raceid, e);
  286. YSI_g_sRaceData[raceid][E_RACE_ENTRY] = e;
  287. if (f)
  288. {
  289. //for (new p = 1; p <= MAX_RACE_WINNERS; p++) Race_SetPrize(raceid, (MAX_RACE_WINNERS + 1) - p, e * p);
  290. for (new p = 1; p <= MAX_RACE_WINNERS; p++) YSI_g_sRaceData[raceid][E_RACE_PRIZES][MAX_RACE_WINNERS - p] = e * p;
  291. //Race_SetFixedWin(raceid, _:f);
  292. }
  293. //Race_SetArial(raceid, _:a);
  294. //Race_SetActive(raceid, 1);
  295. //Race_SetCountdown(raceid, c);
  296. YSI_g_sRaceData[raceid][E_RACE_COUNTDOWN] = c;
  297. //Race_SetExitTime(raceid, x);
  298. //Race_SetInterior(raceid, i);
  299. YSI_g_sRaceData[raceid][E_RACE_INT] = i;
  300. //Race_SetWorld(raceid, w);
  301. YSI_g_sRaceData[raceid][E_RACE_VW] = w;
  302. //Race_SetRestart(raceid, _:r);
  303. //
  304. // Remainder.
  305. //
  306. YSI_g_sRaceData[raceid][E_RACE_CHECKPOINTS] = 0;
  307. YSI_g_sRaceData[raceid][E_RACE_RACER_COUNT] = 0;
  308. YSI_g_sRaceData[raceid][E_RACE_FINISHED] = 0;
  309. YSI_g_sRaceData[raceid][E_RACE_RACER_MAX] = 0;
  310. PA_Init(YSI_g_sRacers[raceid]);
  311. Iter_Clear(YSI_g_sRacePeople[raceid]);
  312. YSI_g_sRaceData[raceid][E_RACE_CP_START] = YSI_g_sCPIndex;
  313. NO_GROUPS(raceid)
  314. {
  315. }
  316. return raceid;
  317. }
  318. /*----------------------------------------------------------------------------*-
  319. Function:
  320. Race_Destroy
  321. Params:
  322. slot - Race to destroy.
  323. bool:refund - Should entrants get their money back?
  324. Return:
  325. -
  326. Notes:
  327. Called whenever a player leaves the race, checks the
  328. number of remaining racers and if none ends the race.
  329. -*----------------------------------------------------------------------------*/
  330. foreign void:_Race_Destroy(slot, refund);
  331. stock Race_Destroy(slot, bool:refund = false)
  332. {
  333. _Race_Destroy(slot, _:refund);
  334. }
  335. global void:_Race_Destroy(slot, refund)
  336. {
  337. if (Race_IsValid(slot))
  338. {
  339. if (YSI_g_sRaceData[slot][E_RACE_FLAGS] & e_RACE_FLAGS_STARTED)
  340. {
  341. foreach (new i : Player)
  342. {
  343. if (PA_Get(YSI_g_sRacers[slot], i))
  344. {
  345. DisablePlayerRaceCheckpoint(i);
  346. Race_PlayerDone(i);
  347. }
  348. }
  349. }
  350. else
  351. {
  352. foreach (new i : Player)
  353. {
  354. if (PA_Get(YSI_g_sRacers[slot], i))
  355. {
  356. _Race_PlayerLeave(i, refund);
  357. }
  358. }
  359. }
  360. YSI_g_sRaceData[slot][E_RACE_RACER_COUNT] = 0;
  361. YSI_g_sRaceData[slot][E_RACE_FLAGS] = e_RACE_FLAGS:0;
  362. new
  363. count = YSI_g_sRaceData[slot][E_RACE_CHECKPOINTS],
  364. start = YSI_g_sRaceData[slot][E_RACE_CP_START];
  365. RaceArray_Shift(start + count, YSI_g_sCPIndex, start);
  366. RaceArray_IndexShift(start, -count);
  367. }
  368. }
  369. /*----------------------------------------------------------------------------*-
  370. Function:
  371. Race_AddCheckpoint
  372. Params:
  373. raceid - Race to add to.
  374. Float:x - X position.
  375. Float:y - Y position.
  376. Float:z - Z position.
  377. Return:
  378. position or -1.
  379. Notes:
  380. -
  381. -*----------------------------------------------------------------------------*/
  382. global Race_AddCheckpoint(raceid, Float:x, Float:y, Float:z)
  383. {
  384. if (!Race_IsValid(raceid)) return RACE_NO_CHECKPOINT;
  385. new
  386. count = YSI_g_sRaceData[raceid][E_RACE_CHECKPOINTS];
  387. RaceArray_Add(YSI_g_sRaceData[raceid][E_RACE_CP_START] + count, x, y, z);
  388. YSI_g_sRaceData[raceid][E_RACE_CHECKPOINTS]++;
  389. return count;
  390. }
  391. /*----------------------------------------------------------------------------*-
  392. Function:
  393. Race_AddStart
  394. Params:
  395. raceid - Race to add to.
  396. Float:x - X position.
  397. Float:y - Y position.
  398. Float:z - Z position.
  399. Float:a - Angle.
  400. Return:
  401. position or -1.
  402. Notes:
  403. Adds a starting point to a race and increases the max
  404. number of racers for the race.
  405. -*----------------------------------------------------------------------------*/
  406. global Race_AddStart(raceid, Float:x, Float:y, Float:z, Float:a)
  407. {
  408. if (!Race_IsValid(raceid)) return RACE_NO_CHECKPOINT;
  409. new
  410. count = YSI_g_sRaceData[raceid][E_RACE_RACER_MAX];
  411. if (count >= MAX_RACE_STARTS) return RACE_NO_CHECKPOINT;
  412. YSI_g_sRaceStarts[raceid][count][0] = x;
  413. YSI_g_sRaceStarts[raceid][count][1] = y;
  414. YSI_g_sRaceStarts[raceid][count][2] = z;
  415. YSI_g_sRaceStarts[raceid][count][3] = a;
  416. YSI_g_sRaceData[raceid][E_RACE_RACER_MAX]++;
  417. return count;
  418. }
  419. /*----------------------------------------------------------------------------*-
  420. Function:
  421. Race_SetFixedWin
  422. Params:
  423. raceid - Race to set for.
  424. set - 1/0.
  425. Return:
  426. -
  427. Notes:
  428. Sets wether or not a race has fixed prizes for the
  429. winners. If not the prizes are calculated at race start
  430. based on the number of entrants and the entry fee.
  431. -*----------------------------------------------------------------------------*/
  432. global void:Race_SetFixedWin(raceid, set)
  433. {
  434. if (!Race_IsValid(raceid)) return;
  435. if (set) YSI_g_sRaceData[raceid][E_RACE_FLAGS] &= ~e_RACE_FLAGS_REL_WIN;
  436. else YSI_g_sRaceData[raceid][E_RACE_FLAGS] |= e_RACE_FLAGS_REL_WIN;
  437. }
  438. /*----------------------------------------------------------------------------*-
  439. Function:
  440. Race_SetRestart
  441. Params:
  442. raceid - Race to set for.
  443. set - 1/0.
  444. Return:
  445. -
  446. Notes:
  447. Sets wether or not a race is destroyed after completion.
  448. -*----------------------------------------------------------------------------*/
  449. global void:Race_SetRestart(raceid, set)
  450. {
  451. if (!Race_IsValid(raceid)) return;
  452. if (set) YSI_g_sRaceData[raceid][E_RACE_FLAGS] |= e_RACE_FLAGS_RESTART;
  453. else YSI_g_sRaceData[raceid][E_RACE_FLAGS] &= ~e_RACE_FLAGS_RESTART;
  454. }
  455. /*----------------------------------------------------------------------------*-
  456. Function:
  457. Race_SetArial
  458. Params:
  459. raceid - Race to set for.
  460. set - 1/0.
  461. Return:
  462. -
  463. Notes:
  464. Toggles the use of arial checkpoints.
  465. -*----------------------------------------------------------------------------*/
  466. global void:Race_SetArial(raceid, set)
  467. {
  468. if (!Race_IsValid(raceid)) return;
  469. if (set) YSI_g_sRaceData[raceid][E_RACE_FLAGS] |= e_RACE_FLAGS_ARIAL;
  470. else YSI_g_sRaceData[raceid][E_RACE_FLAGS] &= ~e_RACE_FLAGS_ARIAL;
  471. }
  472. /*----------------------------------------------------------------------------*-
  473. Function:
  474. Race_SetActive
  475. Params:
  476. raceid - Race to set for.
  477. set - 1/0.
  478. Return:
  479. -
  480. Notes:
  481. Activates the race for entry and use.
  482. -*----------------------------------------------------------------------------*/
  483. _Y_RACES_STATIC stock Race_SetActive(raceid, set)
  484. {
  485. if (!Race_IsValid(raceid)) return;
  486. if (set) YSI_g_sRaceData[raceid][E_RACE_FLAGS] |= e_RACE_FLAGS_ACTIVE;
  487. else YSI_g_sRaceData[raceid][E_RACE_FLAGS] &= ~e_RACE_FLAGS_ACTIVE;
  488. }
  489. /*----------------------------------------------------------------------------*-
  490. Function:
  491. Race_SetCountdown
  492. Params:
  493. raceid - Race to set for.
  494. countdown - Number to count down from.
  495. Return:
  496. -
  497. Notes:
  498. -
  499. -*----------------------------------------------------------------------------*/
  500. global void:Race_SetCountdown(raceid, countdown)
  501. {
  502. if (!Race_IsValid(raceid)) return;
  503. YSI_g_sRaceData[raceid][E_RACE_COUNTDOWN] = countdown;
  504. }
  505. /*----------------------------------------------------------------------------*-
  506. Function:
  507. Race_SetInterior
  508. Params:
  509. raceid - Race to set for.
  510. interior - Interior where race is located.
  511. Return:
  512. -
  513. Notes:
  514. AFAIK you can't drive between interiors so all the
  515. checkpoints must be located in the same interior.
  516. -*----------------------------------------------------------------------------*/
  517. global void:Race_SetInterior(raceid, interior)
  518. {
  519. if (!Race_IsValid(raceid)) return;
  520. YSI_g_sRaceData[raceid][E_RACE_INT] = interior;
  521. }
  522. /*----------------------------------------------------------------------------*-
  523. Function:
  524. Race_SetWorld
  525. Params:
  526. raceid - Race to set for.
  527. world - World to run race in.
  528. Return:
  529. -
  530. Notes:
  531. -
  532. -*----------------------------------------------------------------------------*/
  533. global void:Race_SetWorld(raceid, world)
  534. {
  535. if (!Race_IsValid(raceid)) return;
  536. YSI_g_sRaceData[raceid][E_RACE_VW] = world;
  537. }
  538. /*----------------------------------------------------------------------------*-
  539. Function:
  540. Race_SetPrize
  541. Params:
  542. raceid - Race to set for.
  543. position - Winning position to set for/.
  544. amount - Amount for that position to win.
  545. Return:
  546. -
  547. Notes:
  548. If this is used after the race has started it will over-
  549. write prizes set by relative winnings.
  550. -*----------------------------------------------------------------------------*/
  551. global void:Race_SetPrize(raceid, position, amount)
  552. {
  553. if (!Race_IsValid(raceid) || position >= MAX_RACE_WINNERS) return;
  554. YSI_g_sRaceData[raceid][E_RACE_PRIZES][position - 1] = amount;
  555. }
  556. /*----------------------------------------------------------------------------*-
  557. Function:
  558. Race_Set_ExitTime
  559. Params:
  560. raceid - Race to set for.
  561. time - Time to set.
  562. Return:
  563. -
  564. Notes:
  565. Sets the time you are allowed out a vehicle before you
  566. fail the race. 0 means a vehicle exit is an instant fail.
  567. Useful for long races where cars may well be destroyed.
  568. -*----------------------------------------------------------------------------*/
  569. global void:Race_SetExitTime(raceid, time)
  570. {
  571. if (!Race_IsValid(raceid)) return;
  572. YSI_g_sRaceData[raceid][E_RACE_FLAGS] = (YSI_g_sRaceData[raceid][E_RACE_FLAGS] & (~e_RACE_FLAGS_EXIT_TIME)) | (e_RACE_FLAGS:time & e_RACE_FLAGS_EXIT_TIME);
  573. }
  574. /*----------------------------------------------------------------------------*-
  575. Function:
  576. Race_IsActive
  577. Params:
  578. raceid - Race to check.
  579. Return:
  580. -
  581. Notes:
  582. Wrapper for Race_IsValid.
  583. -*----------------------------------------------------------------------------*/
  584. global Race_IsActive(raceid)
  585. {
  586. return Race_IsValid(raceid);
  587. }
  588. /*----------------------------------------------------------------------------*-
  589. Function:
  590. Race_SetLaps
  591. Params:
  592. raceid - Race to set for.
  593. laps - Number of laps to set.
  594. Return:
  595. -
  596. Notes:
  597. -
  598. -*----------------------------------------------------------------------------*/
  599. global void:Race_SetLaps(raceid, laps)
  600. {
  601. if (!Race_IsValid(raceid)) return;
  602. YSI_g_sRaceData[raceid][E_RACE_LAPS] = laps;
  603. }
  604. /*----------------------------------------------------------------------------*-
  605. Function:
  606. Race_SetEntry
  607. Params:
  608. raceid - Race to set for.
  609. cost - Cost of entry to the race.
  610. Return:
  611. -
  612. Notes:
  613. -
  614. -*----------------------------------------------------------------------------*/
  615. global void:Race_SetEntry(raceid, cost)
  616. {
  617. if (!Race_IsValid(raceid)) return;
  618. YSI_g_sRaceData[raceid][E_RACE_ENTRY] = cost;
  619. }
  620. /*----------------------------------------------------------------------------*-
  621. Function:
  622. Race_Dropout
  623. Params:
  624. playerid - Player dropping out.
  625. Return:
  626. -
  627. Notes:
  628. Called when a player exits their vehicle.
  629. -*----------------------------------------------------------------------------*/
  630. _Y_RACES_STATIC Race_Dropout(playerid)
  631. {
  632. SetTimerEx("Race_Timeout", (YSI_g_sRaceData[(YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_RACE])][E_RACE_FLAGS] & e_RACE_FLAGS_EXIT_TIME), 0, "i", playerid);
  633. YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_RACE] |= RACE_PLAYER_OUT;
  634. YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_TOUT] = GetTickCount();
  635. }
  636. /*----------------------------------------------------------------------------*-
  637. Function:
  638. Race_Rejoin
  639. Params:
  640. playerid - Player rejoining.
  641. Return:
  642. -
  643. Notes:
  644. Called when a player gets in a new vehicle if not timmed
  645. out..
  646. -*----------------------------------------------------------------------------*/
  647. _Y_RACES_STATIC Race_Rejoin(playerid)
  648. {
  649. YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_RACE] &= ~RACE_PLAYER_OUT;
  650. }
  651. /*----------------------------------------------------------------------------*-
  652. Function:
  653. Race_Timeout
  654. Params:
  655. playerid - Player to check.
  656. Return:
  657. -
  658. Notes:
  659. Called from Race_Dropout after the race's exit time. If
  660. the player still isn't in a vehicle (set by Race_Rejoin) the
  661. player fails the race.
  662. -*----------------------------------------------------------------------------*/
  663. public Race_Timeout(playerid)
  664. {
  665. if (YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_RACE] & RACE_PLAYER_OUT) Race_Exit(playerid);
  666. }
  667. /*----------------------------------------------------------------------------*-
  668. Function:
  669. Race_Exit
  670. Params:
  671. playerid - Player who left.
  672. Return:
  673. -
  674. Notes:
  675. Called when a player leaves a race prematurly.
  676. -*----------------------------------------------------------------------------*/
  677. _Y_RACES_STATIC Race_Exit(playerid)
  678. {
  679. DisablePlayerRaceCheckpoint(playerid);
  680. new
  681. slot = YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_RACE];
  682. Race_PlayerDone(playerid);
  683. CallRemoteFunction("OnPlayerExitRace", "ii", playerid, slot);
  684. Race_CheckEnd(slot);
  685. }
  686. /*----------------------------------------------------------------------------*-
  687. Function:
  688. Race_CheckEnd
  689. Params:
  690. slot - Race to check.
  691. Return:
  692. -
  693. Notes:
  694. Called whenever a player leaves the race, checks the
  695. number of remaining racers and if none ends the race.
  696. -*----------------------------------------------------------------------------*/
  697. _Y_RACES_STATIC Race_CheckEnd(slot)
  698. {
  699. // This shouldn't be here...
  700. //YSI_g_sRaceData[slot][E_RACE_RACER_COUNT]--;
  701. if (!(--YSI_g_sRaceData[slot][E_RACE_RACER_COUNT]))
  702. {
  703. CallRemoteFunction("OnRaceEnd", "i", slot);
  704. if (YSI_g_sRaceData[slot][E_RACE_FLAGS] & e_RACE_FLAGS_RESTART)
  705. {
  706. YSI_g_sRaceData[slot][E_RACE_FLAGS] &= ~e_RACE_FLAGS_STARTED;
  707. YSI_g_sRaceData[slot][E_RACE_FINISHED] = 0;
  708. new
  709. count = YSI_g_sRaceData[slot][E_RACE_CHECKPOINTS],
  710. start = YSI_g_sRaceData[slot][E_RACE_CP_START];
  711. RaceArray_Shift(start + count, YSI_g_sCPIndex, start);
  712. RaceArray_IndexShift(start, -count);
  713. // Reset groups.
  714. NO_GROUPS(slot)
  715. {
  716. }
  717. }
  718. else
  719. {
  720. YSI_g_sRaceData[slot][E_RACE_FLAGS] = e_RACE_FLAGS:0;
  721. }
  722. }
  723. }
  724. /*----------------------------------------------------------------------------*-
  725. Function:
  726. Race_PlayerDone
  727. Params:
  728. playerid - Player done.
  729. Return:
  730. -
  731. Notes:
  732. Generic cleanup for anyone who has left a race. Sets
  733. the player back to their old position and sets a few other
  734. variables.
  735. -*----------------------------------------------------------------------------*/
  736. _Y_RACES_STATIC Race_PlayerDone(playerid)
  737. {
  738. new
  739. race = YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_RACE];
  740. YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_RACE] = NO_RACE;
  741. YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_TIME] = GetTickCount() - YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_TIME];
  742. #if defined RACE_POSITION
  743. YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_POSITION] = 0;
  744. #endif
  745. if (Race_IsValid(race))
  746. {
  747. PA_Set(YSI_g_sRacers[race], playerid, false);
  748. Iter_Remove(YSI_g_sRacePeople[race], playerid);
  749. if (IsPlayerConnected(playerid))
  750. {
  751. //SetPlayerPos(playerid, YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_X], YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_Y], YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_Z]);
  752. //SetPlayerFacingAngle(playerid, YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_A]);
  753. new
  754. vehicleid;
  755. if ((vehicleid = GetPlayerVehicleID(playerid)))
  756. {
  757. SetVehiclePos(vehicleid, YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_X], YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_Y], YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_Z]);
  758. SetVehicleZAngle(vehicleid, YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_A]);
  759. LinkVehicleToInterior(vehicleid, YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_INT]);
  760. SetVehicleVirtualWorld(vehicleid, YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_WORLD]);
  761. }
  762. else
  763. {
  764. SetPlayerPos(playerid, YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_X], YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_Y], YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_Z]);
  765. SetPlayerFacingAngle(playerid, YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_A]);
  766. }
  767. SetPlayerInterior(playerid, YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_INT]);
  768. SetPlayerVirtualWorld(playerid, YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_WORLD]);
  769. }
  770. }
  771. }
  772. /*----------------------------------------------------------------------------*-
  773. Function:
  774. Race_GetPlayerExitedTime
  775. Params:
  776. playerid - Player to get time of.
  777. Return:
  778. The time a player has been out a vehicle.
  779. Notes:
  780. -
  781. -*----------------------------------------------------------------------------*/
  782. global Race_GetPlayerExitedTime(playerid)
  783. {
  784. return GetTickCount() - YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_TOUT];
  785. }
  786. /*----------------------------------------------------------------------------*-
  787. Function:
  788. Race_PlayerJoin
  789. Params:
  790. playerid - Player to add.
  791. race - Race to add to.
  792. Return:
  793. -
  794. Notes:
  795. Checks if a player is valid to join a race and if the race
  796. is valid to be joined to and if so adds them to it.
  797. -*----------------------------------------------------------------------------*/
  798. global Race_PlayerJoin(playerid, race)
  799. {
  800. if (YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_RACE] != NO_RACE ||
  801. !Race_IsValid(race)) return 0;
  802. new
  803. e_RACE_FLAGS:flags = YSI_g_sRaceData[race][E_RACE_FLAGS];
  804. if ((flags & e_RACE_FLAGS_STARTED) ||
  805. YSI_g_sRaceData[race][E_RACE_RACER_COUNT] >= YSI_g_sRaceData[race][E_RACE_RACER_MAX] ||
  806. GetPlayerMoney(playerid) < YSI_g_sRaceData[race][E_RACE_ENTRY]) return 0;
  807. GivePlayerMoney(playerid, 0 - YSI_g_sRaceData[race][E_RACE_ENTRY]);
  808. YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_RACE] = race;
  809. YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_LAP] = 0;
  810. YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_CP] = 0;
  811. PA_Set(YSI_g_sRacers[race], playerid, true);
  812. ++YSI_g_sRaceData[race][E_RACE_RACER_COUNT];
  813. Iter_Add(YSI_g_sRacePeople[race], playerid);
  814. #if defined RACE_POSITION
  815. YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_POSITION] = 0;
  816. #endif
  817. return 1;
  818. }
  819. /*----------------------------------------------------------------------------*-
  820. Function:
  821. Race_PlayerLeave
  822. Params:
  823. playerid - Player to leave the race.
  824. refund - Wether or not to give them their entry fee back.
  825. Return:
  826. -
  827. Notes:
  828. Called if a player leaves a race before the race has
  829. started.
  830. -*----------------------------------------------------------------------------*/
  831. foreign _Race_PlayerLeave(playerid, refund);
  832. stock Race_PlayerLeave(playerid, bool:refund = false)
  833. {
  834. return _Race_PlayerLeave(playerid, _:refund);
  835. }
  836. global _Race_PlayerLeave(playerid, refund)
  837. {
  838. new
  839. race = YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_RACE];
  840. if (!Race_IsValid(race) || YSI_g_sRaceData[race][E_RACE_FLAGS] & e_RACE_FLAGS_STARTED) return 0;
  841. if (refund) GivePlayerMoney(playerid, YSI_g_sRaceData[race][E_RACE_ENTRY]);
  842. YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_RACE] = NO_RACE;
  843. PA_Set(YSI_g_sRacers[race], playerid, false);
  844. --YSI_g_sRaceData[race][E_RACE_RACER_COUNT];
  845. Iter_Remove(YSI_g_sRacePeople[race], playerid);
  846. return 1;
  847. }
  848. /*----------------------------------------------------------------------------*-
  849. Function:
  850. Race_Finish
  851. Params:
  852. playerid - Player who finished the race.
  853. Return:
  854. -
  855. Notes:
  856. Called when a player completes a race.
  857. -*----------------------------------------------------------------------------*/
  858. _Y_RACES_STATIC Race_Finish(playerid)
  859. {
  860. new
  861. slot = YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_RACE],
  862. winners = YSI_g_sRaceData[slot][E_RACE_FINISHED];
  863. YSI_g_sRaceData[slot][E_RACE_FINISHED]++;
  864. Race_PlayerDone(playerid);
  865. new
  866. prize;
  867. if (winners < MAX_RACE_WINNERS) prize = YSI_g_sRaceData[slot][E_RACE_PRIZES][winners];
  868. GivePlayerMoney(playerid, prize);
  869. CallRemoteFunction("OnPlayerFinishRace", "iiiii", playerid, slot, winners + 1, prize, YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_TIME]);
  870. Race_CheckEnd(slot);
  871. }
  872. /*----------------------------------------------------------------------------*-
  873. Function:
  874. Race_Start
  875. Params:
  876. race - Race to start.
  877. Return:
  878. -
  879. Notes:
  880. Loops through all players who have entered the race and
  881. moves them to their respective start points. If the prize
  882. is set as relative the prizes are calculated here based on
  883. number of entrants, number of possible winners and entry
  884. fee.
  885. -*----------------------------------------------------------------------------*/
  886. global Race_Start(race)
  887. {
  888. if (!Race_IsValid(race)) return 0;
  889. new
  890. bool:exited = true,
  891. j;
  892. foreach (new i : YSI_g_sRacePeople[race])
  893. {
  894. new
  895. vehicleid;
  896. GetPlayerPos(i, YSI_g_sPlayerRace[i][E_RACE_PLAYER_X], YSI_g_sPlayerRace[i][E_RACE_PLAYER_Y], YSI_g_sPlayerRace[i][E_RACE_PLAYER_Z]);
  897. if ((vehicleid = GetPlayerVehicleID(i)))
  898. {
  899. GetPlayerFacingAngle(i, YSI_g_sPlayerRace[i][E_RACE_PLAYER_A]);
  900. YSI_g_sPlayerRace[i][E_RACE_PLAYER_INT] = GetPlayerInterior(i);
  901. YSI_g_sPlayerRace[i][E_RACE_PLAYER_WORLD] = GetPlayerVirtualWorld(i);
  902. LinkVehicleToInterior(vehicleid, YSI_g_sRaceData[race][E_RACE_INT]);
  903. SetVehicleVirtualWorld(vehicleid, YSI_g_sRaceData[race][E_RACE_VW]);
  904. SetPlayerInterior(i, YSI_g_sRaceData[race][E_RACE_INT]);
  905. SetPlayerVirtualWorld(i, YSI_g_sRaceData[race][E_RACE_VW]);
  906. SetVehiclePos(vehicleid, YSI_g_sRaceStarts[race][j % MAX_RACE_STARTS][0], YSI_g_sRaceStarts[race][j % MAX_RACE_STARTS][1], YSI_g_sRaceStarts[race][j % MAX_RACE_STARTS][2]);
  907. SetVehicleZAngle(vehicleid, YSI_g_sRaceStarts[race][j % MAX_RACE_STARTS][3]);
  908. SetCameraBehindPlayer(i);
  909. TogglePlayerControllable(i, 0);
  910. ++j;
  911. }
  912. else
  913. {
  914. exited = false;
  915. Race_Exit(i);
  916. }
  917. }
  918. if (j)
  919. {
  920. YSI_g_sRaceData[race][E_RACE_FLAGS] |= e_RACE_FLAGS_STARTED;
  921. Race_Countdown(race, YSI_g_sRaceData[race][E_RACE_COUNTDOWN]);
  922. if (YSI_g_sRaceData[race][E_RACE_FLAGS] & e_RACE_FLAGS_REL_WIN)
  923. {
  924. new
  925. prize;
  926. if (j < MAX_RACE_WINNERS) prize = ((j * j) + j) / 2;
  927. else prize = (MAX_RACE_WINNERS * (MAX_RACE_WINNERS + 1)) / 2;
  928. new
  929. count = (YSI_g_sRaceData[race][E_RACE_ENTRY] * j) / prize;
  930. for (new i = 0; i < MAX_RACE_WINNERS; i++) YSI_g_sRaceData[race][E_RACE_PRIZES][i] = (MAX_RACE_WINNERS - i) * count;
  931. }
  932. return 1;
  933. }
  934. else if (exited)
  935. {
  936. // No players were in to begin with.
  937. YSI_g_sRaceData[race][E_RACE_RACER_COUNT] = 1;
  938. Race_CheckEnd(race);
  939. }
  940. return 0;
  941. }
  942. /*----------------------------------------------------------------------------*-
  943. Function:
  944. Race_Countdown
  945. Params:
  946. race - Race to do countdown for.
  947. time - Seconds remaining.
  948. Return:
  949. -
  950. Notes:
  951. -
  952. -*----------------------------------------------------------------------------*/
  953. public Race_Countdown(race, time)
  954. {
  955. if (!(YSI_g_sRaceData[race][E_RACE_FLAGS] & e_RACE_FLAGS_ACTIVE)) return;
  956. if (time)
  957. {
  958. Text_Send(YSI_g_sRacers[race], $YSI_RACE_COUNTDOWN, time);
  959. SetTimerEx("Race_Countdown", 1000, 0, "ii", race, time - 1);
  960. }
  961. else
  962. {
  963. Text_Send(YSI_g_sRacers[race], $YSI_RACE_GO);
  964. new
  965. startTime = GetTickCount(),
  966. vehicleid,
  967. pos;
  968. foreach (new i : YSI_g_sRacePeople[race])
  969. {
  970. if ((vehicleid = GetPlayerVehicleID(i)))
  971. {
  972. TogglePlayerControllable(i, 1);
  973. Race_DoEnterRaceCP(i);
  974. SetVehiclePos(vehicleid, YSI_g_sRaceStarts[race][pos % MAX_RACE_STARTS][0], YSI_g_sRaceStarts[race][pos % MAX_RACE_STARTS][1], YSI_g_sRaceStarts[race][pos % MAX_RACE_STARTS][2] + 0.1);
  975. SetVehicleZAngle(vehicleid, YSI_g_sRaceStarts[race][pos % MAX_RACE_STARTS][3]);
  976. YSI_g_sPlayerRace[i][E_RACE_PLAYER_TIME] = startTime;
  977. pos++;
  978. }
  979. else Race_Exit(i);
  980. }
  981. }
  982. }
  983. /*----------------------------------------------------------------------------*-
  984. Function:
  985. Race_Race
  986. Params:
  987. -
  988. Return:
  989. -
  990. Notes:
  991. Sets up important variables
  992. -*----------------------------------------------------------------------------*/
  993. mhook OnScriptInit()
  994. {
  995. for (new i = 0; i < MAX_PLAYERS; i++)
  996. {
  997. YSI_g_sPlayerRace[i][E_RACE_PLAYER_RACE] = NO_RACE;
  998. }
  999. Iter_Init(YSI_g_sRacePeople);
  1000. Races_SetupGroups();
  1001. return 1;
  1002. }
  1003. /*----------------------------------------------------------------------------*-
  1004. Function:
  1005. Race_OnPlayerEnterRaceCheckpoint
  1006. Params:
  1007. playerid - Player who entered.
  1008. Return:
  1009. -
  1010. Notes:
  1011. Checks a players position in the race and displays the
  1012. corresponding next checkpoint or calls Race_Finish.
  1013. -*----------------------------------------------------------------------------*/
  1014. mhook OnPlayerEnterRaceCP(playerid)
  1015. {
  1016. return Race_DoEnterRaceCP(playerid);
  1017. }
  1018. _Y_RACES_STATIC Race_DoEnterRaceCP(playerid)
  1019. {
  1020. new
  1021. race = YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_RACE];
  1022. if (race & RACE_PLAYER_OUT) return 1;
  1023. // Race_IsValid check mixed with running check.
  1024. if ((0 <= race < MAX_RACES) && (YSI_g_sRaceData[race][E_RACE_FLAGS] & (e_RACE_FLAGS_ACTIVE | e_RACE_FLAGS_STARTED) == (e_RACE_FLAGS_ACTIVE | e_RACE_FLAGS_STARTED)))
  1025. {
  1026. DisablePlayerRaceCheckpoint(playerid);
  1027. new
  1028. start = YSI_g_sRaceData[race][E_RACE_CP_START],
  1029. check = YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_CP],
  1030. checks = YSI_g_sRaceData[race][E_RACE_CHECKPOINTS],
  1031. laps = YSI_g_sRaceData[race][E_RACE_LAPS],
  1032. type = _:(YSI_g_sRaceData[race][E_RACE_FLAGS] & e_RACE_FLAGS_ARIAL);
  1033. if (laps)
  1034. {
  1035. new
  1036. lap = YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_LAP];
  1037. if (lap == laps)
  1038. {
  1039. Race_Finish(playerid);
  1040. return 1;
  1041. }
  1042. else
  1043. {
  1044. if (check + 1 == checks)
  1045. {
  1046. if (lap + 1 == laps)
  1047. {
  1048. SetPlayerRaceCheckpoint(playerid, type ? 4 : 1, YSI_g_sRaceCheckpoints[start][0], YSI_g_sRaceCheckpoints[start][1], YSI_g_sRaceCheckpoints[start][2], 0.0, 0.0, 0.0, 5.0);
  1049. }
  1050. else
  1051. {
  1052. check += start;
  1053. SetPlayerRaceCheckpoint(playerid, type ? 3 : 0, YSI_g_sRaceCheckpoints[check][0], YSI_g_sRaceCheckpoints[check][1], YSI_g_sRaceCheckpoints[check][2], YSI_g_sRaceCheckpoints[start][0], YSI_g_sRaceCheckpoints[start][1], YSI_g_sRaceCheckpoints[start][2], 5.0);
  1054. }
  1055. YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_CP] = 0;
  1056. ++YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_LAP];
  1057. return 1;
  1058. }
  1059. else
  1060. {
  1061. check += start;
  1062. SetPlayerRaceCheckpoint(playerid, type ? 3 : 0, YSI_g_sRaceCheckpoints[check][0], YSI_g_sRaceCheckpoints[check][1], YSI_g_sRaceCheckpoints[check][2], YSI_g_sRaceCheckpoints[check + 1][0], YSI_g_sRaceCheckpoints[check + 1][1], YSI_g_sRaceCheckpoints[check + 1][2], 5.0);
  1063. ++YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_CP];
  1064. return 1;
  1065. }
  1066. }
  1067. }
  1068. else
  1069. {
  1070. switch (checks - check)
  1071. {
  1072. case 0:
  1073. {
  1074. Race_Finish(playerid);
  1075. }
  1076. case 1:
  1077. {
  1078. check += start;
  1079. SetPlayerRaceCheckpoint(playerid, type ? 4 : 1, YSI_g_sRaceCheckpoints[check][0], YSI_g_sRaceCheckpoints[check][1], YSI_g_sRaceCheckpoints[check][2], 0.0, 0.0, 0.0, 5.0);
  1080. }
  1081. default:
  1082. {
  1083. check += start;
  1084. SetPlayerRaceCheckpoint(playerid, type ? 3 : 0, YSI_g_sRaceCheckpoints[check][0], YSI_g_sRaceCheckpoints[check][1], YSI_g_sRaceCheckpoints[check][2], YSI_g_sRaceCheckpoints[check + 1][0], YSI_g_sRaceCheckpoints[check + 1][1], YSI_g_sRaceCheckpoints[check + 1][2], 5.0);
  1085. }
  1086. }
  1087. ++YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_CP];
  1088. return 1;
  1089. }
  1090. }
  1091. return 1;
  1092. }
  1093. /*----------------------------------------------------------------------------*-
  1094. Function:
  1095. Race_OnPlayerStateChange
  1096. Params:
  1097. playerid - Player who's state changed.
  1098. newstate - Their new state.
  1099. oldstate - Their last state.
  1100. Return:
  1101. -
  1102. Notes:
  1103. Processes a players vehicle exit or entry mid race and
  1104. calls the relevant functions.
  1105. -*----------------------------------------------------------------------------*/
  1106. mhook OnPlayerStateChange(playerid, newstate, oldstate)
  1107. {
  1108. new
  1109. race = YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_RACE];
  1110. if (!Race_IsValid(race) || !(YSI_g_sRaceData[race][E_RACE_FLAGS] & e_RACE_FLAGS_STARTED)) return 0;
  1111. if (oldstate == PLAYER_STATE_DRIVER)
  1112. {
  1113. if (!(YSI_g_sRaceData[race][E_RACE_FLAGS] & e_RACE_FLAGS_EXIT_TIME) || newstate != PLAYER_STATE_EXIT_VEHICLE) Race_Exit(playerid);
  1114. else Race_Dropout(playerid);
  1115. }
  1116. else if (newstate == PLAYER_STATE_DRIVER) Race_Rejoin(playerid);
  1117. else if (newstate != PLAYER_STATE_ONFOOT && newstate != PLAYER_STATE_ENTER_VEHICLE_DRIVER) Race_Exit(playerid);
  1118. return 1;
  1119. }
  1120. /*----------------------------------------------------------------------------*-
  1121. Function:
  1122. Race_OnPlayerDisconnect
  1123. Params:
  1124. playerid - Player who left.
  1125. reason - Why they left.
  1126. Return:
  1127. -
  1128. Notes:
  1129. Similar to the Race_OnPlayerStateChange function but
  1130. instantly exits them from the race as they're not there
  1131. anymore.
  1132. -*----------------------------------------------------------------------------*/
  1133. mhook OnPlayerDisconnect(playerid, reason)
  1134. {
  1135. new
  1136. race = YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_RACE];
  1137. if (!Race_IsValid(race)) return 0;
  1138. if (YSI_g_sRaceData[race][E_RACE_FLAGS] & e_RACE_FLAGS_STARTED)
  1139. {
  1140. Race_Exit(playerid);
  1141. }
  1142. else
  1143. {
  1144. Race_PlayerLeave(playerid);
  1145. }
  1146. return 1;
  1147. #pragma unused reason
  1148. }
  1149. /*----------------------------------------------------------------------------*-
  1150. Function:
  1151. Race_OnPlayerConnect
  1152. Params:
  1153. playerid - Player who joined.
  1154. Return:
  1155. -
  1156. Notes:
  1157. Just a fix for IsPlayerInRaceCheckpoint.
  1158. -*----------------------------------------------------------------------------*/
  1159. mhook OnPlayerConnect(playerid)
  1160. {
  1161. DisablePlayerRaceCheckpoint(playerid);
  1162. return 1;
  1163. }
  1164. #if defined RACE_POSITION
  1165. /*----------------------------------------------------------------------------*-
  1166. Function:
  1167. Race_Loop
  1168. Params:
  1169. -
  1170. Return:
  1171. -
  1172. Notes:
  1173. If compiled with RACE_POSITION this function will
  1174. keep track of all player's positions in their race. It uses
  1175. current lap, checkpoint and distance from next
  1176. checkpoint to approximate position.
  1177. Note: If a race doubles back between two checkpoints
  1178. you may be closer than another player thus show as a
  1179. higher position when you are infact behind them.
  1180. -*----------------------------------------------------------------------------*/
  1181. #if YSIM_HAS_MASTER && (_YSIM_IS_CLIENT || _YSIM_IS_STUB)
  1182. stock Race_Loop()
  1183. #else
  1184. task Race_Loop[500 / MAX_RACES]()
  1185. #endif
  1186. {
  1187. static
  1188. race = -1;
  1189. // Process a different race every call.
  1190. race = (race + 1) % MAX_RACES;
  1191. static
  1192. racePos[MAX_PLAYERS][E_RACE_POS];
  1193. if (Race__IsActive(race))
  1194. {
  1195. new
  1196. start = YSI_g_sRaceData[race][E_RACE_CP_START],
  1197. lap,
  1198. cp = Iter_Count(YSI_g_sRacePeople[race]),
  1199. Float:togo,
  1200. pos;
  1201. if (!cp)
  1202. {
  1203. return;
  1204. }
  1205. foreach (new playerid : YSI_g_sRacePeople[race])
  1206. {
  1207. lap = YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_LAP],
  1208. cp = YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_CP] + start;
  1209. static
  1210. Float:x,
  1211. Float:y,
  1212. Float:z;
  1213. GetPlayerPos(playerid, x, y, z);
  1214. // Get the player's (squared) distance to the next checkpoint.
  1215. x -= YSI_g_sRaceCheckpoints[cp][0];
  1216. y -= YSI_g_sRaceCheckpoints[cp][1];
  1217. z -= YSI_g_sRaceCheckpoints[cp][2];
  1218. togo = ((x * x) + (y * y) + (z * z)),
  1219. pos = 1;
  1220. racePos[playerid][E_RACE_POS_CP] = cp;
  1221. racePos[playerid][E_RACE_POS_TOGO] = togo;
  1222. for (new i = Iter_Begin(YSI_g_sRacePeople[race]); (i = Iter_Next(YSI_g_sRacePeople[race], i)) != playerid; )
  1223. {
  1224. // This checks "checkpoint + start", but both players have
  1225. // that offset so it is fine.
  1226. if (YSI_g_sPlayerRace[i][E_RACE_PLAYER_LAP] > lap ||
  1227. (YSI_g_sPlayerRace[i][E_RACE_PLAYER_LAP] == lap &&
  1228. (racePos[i][E_RACE_POS_CP] > cp ||
  1229. (racePos[i][E_RACE_POS_CP] == cp && racePos[i][E_RACE_POS_TOGO] < togo)))) ++pos;
  1230. // This player is on a higher lap, or on a higher
  1231. // checkpoint, or less distance from their next checkpoint.
  1232. else ++YSI_g_sPlayerRace[i][E_RACE_PLAYER_POSITION];
  1233. }
  1234. YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_POSITION] = pos;
  1235. }
  1236. #if defined RACE_SHOW_POS
  1237. // Race time.
  1238. lap = Race_GetPlayerRaceTime(Iter_First(YSI_g_sRacePeople[race])) / 1000;
  1239. // Racer count.
  1240. cp = Iter_Count(YSI_g_sRacePeople[race]);
  1241. new
  1242. time[8],
  1243. th[3];
  1244. format(time, sizeof (time), "%d:%02d", lap / 60, lap % 60);
  1245. foreach (new playerid : YSI_g_sRacePeople[race])
  1246. {
  1247. pos = YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_POSITION];
  1248. switch (pos % 20)
  1249. {
  1250. case 1: th = "ST";
  1251. case 2: th = "ND";
  1252. case 3: th = "RD";
  1253. case 11: if (pos % 100 > 20) th = "TH"; else th = "ST";
  1254. case 12: if (pos % 100 > 20) th = "TH"; else th = "ND";
  1255. case 13: if (pos % 100 > 20) th = "TH"; else th = "RD";
  1256. default: th = "TH";
  1257. }
  1258. // Show the background.
  1259. // Show the position.
  1260. // Show the "th".
  1261. // Show the races count.
  1262. // Show the time.
  1263. }
  1264. #endif
  1265. }
  1266. }
  1267. /*----------------------------------------------------------------------------*-
  1268. Function:
  1269. Race_GetPlayerPosition
  1270. Params:
  1271. playerid - Player to get position of.
  1272. Return:
  1273. Dynamic position in race.
  1274. Notes:
  1275. -
  1276. -*----------------------------------------------------------------------------*/
  1277. global Race_GetPlayerPosition(playerid)
  1278. {
  1279. return YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_POSITION];
  1280. }
  1281. #endif
  1282. /*----------------------------------------------------------------------------*-
  1283. Function:
  1284. Race_GetPlayerRaceTime
  1285. Params:
  1286. playerid - Player to get time for.
  1287. Return:
  1288. Time in race so far.
  1289. Notes:
  1290. -
  1291. -*----------------------------------------------------------------------------*/
  1292. global Race_GetPlayerRaceTime(playerid)
  1293. {
  1294. return GetTickCount() - YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_TIME];
  1295. }
  1296. /*----------------------------------------------------------------------------*-
  1297. Function:
  1298. Race_GetPlayerRace
  1299. Params:
  1300. playerid - Player to get race of.
  1301. Return:
  1302. Player's race.
  1303. Notes:
  1304. -
  1305. -*----------------------------------------------------------------------------*/
  1306. global Race_GetPlayerRace(playerid)
  1307. {
  1308. if (VALID_PLAYERID(playerid)) return YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_RACE];
  1309. return NO_RACE;
  1310. }
  1311. /*----------------------------------------------------------------------------*-
  1312. Function:
  1313. Race_SetPlayer
  1314. Params:
  1315. race - Which race to add them to.
  1316. playerid - Player to set in the race.
  1317. bool:set - Add or remove them.
  1318. Return:
  1319. -
  1320. Notes:
  1321. -
  1322. -*----------------------------------------------------------------------------*/
  1323. global Race_SetPlayer(race, playerid, bool:set)
  1324. {
  1325. if (Race_IsValid(race))
  1326. {
  1327. if (set)
  1328. {
  1329. if (!(YSI_g_sRaceData[race][E_RACE_FLAGS] & e_RACE_FLAGS_STARTED))
  1330. {
  1331. Race_PlayerJoin(playerid, race);
  1332. return 1;
  1333. }
  1334. }
  1335. else if (race == YSI_g_sPlayerRace[playerid][E_RACE_PLAYER_RACE])
  1336. {
  1337. if (YSI_g_sRaceData[race][E_RACE_FLAGS] & e_RACE_FLAGS_STARTED)
  1338. {
  1339. Race_Exit(playerid);
  1340. }
  1341. else
  1342. {
  1343. Race_PlayerLeave(playerid);
  1344. }
  1345. return 1;
  1346. }
  1347. }
  1348. return 0;
  1349. }
  1350. // Called when a player finishes the race.
  1351. forward OnPlayerFinishRace(playerid, race, position, prize, time);
  1352. // Called when a player drops out of the race.
  1353. forward OnPlayerExitRace(playerid, race);
  1354. // Called when the race is over.
  1355. forward OnRaceEnd(race);