HLMOD.HU Forrás Megtekintés - www.hlmod.hu
  1. #include <amxmodx>
  2. #include <amxmisc>
  3. #include <engine>
  4. #include <maths>
  5.  
  6. #pragma semicolon 1;
  7.  
  8. #define PLUGIN "Clock Maker"
  9. #define VERSION "1.1"
  10. #define AUTHOR "Necro"
  11.  
  12. #define ADMIN_LEVEL ADMIN_MENU //admin hozzaferes, ezt hasznalja a plug. ADMIN_MENU = flag 'u'
  13. #define MAIN_MENU_KEYS (1<<0)|(1<<1)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)|(1<<9)
  14.  
  15. /* enum for menu selections */
  16. enum { N1, N2, N3, N4, N5, N6, N7, N8, N9, N0 };
  17. new const X = 0;
  18. new const Y = 1;
  19. new const Z = 2; //for some reason I got tag mismatch on Z when using an enum
  20.  
  21. new gszMainMenuText[256];
  22. new const gszClockFaces[] = "sprites/clock_faces.spr";
  23. new const gszClockDigits[] = "sprites/clock_digits.spr";
  24. new const gszPrefix[] = "[CM] ";
  25. new const gszInfoTarget[] = "info_target";
  26. new const gszClockClassname[] = "cm_clock";
  27. new const gszClockDigitClassname[] = "cm_clockdigit";
  28. new const Float:gfDigitOffsetMultipliers[4] = {0.725, 0.275, 0.3, 0.75};
  29. new const Float:gfClockSize[2] = {80.0, 32.0};
  30. new const Float:gfTitleSize = 16.0;
  31.  
  32. new gszTime[5];
  33. new gszFile[128];
  34. new gTimeOffsetOld;
  35. new gHourTypeOld;
  36.  
  37. const gClockTypesMax = 2;
  38.  
  39. //clock types
  40. enum
  41. {
  42. CM_SERVERTIME,
  43. CM_MAPTIMELEFT
  44. };
  45.  
  46. new gClockSaveIds[gClockTypesMax] =
  47. {
  48. 'C', 'T'
  49. };
  50.  
  51. public plugin_init()
  52. {
  53. register_plugin(PLUGIN, VERSION, AUTHOR);
  54.  
  55. //CVARs
  56. register_cvar("cm_hourtype", "1"); //0: 12 oras, 1: 24 oras
  57. register_cvar("cm_hourannounce", "1"); //egeszkor bemondja az idot
  58. register_cvar("cm_timeoffset", "0"); //eltolja az idot egy kul. idozonaba, +/- ora
  59.  
  60. //menuk
  61. register_menucmd(register_menuid("clockMainMenu"), MAIN_MENU_KEYS, "handleMainMenu");
  62.  
  63. //commandok
  64. register_clcmd("say /cm", "showClockMenu", ADMIN_LEVEL);
  65. }
  66.  
  67. public plugin_precache()
  68. {
  69. precache_model(gszClockFaces);
  70. precache_model(gszClockDigits);
  71. }
  72.  
  73. public plugin_cfg()
  74. {
  75. //create the main menu
  76. new size = sizeof(gszMainMenuText);
  77. add(gszMainMenuText, size, "\yIdovetito Menu^n^n");
  78. add(gszMainMenuText, size, "\r1. \wSzerver ido mutatasa^n");
  79. add(gszMainMenuText, size, "\r2. \wVisszalevo ido mutatasa^n^n");
  80. add(gszMainMenuText, size, "\r4. \wOra torlese^n^n");
  81. add(gszMainMenuText, size, "\r5. \wNagyitas^n");
  82. add(gszMainMenuText, size, "\r6. \wKicsinyites^n^n");
  83. add(gszMainMenuText, size, "\r7. \wOra mentese^n");
  84. add(gszMainMenuText, size, "\r8. \wOra betoltese^n^n");
  85. add(gszMainMenuText, size, "\r0. \wBezaras^n");
  86.  
  87. //store current CVAR values (so we can check if they get changed)
  88. gTimeOffsetOld = get_cvar_num("cm_timeoffset");
  89. gHourTypeOld = get_cvar_num("cm_hourtype");
  90.  
  91. //make save folder in basedir
  92. new szDir[64];
  93. new szMap[32];
  94.  
  95. get_basedir(szDir, 64);
  96. add(szDir, 64, "/clockmaker");
  97.  
  98. //create the folder is it doesn't exist
  99. if (!dir_exists(szDir))
  100. {
  101. mkdir(szDir);
  102. }
  103.  
  104. get_mapname(szMap, 32);
  105. formatex(gszFile, 96, "%s/%s.cm", szDir, szMap);
  106.  
  107. //load the clocks
  108. loadClocks(0);
  109.  
  110. //set a task to update the clocks (every second is frequent enough)
  111. set_task(1.0, "taskUpdateClocks", 0, "", 0, "b");
  112. }
  113.  
  114. public taskUpdateClocks()
  115. {
  116. new clock = -1;
  117.  
  118. //get the time digits
  119. new serverTimeDigits[4];
  120. new timeleftDigits[4];
  121. new bool:bUpdateServerTime = getTimeDigits(CM_SERVERTIME, serverTimeDigits);
  122. getTimeDigits(CM_MAPTIMELEFT, timeleftDigits);
  123.  
  124. //find all clock entities
  125. while ((clock = find_ent_by_class(clock, gszClockClassname)))
  126. {
  127. //get the clock type
  128. new clockType = entity_get_int(clock, EV_INT_groupinfo);
  129.  
  130. //if the time changed for this clocktype
  131. if (clockType == CM_SERVERTIME)
  132. {
  133. if (bUpdateServerTime)
  134. {
  135. //set the clock to the correct time
  136. set_clock_digits(clock, serverTimeDigits);
  137. }
  138. }
  139. else if (clockType == CM_MAPTIMELEFT)
  140. {
  141. //set the clock to show the timeleft
  142. set_clock_digits(clock, timeleftDigits);
  143. }
  144. }
  145.  
  146. //check to see if its on the hour
  147. if (bUpdateServerTime)
  148. {
  149. new hour, mins;
  150. time(hour, mins);
  151.  
  152. //if its on the hour then alert
  153. if (mins == 0)
  154. {
  155. alertHour(hour);
  156. }
  157. }
  158. }
  159.  
  160. public showClockMenu(id)
  161. {
  162. //show the main menu to the player
  163. show_menu(id, MAIN_MENU_KEYS, gszMainMenuText, -1, "clockMainMenu");
  164.  
  165. return PLUGIN_HANDLED;
  166. }
  167.  
  168. public handleMainMenu(id, num)
  169. {
  170. switch (num)
  171. {
  172. case N1: createClockAiming(id, CM_SERVERTIME);
  173. case N2: createClockAiming(id, CM_MAPTIMELEFT);
  174. case N4: deleteClockAiming(id);
  175. case N5: scaleClockAiming(id, 0.1);
  176. case N6: scaleClockAiming(id, -0.1);
  177. case N7: saveClocks(id);
  178. case N8: loadClocks(id);
  179. }
  180.  
  181. //show menu again
  182. if (num != N0)
  183. {
  184. showClockMenu(id);
  185. }
  186.  
  187. return PLUGIN_HANDLED;
  188. }
  189.  
  190. createClockAiming(id, clockType)
  191. {
  192. //make sure player has access to this command
  193. if (get_user_flags(id) & ADMIN_LEVEL)
  194. {
  195. new origin[3];
  196. new Float:vOrigin[3];
  197. new Float:vAngles[3];
  198. new Float:vNormal[3];
  199.  
  200. //get the origin of where the player is aiming
  201. get_user_origin(id, origin, 3);
  202. IVecFVec(origin, vOrigin);
  203.  
  204. new bool:bSuccess = traceClockAngles(id, vAngles, vNormal, 1000.0);
  205.  
  206. //if the trace was successfull
  207. if (bSuccess)
  208. {
  209. //if the plane the trace hit is vertical
  210. if (vNormal[2] == 0.0)
  211. {
  212. //create the clock
  213. new bool:bSuccess = createClock(clockType, vOrigin, vAngles, vNormal);
  214.  
  215. //if clock created successfully
  216. if (bSuccess)
  217. {
  218. client_print(id, print_chat, "%sCsinalt egy orat!", gszPrefix);
  219. }
  220. }
  221. else
  222. {
  223. client_print(id, print_chat, "%sAz orat a falra kell helyezned!", gszPrefix);
  224. }
  225. }
  226. else
  227. {
  228. client_print(id, print_chat, "%sMenj kozelebb a celhoz, hogy letre tudd hozni az orat", gszPrefix);
  229. }
  230. }
  231. }
  232.  
  233. bool:createClock(clockType, Float:vOrigin[3], Float:vAngles[3], Float:vNormal[3], Float:fScale = 1.0)
  234. {
  235. new clock = create_entity(gszInfoTarget);
  236. new digit[4];
  237. new bool:bFailed = false;
  238.  
  239. //create 4 new entities to use for digits on the clock
  240. for (new i = 0; i < 4; ++i)
  241. {
  242. digit[i] = create_entity(gszInfoTarget);
  243.  
  244. //if failed boolean is false and entity failed to create
  245. if (!bFailed && !is_valid_ent(digit[i]))
  246. {
  247. bFailed = true;
  248. break;
  249. }
  250. }
  251.  
  252. //make sure all entities were created successfully
  253. if (is_valid_ent(clock) && !bFailed)
  254. {
  255. //adjust the origin to lift the clock off the wall (prevent flickering)
  256. vOrigin[0] += (vNormal[0] * 0.5);
  257. vOrigin[1] += (vNormal[1] * 0.5);
  258. vOrigin[2] += (vNormal[2] * 0.5);
  259.  
  260. //set clock properties
  261. entity_set_string(clock, EV_SZ_classname, gszClockClassname);
  262. entity_set_int(clock, EV_INT_solid, SOLID_NOT);
  263. entity_set_model(clock, gszClockFaces);
  264. entity_set_vector(clock, EV_VEC_angles, vAngles);
  265. entity_set_float(clock, EV_FL_scale, fScale);
  266. entity_set_origin(clock, vOrigin);
  267. entity_set_int(clock, EV_INT_groupinfo, clockType);
  268.  
  269. //set the entity frame (clock face) depending on the clock type
  270. switch (clockType)
  271. {
  272. case CM_SERVERTIME: entity_set_float(clock, EV_FL_frame, 0.0);
  273. case CM_MAPTIMELEFT: entity_set_float(clock, EV_FL_frame, 1.0);
  274. }
  275.  
  276. //link the digits entities to the clock
  277. entity_set_int(clock, EV_INT_iuser1, digit[0]);
  278. entity_set_int(clock, EV_INT_iuser2, digit[1]);
  279. entity_set_int(clock, EV_INT_iuser3, digit[2]);
  280. entity_set_int(clock, EV_INT_iuser4, digit[3]);
  281.  
  282. new digitValues[4];
  283.  
  284. //setup the digits to make up the time
  285. for (new i = 0; i < 4; ++i)
  286. {
  287. //setup digit properties
  288. entity_set_string(digit[i], EV_SZ_classname, gszClockDigitClassname);
  289. entity_set_vector(digit[i], EV_VEC_angles, vAngles);
  290. entity_set_model(digit[i], gszClockDigits);
  291. entity_set_float(digit[i], EV_FL_scale, fScale);
  292.  
  293. //set digit position
  294. set_digit_origin(i, digit[i], vOrigin, vNormal, fScale);
  295.  
  296. //get the time digits
  297. getTimeDigits(clockType, digitValues);
  298.  
  299. //set the in-game clocks digits
  300. set_clock_digits(clock, digitValues);
  301. }
  302.  
  303. return true;
  304. }
  305. else
  306. {
  307. //delete clock face if it created successfully
  308. if (is_valid_ent(clock))
  309. {
  310. remove_entity(clock);
  311. }
  312.  
  313. //iterate though the entity array and delete whichever ones created successfully
  314. for (new i = 0; i < 4; ++i)
  315. {
  316. if (is_valid_ent(digit[i]))
  317. {
  318. remove_entity(digit[i]);
  319. }
  320. }
  321. }
  322.  
  323. return false;
  324. }
  325.  
  326. deleteClockAiming(id)
  327. {
  328. new bool:bDeleted;
  329. new clock = get_clock_aiming(id);
  330.  
  331. if (clock)
  332. {
  333. //delete the clock
  334. bDeleted = deleteClock(clock);
  335.  
  336. //if the clock was deleted successfully
  337. if (bDeleted)
  338. {
  339. client_print(id, print_chat, "%sTorolte az orat!", gszPrefix);
  340. }
  341. }
  342. }
  343.  
  344. bool:deleteClock(ent)
  345. {
  346. //if the entity is a clock
  347. if (isClock(ent))
  348. {
  349. //get entity IDs of digits on the clock
  350. new digit[4];
  351. digit[0] = entity_get_int(ent, EV_INT_iuser1);
  352. digit[1] = entity_get_int(ent, EV_INT_iuser2);
  353. digit[2] = entity_get_int(ent, EV_INT_iuser3);
  354. digit[3] = entity_get_int(ent, EV_INT_iuser4);
  355.  
  356. //delete the digits on the clock if they're valid
  357. if (is_valid_ent(digit[0])) remove_entity(digit[0]);
  358. if (is_valid_ent(digit[1])) remove_entity(digit[1]);
  359. if (is_valid_ent(digit[2])) remove_entity(digit[2]);
  360. if (is_valid_ent(digit[3])) remove_entity(digit[3]);
  361.  
  362. //delete the clock face
  363. remove_entity(ent);
  364.  
  365. //successfully deleted the clock
  366. return true;
  367. }
  368.  
  369. return false;
  370. }
  371.  
  372. scaleClockAiming(id, Float:fScaleAmount)
  373. {
  374. //get the clock the player is aiming at (if any)
  375. new clock = get_clock_aiming(id);
  376.  
  377. //if player is aiming at a clock
  378. if (clock)
  379. {
  380. //get the clocks digit entities
  381. new digit[4];
  382. new bSuccess = get_clock_digits(clock, digit);
  383.  
  384. //if successfully got clocks digit entities
  385. if (bSuccess)
  386. {
  387. new Float:vOrigin[3];
  388. new Float:vNormal[3];
  389. new Float:vAngles[3];
  390.  
  391. //get the clocks current scale and add on the specified amount
  392. new Float:fScale = entity_get_float(clock, EV_FL_scale);
  393. fScale += fScaleAmount;
  394.  
  395. //make sure the scale isn't negative
  396. if (fScale > 0.01)
  397. {
  398. //set the clocks scale
  399. entity_set_float(clock, EV_FL_scale, fScale);
  400.  
  401. //get the clocks origin and angles
  402. entity_get_vector(clock, EV_VEC_origin, vOrigin);
  403. entity_get_vector(clock, EV_VEC_angles, vAngles);
  404.  
  405. //get the clocks normal vector from the angles
  406. angle_vector(vAngles, ANGLEVECTOR_FORWARD, vNormal);
  407.  
  408. //set the normal to point in the opposite direction
  409. vNormal[0] = -vNormal[0];
  410. vNormal[1] = -vNormal[1];
  411. vNormal[2] = -vNormal[2];
  412.  
  413. //enlarge the clocks digits by the specified amount
  414. for (new i = 0; i < 4; ++i)
  415. {
  416. //set the digits scale
  417. entity_set_float(digit[i], EV_FL_scale, fScale);
  418.  
  419. //adjust the digits origin because of the new scale
  420. set_digit_origin(i, digit[i], vOrigin, vNormal, fScale);
  421. }
  422. }
  423. }
  424. }
  425. }
  426.  
  427. saveClocks(id)
  428. {
  429. //make sure player has access to this command
  430. if (get_user_flags(id) & ADMIN_LEVEL)
  431. {
  432. new ent = -1;
  433. new Float:vOrigin[3];
  434. new Float:vAngles[3];
  435. new Float:fScale;
  436. new clockCount = 0;
  437. new szData[128];
  438.  
  439. //open file for writing
  440. new file = fopen(gszFile, "wt");
  441. new clockType;
  442.  
  443. while ((ent = find_ent_by_class(ent, gszClockClassname)))
  444. {
  445. //get clock info
  446. entity_get_vector(ent, EV_VEC_origin, vOrigin);
  447. entity_get_vector(ent, EV_VEC_angles, vAngles);
  448. fScale = entity_get_float(ent, EV_FL_scale);
  449. clockType = entity_get_int(ent, EV_INT_groupinfo);
  450.  
  451. //format clock info and save it to file
  452. formatex(szData, 128, "%c %f %f %f %f %f %f %f^n", gClockSaveIds[clockType], vOrigin[0], vOrigin[1], vOrigin[2], vAngles[0], vAngles[1], vAngles[2], fScale);
  453. fputs(file, szData);
  454.  
  455. //increment clock count
  456. ++clockCount;
  457. }
  458.  
  459. //get players name
  460. new szName[32];
  461. get_user_name(id, szName, 32);
  462.  
  463. //notify all admins that the player saved clocks to file
  464. for (new i = 1; i <= 32; ++i)
  465. {
  466. //make sure player is connected
  467. if (is_user_connected(i))
  468. {
  469. if (get_user_flags(i) & ADMIN_LEVEL)
  470. {
  471. client_print(i, print_chat, "%s'%s' elmetette %d az idot %s!", gszPrefix, szName, clockCount, (clockCount == 1 ? "" : "s"));
  472. }
  473. }
  474. }
  475.  
  476. //close file
  477. fclose(file);
  478. }
  479. }
  480.  
  481. loadClocks(id)
  482. {
  483. //if the clock save file exists
  484. if (file_exists(gszFile))
  485. {
  486. new szData[128];
  487. new szType[2];
  488. new oX[13], oY[13], oZ[13];
  489. new aX[13], aY[13], aZ[13];
  490. new szScale[13];
  491. new Float:vOrigin[3];
  492. new Float:vAngles[3];
  493. new Float:vNormal[3];
  494. new Float:fScale;
  495. new clockCount = 0;
  496.  
  497. //open the file for reading
  498. new file = fopen(gszFile, "rt");
  499.  
  500. //iterate through all the lines in the file
  501. while (!feof(file))
  502. {
  503. szType = "";
  504. fgets(file, szData, 128);
  505. parse(szData, szType, 2, oX, 12, oY, 12, oZ, 12, aX, 12, aY, 12, aZ, 12, szScale, 12);
  506.  
  507. vOrigin[0] = str_to_float(oX);
  508. vOrigin[1] = str_to_float(oY);
  509. vOrigin[2] = str_to_float(oZ);
  510. vAngles[0] = str_to_float(aX);
  511. vAngles[1] = str_to_float(aY);
  512. vAngles[2] = str_to_float(aZ);
  513. fScale = str_to_float(szScale);
  514.  
  515. if (strlen(szType) > 0)
  516. {
  517. //get the normal vector from the angles
  518. angle_vector(vAngles, ANGLEVECTOR_FORWARD, vNormal);
  519.  
  520. //set the normal to point in the opposite direction
  521. vNormal[0] = -vNormal[0];
  522. vNormal[1] = -vNormal[1];
  523. vNormal[2] = -vNormal[2];
  524.  
  525. //create the clock depending on the clock type
  526. switch (szType[0])
  527. {
  528. case 'C': createClock(CM_SERVERTIME, vOrigin, vAngles, vNormal, fScale);
  529. case 'T': createClock(CM_MAPTIMELEFT, vOrigin, vAngles, vNormal, fScale);
  530. }
  531.  
  532. ++clockCount;
  533. }
  534. }
  535.  
  536. //close the file
  537. fclose(file);
  538.  
  539. //if a player is loading the clocks
  540. if (id > 0 && id <= 32)
  541. {
  542. //get players name
  543. new szName[32];
  544. get_user_name(id, szName, 32);
  545.  
  546. //notify all admins that the player loaded clocks from file
  547. for (new i = 1; i <= 32; ++i)
  548. {
  549. //make sure player is connected
  550. if (is_user_connected(i))
  551. {
  552. if (get_user_flags(i) & ADMIN_LEVEL)
  553. {
  554. client_print(i, print_chat, "%s'%s' betoltotte %d az idot%s!", gszPrefix, szName, clockCount, (clockCount == 1 ? "" : "s"));
  555. }
  556. }
  557. }
  558. }
  559. }
  560. }
  561.  
  562. get_clock_aiming(id)
  563. {
  564. //get hit point for where player is aiming
  565. new origin[3];
  566. new Float:vOrigin[3];
  567. get_user_origin(id, origin, 3);
  568. IVecFVec(origin, vOrigin);
  569.  
  570. new ent = -1;
  571.  
  572. //find all entities within a 2 unit sphere
  573. while ((ent = find_ent_in_sphere(ent, vOrigin, 2.0)))
  574. {
  575. //if entity is a clock
  576. if (isClock(ent))
  577. {
  578. return ent;
  579. }
  580. }
  581.  
  582. return 0;
  583. }
  584.  
  585. bool:traceClockAngles(id, Float:vAngles[3], Float:vNormal[3], Float:fDistance)
  586. {
  587. //get players origin and add on their view offset
  588. new Float:vPlayerOrigin[3];
  589. new Float:vViewOfs[3];
  590. entity_get_vector(id, EV_VEC_origin, vPlayerOrigin);
  591. entity_get_vector(id, EV_VEC_view_ofs, vViewOfs);
  592. vPlayerOrigin[0] += vViewOfs[0];
  593. vPlayerOrigin[1] += vViewOfs[1];
  594. vPlayerOrigin[2] += vViewOfs[2];
  595.  
  596. //calculate the end point for trace using the players view angle
  597. new Float:vAiming[3];
  598. entity_get_vector(id, EV_VEC_v_angle, vAngles);
  599. vAiming[0] = vPlayerOrigin[0] + floatcos(vAngles[1], degrees) * fDistance;
  600. vAiming[1] = vPlayerOrigin[1] + floatsin(vAngles[1], degrees) * fDistance;
  601. vAiming[2] = vPlayerOrigin[2] + floatsin(-vAngles[0], degrees) * fDistance;
  602.  
  603. //trace a line and get the normal for the plane it hits
  604. new trace = trace_normal(id, vPlayerOrigin, vAiming, vNormal);
  605.  
  606. //convert the normal into an angle vector
  607. vector_to_angle(vNormal, vAngles);
  608.  
  609. //spin the angle vector 180 degrees around the Y axis
  610. vAngles[1] += 180.0;
  611. if (vAngles[1] >= 360.0) vAngles[1] -= 360.0;
  612.  
  613. return bool:trace;
  614. }
  615.  
  616. set_digit_origin(i, digit, Float:vOrigin[3], Float:vNormal[3], Float:fScale)
  617. {
  618. //make sure the digit entity is valid
  619. if (is_valid_ent(digit))
  620. {
  621. new Float:vDigitNormal[3];
  622. new Float:vPos[3];
  623. new Float:fVal;
  624.  
  625. //change the normals to get the left and right depending on the digit
  626. vDigitNormal = vNormal;
  627. if (i == 0 || i == 1) vDigitNormal[X] = -vDigitNormal[X];
  628. if (i == 2 || i == 3) vDigitNormal[Y] = -vDigitNormal[Y];
  629.  
  630. //setup digit position
  631. fVal = (((gfClockSize[X] / 2) * gfDigitOffsetMultipliers[i])) * fScale;
  632. vPos[X] = vOrigin[X] + (vDigitNormal[Y] * fVal);
  633. vPos[Y] = vOrigin[Y] + (vDigitNormal[X] * fVal);
  634. vPos[Z] = vOrigin[Z] + vNormal[Z] - ((gfTitleSize / 2.0 )* fScale);
  635.  
  636. //bring digit sprites forwards off the clock face to prevent flickering
  637. vPos[0] += (vNormal[0] * 0.5);
  638. vPos[1] += (vNormal[1] * 0.5);
  639. vPos[2] += (vNormal[2] * 0.5);
  640.  
  641. //set the digits origin
  642. entity_set_origin(digit, vPos);
  643. }
  644. }
  645.  
  646. bool:getTimeDigits(clockType, digitValues[4])
  647. {
  648. switch (clockType)
  649. {
  650. case CM_SERVERTIME:
  651. {
  652. new bool:bChanged = false;
  653. new szTime[5];
  654. new timeOffset = get_cvar_num("cm_timeoffset");
  655. new hourType = get_cvar_num("cm_hourtype");
  656.  
  657. //get the time
  658. new hour, mins;
  659. time(hour, mins);
  660.  
  661. //add on the time offset
  662. hour += timeOffset;
  663.  
  664. //make sure hour hasnt gone out of bounds
  665. while (hour < 0)
  666. {
  667. hour += 24;
  668. }
  669.  
  670. while (hour >= 24)
  671. {
  672. hour -= 24;
  673. }
  674.  
  675. //if server is set to use 12 hour clocks
  676. if (hourType == 0)
  677. {
  678. if (hour > 12)
  679. {
  680. hour -= 12;
  681. }
  682. }
  683.  
  684. //format the time into a string
  685. format(szTime, 4, "%s%d%s%d", (hour < 10 ? "0" : ""), hour, (mins < 10 ? "0" : ""), mins);
  686.  
  687. //calculate time digits from string
  688. digitValues[0] = szTime[0] - 48;
  689. digitValues[1] = szTime[1] - 48;
  690. digitValues[2] = szTime[2] - 48;
  691. digitValues[3] = szTime[3] - 48;
  692.  
  693. //if the time has changed
  694. if (!equal(gszTime, szTime))
  695. {
  696. gszTime = szTime;
  697. bChanged = true;
  698. }
  699.  
  700. //if the hour type has changed
  701. if (hourType != gHourTypeOld)
  702. {
  703. gHourTypeOld = hourType;
  704. bChanged = true;
  705. }
  706.  
  707. //if the time offset value has changed
  708. if (timeOffset != gTimeOffsetOld)
  709. {
  710. gTimeOffsetOld = timeOffset;
  711. bChanged = true;
  712. }
  713.  
  714. return bChanged;
  715. }
  716.  
  717. case CM_MAPTIMELEFT:
  718. {
  719. //get timeleft on map and calculate the minutes and seconds
  720. new timeleft = get_timeleft();
  721. new mins = timeleft / 60;
  722. new secs = timeleft % 60;
  723.  
  724. //format the timeleft into a string
  725. new szTime[5];
  726. format(szTime, 4, "%s%d%s%d", (mins < 10 ? "0" : ""), mins, (secs < 10 ? "0" : ""), secs);
  727.  
  728. //calculate time digits from string
  729. digitValues[0] = szTime[0] - 48;
  730. digitValues[1] = szTime[1] - 48;
  731. digitValues[2] = szTime[2] - 48;
  732. digitValues[3] = szTime[3] - 48;
  733.  
  734. return true;
  735. }
  736. }
  737.  
  738. return false;
  739. }
  740.  
  741. bool:get_clock_digits(clock, digit[4])
  742. {
  743. //if the entity is a clock
  744. if (isClock(clock))
  745. {
  746. //get entity IDs of digits on the clock
  747. digit[0] = entity_get_int(clock, EV_INT_iuser1);
  748. digit[1] = entity_get_int(clock, EV_INT_iuser2);
  749. digit[2] = entity_get_int(clock, EV_INT_iuser3);
  750. digit[3] = entity_get_int(clock, EV_INT_iuser4);
  751.  
  752. //make sure all the clock digits are valid
  753. for (new i = 0; i < 4; ++i)
  754. {
  755. if (!is_valid_ent(digit[i]))
  756. {
  757. log_amx("%sInvalid digit entity in clock", gszPrefix);
  758.  
  759. return false;
  760. }
  761. }
  762. }
  763.  
  764. return true;
  765. }
  766.  
  767. set_clock_digits(clock, digitValues[4])
  768. {
  769. //get the clocks digit entities
  770. new digits[4];
  771. new bool:bSuccess = get_clock_digits(clock, digits);
  772.  
  773. //if successfully got clocks digit entities
  774. if (bSuccess)
  775. {
  776. //setup clock digits
  777. entity_set_float(digits[0], EV_FL_frame, float(digitValues[0]));
  778. entity_set_float(digits[1], EV_FL_frame, float(digitValues[1]));
  779. entity_set_float(digits[2], EV_FL_frame, float(digitValues[2]));
  780. entity_set_float(digits[3], EV_FL_frame, float(digitValues[3]));
  781. }
  782. }
  783.  
  784. alertHour(hour)
  785. {
  786. //if we're set to speak the hour
  787. if (get_cvar_num("cm_hourannounce") > 0)
  788. {
  789. new szMeridiem[4] = "am";
  790. new szHour[16];
  791.  
  792. //setup hour. Make sure hour isn't above 12 and isn't 00 o'clock
  793. if (hour >= 12) szMeridiem = "pm";
  794. if (hour > 12) hour -= 12;
  795. if (hour == 0) hour = 12;
  796.  
  797. //get the hour as a word
  798. num_to_word(hour, szHour, 15);
  799.  
  800. //speak the time
  801. client_cmd(0, "spk ^"fvox/bell _period %s %s^"", szHour, szMeridiem);
  802. }
  803. }
  804.  
  805. bool:isClock(ent)
  806. {
  807. //if entity is valid
  808. if (is_valid_ent(ent))
  809. {
  810. //get classname of entity
  811. new szClassname[32];
  812. entity_get_string(ent, EV_SZ_classname, szClassname, 32);
  813.  
  814. //if classname of entity matches global clock classname
  815. if (equal(szClassname, gszClockClassname))
  816. {
  817. //entity is a clock
  818. return true;
  819. }
  820. }
  821.  
  822. return false;
  823. }
  824.