Y_Less

If you think you know PAWN, what does this working code do?

Jun 1st, 2011
5,435
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pawn 14.98 KB | None | 0 0
  1. /*============================================================================*\
  2. *==============================================================================*
  3. ================================================================================
  4. ||||                                                                        ||||
  5. ||||                         HERE BEGINS VERSION 2!                         ||||
  6. ||||                                                                        ||||
  7. ================================================================================
  8. *==============================================================================*
  9. \*============================================================================*/
  10.  
  11. #include <YSI\internal\y_version>
  12. #include <YSI\y_amx>
  13. #include <YSI\internal\y_shortfunc>
  14. #include <YSI\y_malloc>
  15. #include <YSI\y_iterate>
  16. // This will be called twice and means there are two separate OnScriptInit
  17. // functions in this file.
  18. #include <YSI\y_hooks>
  19. #include <YSI\y_debug>
  20.  
  21. #define task%0[%1](%2) %0@yT_(g,p);public%0@yT_(g,p){static s=-1;return _Timer_I(#%0,%1,g,s);}%0();public%0()
  22.  
  23. #define ptask%0[%1](%2) stock %0_yT@=1;%0@yT_(g,p);public%0@yT_(g,p){static s[MAX_PLAYERS]={-1,...},a[2];return _Timer_D(#%0@_yT,%1,g,p,s,%0_yT@,a);}%0@_yT(p);public%0@_yT(p)if(%0_yT@)%0(p);%0(%2)
  24.  
  25. static stock
  26.     Alloc:YSI_g_sLastSlot = NO_ALLOC,
  27.     Alloc:YSI_g_sFirstSlot = NO_ALLOC,
  28.     YSI_g_sPlayerTimers = -1;
  29.  
  30. hook OnScriptInit()
  31. {
  32.     P:1("hook Timers_OnScriptInit called");
  33.     new
  34.         pointer,
  35.         time,
  36.         idx,
  37.         entry;
  38.     while ((idx = AMX_GetPublicEntrySuffix(idx, entry, _A<@yT_>)))
  39.     //while ((idx = AMX_GetPublicPointerSuffix(idx, pointer, _A<@yT_>)))
  40.     {
  41.         P:6("Timer_OnScriptInit: entry: %d", entry);
  42.         #emit LREF.S.pri entry
  43.         #emit STOR.S.pri pointer
  44.         //YSI_g_sCurFunc = pointer;
  45.         // Don't bother with the real name, call the function by address to get
  46.         // the time the function runs for.
  47.         P:7("Timer_OnScriptInit: pointer: %d", pointer);
  48.         // Push the address of the current function.
  49.         #emit PUSH.S     pointer
  50.         #emit PUSH.C     0xFFFFFFFF
  51.         #emit PUSH.C     8
  52.         #emit LCTRL      6
  53.         #emit ADD.C      28
  54.         #emit PUSH.pri
  55.         #emit LOAD.S.pri pointer
  56.         #emit SCTRL      6
  57.         #emit STOR.S.pri time
  58.         //YSI_g_sCurFunc = 0;
  59.         P:7("Timer_OnScriptInit: time: %d", time);
  60.         if (time != -1)
  61.         {
  62.             // Find all the functions with the same time.  This is less
  63.             // efficient than previous implementations (it is O(N^2)), but also
  64.             // more robust as it won't fail no matter how many different times
  65.             // there are - old ones relied on an array with a finite size.
  66.             new
  67.                 pointer2,
  68.                 time2,
  69.                 idx2,
  70.                 total,
  71.                 pre;
  72.             while ((idx2 = AMX_GetPublicPointerSuffix(idx2, pointer2, _A<@yT_>)))
  73.             {
  74.                 // Call the functions a second time to guarantee getting
  75.                 #emit PUSH.C     0
  76.                 #emit PUSH.C     0xFFFFFFFF
  77.                 #emit PUSH.C     8
  78.                 #emit LCTRL      6
  79.                 #emit ADD.C      28
  80.                 #emit PUSH.pri
  81.                 #emit LOAD.S.pri pointer2
  82.                 #emit SCTRL      6
  83.                 #emit STOR.S.pri time2
  84.                 if (time2 == time)
  85.                 {
  86.                     ++total;
  87.                     if (idx2 < idx)
  88.                     {
  89.                         ++pre;
  90.                     }
  91.                 }
  92.             }
  93.             P:7("Timer_OnScriptInit: total: %d, time: %d, pre: %d", total, time, pre);
  94.             // Now we know what time this function has, how many others have
  95.             // that time and how many have already been started.
  96.             new
  97.                 buffer[32];
  98.             entry += 4;
  99.             #emit LREF.S.pri entry
  100.             #emit STOR.S.pri pointer
  101.             AMX_ReadString(AMX_Base + pointer, buffer);
  102.             P:7("Timer_OnScriptInit: %s", unpack(buffer));
  103.             // Get the time offset for the current call.  This should mean that
  104.             // all the functions are nicely spread out.
  105.             SetTimerEx(buffer, time * pre / total, 0, "ii", 1, -1);
  106.         }
  107.     }
  108.     P:1("hook Timers_OnScriptInit ended");
  109. }
  110.  
  111. hook OnPlayerConnect(playerid)
  112. {
  113.     P:1("hook Timers_OnPlayerConnect called: %d", playerid);
  114.     // Loop through all the per-player timers.  Correctly finds them all from a
  115.     // linked list hidden in static variables (which are really global).
  116.     new
  117.         cur = YSI_g_sPlayerTimers,
  118.         data;
  119.     while (cur != -1)
  120.     {
  121.         #emit LREF.S.pri  cur
  122.         #emit STOR.S.pri  data
  123.         P:6("Timers_OnPlayerConnect: func: %x", data);
  124.         // Start this timer for this player.
  125.         #emit PUSH.S     playerid
  126.         #emit PUSH.C     1
  127.         // Push the parameter count (in bytes).  This is actually passed to
  128.         // native functions directly.
  129.         #emit PUSH.C     8
  130.         // Call the function currently in the list to trigger the repeating
  131.         // timer.  This involves getting the current "cip" address, modifying it
  132.         // to get the return address then modifying "cip" to call the function.
  133.         #emit LCTRL      6
  134.         #emit ADD.C      28
  135.         #emit PUSH.pri
  136.         #emit LOAD.S.pri data
  137.         #emit SCTRL      6
  138.         // Returned, get the next list element.
  139.         cur += 4;
  140.         #emit LREF.S.pri  cur
  141.         #emit STOR.S.pri  cur
  142.     }
  143.     P:1("hook Timers_OnPlayerConnect ended");
  144. }
  145.  
  146. hook OnPlayerDisconnect(playerid, reason)
  147. {
  148.     P:1("hook Timers_OnPlayerDisconnect called: %d, %d, playerid, reason");
  149.     // Loop through all the per-player timers.  Correctly finds them all from a
  150.     // linked list hidden in static variables (which are really global).
  151.     new
  152.         cur = YSI_g_sPlayerTimers,
  153.         data;
  154.     while (cur != -1)
  155.     {
  156.         #emit LREF.S.pri  cur
  157.         #emit STOR.S.pri  data
  158.         P:6("Timers_OnPlayerDisconnect: func: %x", data);
  159.         // End this timer for this player.
  160.         #emit PUSH.S     playerid
  161.         #emit PUSH.C     0
  162.         // Push the parameter count (in bytes).  This is actually passed to
  163.         // native functions directly.
  164.         #emit PUSH.C     8
  165.         // Call the function currently in the list to trigger the repeating
  166.         // timer.  This involves getting the current "cip" address, modifying it
  167.         // to get the return address then modifying "cip" to call the function.
  168.         #emit LCTRL      6
  169.         #emit ADD.C      28
  170.         #emit PUSH.pri
  171.         #emit LOAD.S.pri data
  172.         #emit SCTRL      6
  173.         // Returned, get the next list element.
  174.         cur += 4;
  175.         #emit LREF.S.pri  cur
  176.         #emit STOR.S.pri  cur
  177.     }
  178.     P:1("hook Timers_OnPlayerDisconnect ended");
  179. }
  180.  
  181. stock _Timer_I(func[], interval, action, &result)
  182. {
  183.     P:3("_Timer_I called");
  184.     switch (action)
  185.     {
  186.         case 0:
  187.         {
  188.             if (result != -1)
  189.             {
  190.                 KillTimer(result),
  191.                 result =- 1;
  192.             }
  193.         }
  194.         case 1:
  195.         {
  196.             if (result == -1)
  197.             {
  198.                 result = SetTimer(func, interval, 1);
  199.             }
  200.         }
  201.     }
  202.     return interval;
  203. }
  204.  
  205. // Attempt to stop or start a task, possibly for a single player.
  206. stock _Timer_D(func[], interval, const action, who, results[MAX_PLAYERS], &pause, a[2])
  207. {
  208.     P:3("_Timer_D called");
  209.     switch (action)
  210.     {
  211.         case -1:
  212.         {
  213.             if (who)
  214.             {
  215.                 a[0] = who;
  216.                 a[1] = YSI_g_sPlayerTimers;
  217.                 // Store the address of the global array.
  218.                 #emit LOAD.S.pri  a
  219.                 #emit STOR.pri    YSI_g_sPlayerTimers
  220.             }
  221.         }
  222.         case 0:
  223.         {
  224.             // Stop the timer.
  225.             if (who == -1)
  226.             {
  227.                 pause = 0;
  228.             }
  229.             else if (results[who] != -1)
  230.             {
  231.                 KillTimer(results[who]);
  232.                 results[who] = -1;
  233.             }
  234.         }
  235.         case 1:
  236.         {
  237.             // Start the timer.
  238.             if (who == -1)
  239.             {
  240.                 pause = 1;
  241.             }
  242.             else if (results[who] == -1)
  243.             {
  244.                 results[who] = SetTimerEx(func, interval, true, "i", who);
  245.             }
  246.         }
  247.     }
  248.     // No global interval for per-player timers.
  249.     return -1;
  250. }
  251.  
  252. static stock Alloc:Timer_GetSingleSlot(len)
  253. {
  254.     // Allocates memory and secretly appends data to the start.
  255.     P:4("Timer_GetSingleSlot called: %d", len);
  256.     new
  257.         Alloc:slot = malloc(len + 1);
  258.     if (slot == NO_ALLOC)
  259.     {
  260.         return NO_ALLOC;
  261.     }
  262.     P:5("Timer_GetSingleSlot: %d, %d, %d", _:YSI_g_sFirstSlot, _:YSI_g_sLastSlot, _:slot);
  263.     // Standard linked list.
  264.     if (YSI_g_sFirstSlot == NO_ALLOC)
  265.     {
  266.         YSI_g_sFirstSlot = slot;
  267.     }
  268.     else
  269.     {
  270.         mset(YSI_g_sLastSlot, 0, _:slot);
  271.     }
  272.     YSI_g_sLastSlot = slot;
  273.     mset(YSI_g_sLastSlot, 0, -1);
  274.     return slot;// + Alloc:1;
  275. }
  276.  
  277. // Allocate memory to store a string.
  278. stock _Timer_S(string:str[])
  279. {
  280.     P:3("_Timer_S called");
  281.     new
  282.         len = strlen(str);
  283.     if (len & 0x0F)
  284.     {
  285.         len = (len & ~0x0F) + 32;
  286.     }
  287.     new
  288.         Alloc:slot = Timer_GetSingleSlot(len + 1);
  289.     if (slot != NO_ALLOC)
  290.     {
  291.         msets(slot, 1, str);
  292.     }
  293.     P:5("str: %d", _:slot);
  294.     return _:slot + 1;
  295. }
  296.  
  297. // Allocate memory to store an array.
  298. stock _Timer_A(str[], len)
  299. {
  300.     P:3("_Timer_A called");
  301.     new
  302.         Alloc:slot = Timer_GetSingleSlot(len);
  303.     if (slot != NO_ALLOC)
  304.     {
  305.         mseta(slot, 1, str, len);
  306.     }
  307.     P:5("str: %d", _:slot);
  308.     return _:slot + 1;
  309. }
  310.  
  311. stock
  312.     I@ = -1;
  313.  
  314. // Create the timer setup.
  315. stock _Timer_C(timer, g)
  316. {
  317.     P:3("_Timer_C called: %d, %d", timer, g);
  318.     // This is done here for convenience.
  319.     I@ = -1;
  320.     // Only repeating timers are freed like this.
  321.     if (g)
  322.     {
  323.         new
  324.             Alloc:slot = Timer_GetSingleSlot(1);
  325.         P:5("_Timer_C: slot = %d", _:slot);
  326.         if (slot == NO_ALLOC)
  327.         {
  328.             // Not a graceful fail!
  329.             return 0;
  330.         }
  331.         mset(slot, 1, timer);
  332.         // Just so it isn't a real timer ID (or possibly isn't).
  333.         slot = ~YSI_g_sFirstSlot;// ^ Alloc:-1;
  334.         YSI_g_sFirstSlot = NO_ALLOC;
  335.         YSI_g_sLastSlot = NO_ALLOC;
  336.         return _:slot;
  337.     }
  338.     // Reset these variables on all timers, including self-cleaning ones.
  339.     YSI_g_sFirstSlot = NO_ALLOC;
  340.     YSI_g_sLastSlot = NO_ALLOC;
  341.     return 0;
  342. }
  343.  
  344. // Free all timer resources.
  345. stock _Timer_F(slot)
  346. {
  347.     P:3("_Timer_F called");
  348.     // This is done here for convenience.
  349.     new
  350.         next;
  351.     slot = ~slot; //^= -1;
  352.     for ( ; ; )
  353.     {
  354.         next = mget(Alloc:slot, 0);
  355.         P:6("_Timer_F: slot = %d, next = %d", slot, next);
  356.         // Out of stored strings and arrays.
  357.         if (next == -1)
  358.         {
  359.             KillTimer(mget(Alloc:slot, 1));
  360.             free(Alloc:slot);
  361.             break;
  362.         }
  363.         free(Alloc:slot);
  364.         slot = next;
  365.     }
  366.     return 1;
  367. }
  368.  
  369. // Free one timer resource.
  370. /*stock _Timer_H(slot)
  371. {
  372.     P:3("_Timer_H called");
  373.     // This is done here for convenience.
  374.     free(Alloc:(slot - 1));
  375. }*/
  376.  
  377. // Free one timer resource.  Now actually frees many, not just one.
  378. stock _Timer_H(...)
  379. {
  380.     P:3("_Timer_H called");
  381.     new
  382.         c = numargs();
  383.     while (c--)
  384.     {
  385.         // This is done here for convenience.
  386.         free(Alloc:(getarg(c) - 1));
  387.     }
  388. }
  389.  
  390. //#define _Timer_G(%0) YSI_gMallocMemory[%0]
  391. //#define _Timer_B _Timer_G
  392.  
  393. /*#define pause_task%0; {%0@yT_(0,-1);}
  394. #define resume_task%0; {%0@yT_(1,-1);}
  395. #define pause_ptask%0; {%0@yT_(0,%1);}
  396. #define resume_ptask%0; {J@=_:hym:%0@yT_(1,%1);}*/
  397.  
  398. #define pause%0; {J@=_:hym:%0@yT_(0,-1);}
  399. #define resume%0; {J@=_:hym:%0@yT_(1,-1);}
  400. #define hym:%0:%1@yT_(%2,-1) %0@yT_(%2,%1)
  401.  
  402. // These are the tag-type definitions for the various possible parameter types.
  403. //#define hya:hyb:hyc:hyd:hyz:#%0#%1|||%2string:%3[%4]|||%5,%6;%9||| hya:hyb:hyc:hyd:hyz:#%0d#%1,_Timer_S(%3)|||%5|||%6;%9,hyv<<<%3>>>|||
  404. // This one has an extra parameter because arrays must always be followed by
  405. // their length.
  406. #define hyb:hyc:hyd:hyz:#%0#%1|||%3[%4]|||%5,%6;%9||| hya:hyy:#%0#%1|||%3[%4]|||%5,%6;%9|||
  407. //hya:hyb:hyc:hyd:hyz:#%0d#%1,_Timer_A(%3,%5)|||%5|||%6,%7;%9,hyv<<<%3>>>|||
  408.  
  409. #define hya:hyy:#%0#%1|||%2string:%3[%4]|||%5,%6;%9||| hyb:hyc:hyd:hyz:#%0d#%1,_Timer_S(%3)|||%5|||%6;%9,hyv&%3&|||
  410.  
  411. #define hyy:#%0#%1|||%3[%4]|||%5,%6,%7;%9||| hyb:hyc:hyd:hyz:#%0d#%1,_Timer_A(%3,%5)|||%5|||%6,%7;%9,hyv&%3&|||
  412.  
  413. #define hyc:hyd:hyz:#%0#%1|||%2:%3|||%5,%6;%9||| hyb:hyc:hyd:hyz:#%0d#%1,_:%3|||%5|||%6;%9,%2:%3|||
  414.  
  415. #define hyd:hyz:#%0#%1|||%3|||%5,%6;%9||| hyb:hyc:hyd:hyz:#%0d#%1,%3|||%5|||%6;%9,%3|||
  416.  
  417. // Main entry point for defer type determination.
  418. #define _YT@CT:%0,%1)%3;%2||| hyb:hyc:hyd:hyz:##|||%0|||%1;%2|||
  419.  
  420. // Detect zero parameters.
  421. #define O@(#%0,%1,%2,%6:,,)%7;%3|||%5||| K@(#%0,%1,%2),%7);%3@_yT();public%3@_yT(){%5();}%5
  422. //#define hye:__hyf=%4)%5O@(#%0#__hyf,%2,_YT@CT:,,;%3||| __hyg=%4)return K@(#%0#,__hyg,%2);%3@_yT();public%3@_yT(){%3_yT@();}
  423.  
  424. // Define for "defer" with timer, parameters and main function.
  425. #define defer%0[%1](%2) stock%0(%2)return _Timer_C(O@(#%0@_yT,I@==-1?(%1):I@,0,_YT@CT:%2,,)0;%0|||%0_yT@|||(%2)
  426.  
  427. // This is called if we need to add a leading comma to the time parameter.
  428. //#define __hyf ,__hyg
  429.  
  430. // Expand additional parameters out to three functions after processing.
  431. //#define hyz:%0||||||;%1,%2|||%3|||%4||| hyy:hyw:%0),0);%1@_yT(%2);public%1@_yT(%2){%4(%2);}%3%4
  432. #define hyz:%0||||||;%1,%2|||%4||| %0),0);hyj:%1@_yT(%2);public hyj:%1@_yT(%2){%4(%2);}%4
  433.  
  434. // Remove excess "_Timer_G" and "_Timer_B".
  435. //#define hyy:hyw:%0;%1(%2_Timer_G(%3)%4);%5(%6_Timer_G(%7)%8){%9} hyy:hyw:%0;%1(%2%3%4);%5(%6%7%8){%9_Timer_H(%3);}
  436. //#define hyw:%0;%1(%2_Timer_B(%3)%4);%5(%6_Timer_B(%7)%8){%9} hyy:hyw:%0;%1(%2%3%4);%5(%6%7%8){%9_Timer_H(%3);}
  437.  
  438. // Define for "force" to call function quickly.
  439. //#define force%0[%1](%2) (J@=_:hyr:hyq:%0:%1(%2))
  440. #define force%0(%2) (%0_yT@(%2))
  441.  
  442. #define hyr:hyq:%0:%2-1(%2) %0_yT@(%2)
  443.  
  444. #define hyq:%0:%1(%2) (I@=(%1),%0(%2))
  445.  
  446. #define @%0:%1(%2) (hyr:hyq:%1:%0(%2))
  447. #define after%0(%2) (I@=0,%0(%2))
  448.  
  449. // This is the start of the "repeat" code - code for looping timers.
  450.  
  451. // These are the tag-type definitions for the various possible parameter types.
  452. #define hyf:hyg:hyh:hyx:#%0#%1|||%3[%4]|||%5,%6;%9||| hye:hyw:#%0#%1|||%3[%4]|||%5,%6;%9|||
  453.  
  454. #define hye:hyw:#%0#%1|||%2string:%3[%4]|||%5,%6;%9||| hyf:hyg:hyh:hyx:#%0d#%1,_Timer_S(%3)|||%5|||%6;%9,hyv&%3&|||
  455.  
  456. #define hyw:#%0#%1|||%3[%4]|||%5,%6,%7;%9||| hyf:hyg:hyh:hyx:#%0d#%1,_Timer_A(%3,%5)|||%5|||%6,%7;%9,hyv&%3&|||
  457. // This one has an extra parameter because arrays must always be followed by
  458. // their length.
  459. //#define hyf:hyg:hyh:hyx:#%0#%1|||%3[%4]|||%5,%6,%7;%9||| hyf:hyg:hyh:hyx:#%0d#%1,_Timer_A(%3,%5)|||%5|||%6,%7;%9,hyv<<<%3>>>|||
  460.  
  461. #define hyg:hyh:hyx:#%0#%1|||%2:%3|||%5,%6;%9||| hyf:hyg:hyh:hyx:#%0d#%1,%2:%3|||%5|||%6;%9,%2:%3|||
  462.  
  463. #define hyh:hyx:#%0#%1|||%3|||%5,%6;%9||| hyf:hyg:hyh:hyx:#%0d#%1,%3|||%5|||%6;%9,%3|||
  464.  
  465. // Main entry point for defer type determination.
  466. #define _YT@CR:%0,%1)%3;%2||| hyf:hyg:hyh:hyx:##|||%0|||%1;%2|||
  467.  
  468. //#define O@(#%0,%1,%2,%6:,,)%7;%3|||%4|||%5||| K@(#%0,%1,%2),%7);%3@_yT();public%3@_yT(){%5();}%4%5
  469. // Define for "defer" with timer, parameters and main function.
  470. //#define defer%0[%1](%2) stock%0(%2)return _Timer_C(O@(#%0@_yT,I@==-1?(%1):I@,0,_YT@CT:%2,,)0;%0||||||%0_yT@|||(%2)
  471. #define repeat%0[%1](%2) stock%0_yT@(%2)return _Timer_C(O@(#%0@_yT,I@==-1?(%1):I@,1,_YT@CR:%2,,)1;%0|||%0|||(%2)
  472.  
  473. //#define hyi(%0) return _Timer_F(%0);
  474.  
  475. // This is called if we need to add a leading comma to the time parameter.
  476. //#define __hyf ,__hyg
  477.  
  478. // Expand additional parameters out to three functions after processing.
  479. //#define hyx:%0||||||;%1,%2|||%3|||%4||| hyu:hyv:%0),1);%1@_yT(%2);public%1@_yT(%2){%4(%2);}%3%4
  480. #define hyx:%0||||||;%1,%2|||%4||| %0),1);hyu:%1@_yT(%2);public hyu:%1@_yT(%2){%4(%2);}%4
  481.  
  482. // Remove excess "_Timer_G" and "_Timer_B".
  483. //#define hyu:hyv:%0;%1(%2_Timer_G(%3)%4);%5(%6_Timer_G(%7)%8) hyu:hyv:%0;%1(%2%3%4);%5(%6%7%8)
  484. //#define hyv:%0;%1(%2_Timer_B(%3)%4);%5(%6_Timer_B(%7)%8) hyu:hyv:%0;%1(%2%3%4);%5(%6%7%8)
  485.  
  486. #define hyj:%0{%1(%8&%2&%3)%9} hyj:%0{%1(%8:YSI_gMallocMemory[%2]%3);hyl(hyk:%2)%9}
  487. #define hyu:%0{%1(%8&%2&%3)%9} hyu:%0{%1(%8:YSI_gMallocMemory[%2]%3)%9}
  488. #define hyv&%0& %0
  489.  
  490. #define hyk:%0);hyl(hyk:%1); %0,hyk:%1);
  491. #define hyl _Timer_H
  492.  
  493. //#define start%0(%1) (J@=%0_yT@(%1))
  494. #define start%0(%1) (Timer:%0_yT@(%1))
  495. #define stop%1; {_Timer_F(%1);}
Advertisement
Add Comment
Please, Sign In to add comment