Advertisement
Y_Less

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

Aug 30th, 2011
1,430
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pawn 25.92 KB | None | 0 0
  1. /*----------------------------------------------------------------------------*\
  2.                       ====================================
  3.                        y_timers - Run timers efficiently.
  4.                       ====================================
  5. Description:
  6.     Sets up repeating timers without requiring any SetTimers and arranges them
  7.     so that they will be very unlikely to meet (at least for a long time) using
  8.     scheduling algorithms to get timers with the same period to be offset.  Also
  9.     fixes arrays and strings in timers so they can be passed properly.
  10. Legal:
  11.     Version: MPL 1.1
  12.    
  13.     The contents of this file are subject to the Mozilla Public License Version
  14.     1.1 (the "License"); you may not use this file except in compliance with
  15.     the License. You may obtain a copy of the License at
  16.     http://www.mozilla.org/MPL/
  17.    
  18.     Software distributed under the License is distributed on an "AS IS" basis,
  19.     WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  20.     for the specific language governing rights and limitations under the
  21.     License.
  22.    
  23.     The Original Code is the YSI timers include.
  24.    
  25.     The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  26.     Portions created by the Initial Developer are Copyright (C) 2011
  27.     the Initial Developer. All Rights Reserved.
  28.    
  29.     Contributors:
  30.         ZeeX, koolk, JoeBullet/Google63, g_aSlice/Slice
  31.    
  32.     Thanks:
  33.         JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
  34.         ZeeX - Very productive conversations.
  35.         koolk - IsPlayerinAreaEx code.
  36.         TheAlpha - Danish translation.
  37.         breadfish - German translation.
  38.         Fireburn - Dutch translation.
  39.         yom - French translation.
  40.         50p - Polish translation.
  41.         Zamaroht - Spanish translation.
  42.         Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes
  43.             for me to strive to better.
  44.         Pixels^ - Running XScripters where the idea was born.
  45.         Matite - Pestering me to release it and using it.
  46.    
  47.     Very special thanks to:
  48.         Thiadmer - PAWN, whose limits continue to amaze me!
  49.         Kye/Kalcor - SA:MP.
  50.         SA:MP Team past, present and future - SA:MP.
  51.    
  52. Version:
  53.     2.0
  54. Changelog:
  55.     29/04/11:
  56.         Added version 2 of the code with more advanced options.
  57.     21/03/11:
  58.         Added debug printing to timer functions.  Uses "P:C" in compiling.
  59.     26/10/10:
  60.         Officially added simple calling.
  61.         Added "delay" functions.
  62.     12/10/10:
  63.         Rewrote for YSI 1.0 using y_scripting.
  64.     11/08/07:
  65.         Removed millions of defines to reduce pre-processing.
  66.         Added pickups.
  67.     03/08/07:
  68.         First version.
  69. \*----------------------------------------------------------------------------*/
  70.  
  71. // Disable this version!
  72. #if defined USE_Y_TIMERS_V1
  73.  
  74. #include <YSI\internal\y_version>
  75.  
  76. #include <YSI\internal\y_shortfunc>
  77. #include <YSI\y_hooks>
  78.  
  79. #include <YSI\y_amx>
  80. #include <YSI\y_debug>
  81.  
  82. //#define Timer:%0[%1](%2) forward @yT_%1_%0();@yT_%1_%0()
  83. #define Timer:%0[%1](%2) @yT_%1_%0();stock %0()@yT_%1_%0();@yT_%1_%0()P:C(for(new __%0=1;__%0&&(printf("Timer "#%0"["#%1"]" called.")|1);__%0^=1));
  84.  
  85. #define Delay:%0[%1,%2](%3) stock %0(%3)return O@(#@#%0,%1,0,#%2#x,%3);stock v@%0(_:_o@,%3)return O@(#@#%0,_o@,0,#%2#x,%3);@%0(%3);@%0(%3)
  86.  
  87. #define FixDelay:%0[%1,%2](%3) stock %0(%3)return O@("@_"#%0,%1,0,#%2#x,%3);@_%0(%3);@_%0(%3)
  88. // There's a bug in passing strings to timer functions, so I've remove it.
  89. //#define Delay@p:%0[%1,%2](%3)<%4> stock %0(%3)return O@(#@#%0,%1,0,#%2,%4);stock v@%0(_o@,%3)return O@(#@#%0,_o@,0,#%2,%4);forward @%0(%3);@%0(%3)
  90.  
  91. #define skip:%0(%3) @%0(%3)
  92. #define delay:%0[%1](%3) v@%0(_:%1,%3)
  93.  
  94. // This defines the number of different periods that timers can have.  This
  95. // number is a HUGE over-estimate, you would need to have over 256 timers, none
  96. // of them with the same period, for this number to be too small!
  97. #define MAX_TIMER_VARIATIONS            (256)
  98.  
  99. //#define timer%0[%1](%2) %0@yT_();public%0@yT_()
  100.  
  101. forward Timer_Start(timer, delay);
  102.  
  103. /*----------------------------------------------------------------------------*\
  104. Function:
  105.     OnScriptInit
  106. Params:
  107.     -
  108. Return:
  109.     -
  110. Notes:
  111.     -
  112. \*----------------------------------------------------------------------------*/
  113.  
  114. hook OnScriptInit()
  115. {
  116.     new
  117.         buffer[32],
  118.         idx = 0,
  119.         timers[MAX_TIMER_VARIATIONS][2],//[3],
  120.         periods = 0;
  121.     // 0 = time, 1 = count, 2 = offset.
  122.     // First loop - get all the different periods.
  123.     // Get the list of timers from the list of publics.
  124.     while ((idx = AMX_GetPublicNamePrefix(idx, buffer, _A<@yT_>)))
  125.     {
  126.         // Get the time associated with the timer.  We know this starts at index
  127.         // position 4, because we always set it to be there.
  128.         new
  129.             time = strval(buffer[1]);
  130.         if (time)
  131.         {
  132.             // Valid time, find this in the array.
  133.             for (new i = 0; ; ++i)
  134.             {
  135.                 if (i == periods)
  136.                 {
  137.                     timers[i][0] = time;
  138.                     timers[i][1] = 1;
  139.                     ++periods;
  140.                     break;
  141.                 }
  142.                 else if (timers[i][0] == time)
  143.                 {
  144.                     ++timers[i][1];
  145.                     break;
  146.                 }
  147.             }
  148.             if (periods == MAX_TIMER_VARIATIONS)
  149.             {
  150.                 P:E("Timer array full");
  151.                 break;
  152.             }
  153.         }
  154.     }
  155.     // Group timers with common periods together, for example timers with 1000
  156.     // and 500ms periods need to be interleaved so they don't run at the same
  157.     // time very often.  Obviously ANY combination of timers will eventually run
  158.     // at the same time at some point, but we can reduce this chance.
  159.     /*for (new i = 0; i != periods; ++i)
  160.     {
  161.         new
  162.             time = timers[i][0];
  163.         if (timers[i][2])
  164.         {
  165.             for (new j = 0; j != i; ++j)
  166.             {
  167.                 new
  168.                     ct = timers[j][0];
  169.                 if ((time / ct) * ct == time || (ct / time) * time == ct)
  170.                 {
  171.                     // Set the count to the same as the master.
  172.                     timers[i][1] = timers[j][1];
  173.                     break;
  174.                 }
  175.             }
  176.         }
  177.         else
  178.         {
  179.             new
  180.                 offset = timers[i][1];
  181.             for (new j = i + 1; j != periods; ++j)
  182.             {
  183.                 // Find similar periods.
  184.                 new
  185.                     ct = timers[j][0];
  186.                 if ((time / ct) * ct == time)
  187.                 {
  188.                     // This time is larger.
  189.                 }
  190.                 else if ((ct / time) * time == ct)
  191.                 {
  192.                 }
  193.                 if ((time / ct) * ct == time || (ct / time) * time == ct)
  194.                 {
  195.                     // That's integer division, so valid code.  Mark this
  196.                     // element as controlled by another element.
  197.                     timers[j][2] = offset;
  198.                     offset += timers[j][1];
  199.                 }
  200.             }
  201.             timers[i][1] = offset;
  202.         }
  203.     }*/
  204.     printf("ENTRY>>>>");
  205.     C:1(for(new i;i!=periods;++i)printf("%d %d %d",timers[i][0],timers[i][1],0););//,timers[i][2]););
  206.     // Now we know how many of each period there are we can try arrange them so
  207.     // that they execute at very different times.
  208.     // [1] contains the total number of timers on similar periods.
  209.     for (new i = 0; i != periods; ++i)
  210.     {
  211.         // First calculate the gap between the timers.
  212.         new
  213.             time = timers[i][0],
  214.             offset = time / timers[i][1];
  215.         // Now start all the timers with this time at that offset.
  216.         idx = 0;
  217.         new
  218.             last = 0,
  219.             curo = offset;
  220.         while ((idx = AMX_GetPublicNamePrefix(idx, buffer, _A<@yT_>)))
  221.         {
  222.             if (strval(buffer[1]) == time)
  223.             {
  224.                 // That's the old start code, which uses 7ms offsets to try get
  225.                 // as close as possible to different server frames (5ms).
  226.                 SetTimerEx("Timer_Start", curo + (random(14) - 7), 0, "ii", last, time);
  227.                 //SetTimerEx("Timer_Start", curo, 0, "ii", last, time);
  228.                 curo += offset;
  229.             }
  230.             // So that the first found timer in the next function is correct.
  231.             last = idx;
  232.         }
  233.     }
  234. }
  235.  
  236. /*----------------------------------------------------------------------------*\
  237. Function:
  238.     Timer_Start
  239. Params:
  240.     timer - Approximate public function index.
  241.     delay - How often it's called.
  242. Return:
  243.     -
  244. Notes:
  245.     Only needed for more than one timer.  Offsets calls from each other for
  246.     better server load distribution.
  247. \*----------------------------------------------------------------------------*/
  248.  
  249. public Timer_Start(timer, delay)
  250. {
  251.     new
  252.         buffer[32];
  253.     AMX_GetPublicNamePrefix(timer, buffer, _A<@yT_>);
  254.     SetTimer(buffer, delay, 1);
  255. }
  256.  
  257. #else
  258.  
  259. /*============================================================================*\
  260. *==============================================================================*
  261. ================================================================================
  262. ||||                                                                        ||||
  263. ||||                         HERE BEGINS VERSION 2!                         ||||
  264. ||||                                                                        ||||
  265. ================================================================================
  266. *==============================================================================*
  267. \*============================================================================*/
  268.  
  269. #include <YSI\internal\y_version>
  270. #include <YSI\y_amx>
  271. #include <YSI\internal\y_shortfunc>
  272. #include <YSI\y_malloc>
  273. #include <YSI\y_iterate>
  274. // This will be called twice and means there are two separate OnScriptInit
  275. // functions in this file.
  276. #include <YSI\y_hooks>
  277. #include <YSI\y_debug>
  278.  
  279. #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()
  280.  
  281. #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)
  282.  
  283. #define pause%0; {J@=_:@Ym:%0@yT_(0,-1);}
  284. #define resume%0; {J@=_:@Ym:%0@yT_(1,-1);}
  285. #define @Ym:%0:%1@yT_(%2,-1) %0@yT_(%2,%1)
  286.  
  287. static stock
  288.     Alloc:YSI_g_sLastSlot = NO_ALLOC,
  289.     Alloc:YSI_g_sFirstSlot = NO_ALLOC,
  290.     YSI_g_sPlayerTimers = -1;
  291.  
  292. hook OnScriptInit()
  293. {
  294.     P:1("hook Timers_OnScriptInit called");
  295.     new
  296.         pointer,
  297.         time,
  298.         idx,
  299.         entry;
  300.     while ((idx = AMX_GetPublicEntrySuffix(idx, entry, _A<@yT_>)))
  301.     //while ((idx = AMX_GetPublicPointerSuffix(idx, pointer, _A<@yT_>)))
  302.     {
  303.         P:6("Timer_OnScriptInit: entry: %d", entry);
  304.         #emit LREF.S.pri entry
  305.         #emit STOR.S.pri pointer
  306.         //YSI_g_sCurFunc = pointer;
  307.         // Don't bother with the real name, call the function by address to get
  308.         // the time the function runs for.
  309.         P:7("Timer_OnScriptInit: pointer: %d", pointer);
  310.         // Push the address of the current function.
  311.         #emit PUSH.S     pointer
  312.         #emit PUSH.C     0xFFFFFFFF
  313.         #emit PUSH.C     8
  314.         #emit LCTRL      6
  315.         #emit ADD.C      28
  316.         #emit PUSH.pri
  317.         #emit LOAD.S.pri pointer
  318.         #emit SCTRL      6
  319.         #emit STOR.S.pri time
  320.         //YSI_g_sCurFunc = 0;
  321.         P:7("Timer_OnScriptInit: time: %d", time);
  322.         if (time != -1)
  323.         {
  324.             // Find all the functions with the same time.  This is less
  325.             // efficient than previous implementations (it is O(N^2)), but also
  326.             // more robust as it won't fail no matter how many different times
  327.             // there are - old ones relied on an array with a finite size.
  328.             new
  329.                 pointer2,
  330.                 time2,
  331.                 idx2,
  332.                 total,
  333.                 pre;
  334.             while ((idx2 = AMX_GetPublicPointerSuffix(idx2, pointer2, _A<@yT_>)))
  335.             {
  336.                 // Call the functions a second time to guarantee getting
  337.                 #emit PUSH.C     0
  338.                 #emit PUSH.C     0xFFFFFFFF
  339.                 #emit PUSH.C     8
  340.                 #emit LCTRL      6
  341.                 #emit ADD.C      28
  342.                 #emit PUSH.pri
  343.                 #emit LOAD.S.pri pointer2
  344.                 #emit SCTRL      6
  345.                 #emit STOR.S.pri time2
  346.                 if (time2 == time)
  347.                 {
  348.                     ++total;
  349.                     if (idx2 < idx)
  350.                     {
  351.                         ++pre;
  352.                     }
  353.                 }
  354.             }
  355.             P:7("Timer_OnScriptInit: total: %d, time: %d, pre: %d", total, time, pre);
  356.             // Now we know what time this function has, how many others have
  357.             // that time and how many have already been started.
  358.             new
  359.                 buffer[32];
  360.             entry += 4;
  361.             #emit LREF.S.pri entry
  362.             #emit STOR.S.pri pointer
  363.             AMX_ReadString(AMX_BASE_ADDRESS + pointer, buffer);
  364.             P:7("Timer_OnScriptInit: %s", unpack(buffer));
  365.             // Get the time offset for the current call.  This should mean that
  366.             // all the functions are nicely spread out.
  367.             SetTimerEx(buffer, time * pre / total, 0, "ii", 1, -1);
  368.         }
  369.     }
  370.     P:1("hook Timers_OnScriptInit ended");
  371. }
  372.  
  373. hook OnPlayerConnect(playerid)
  374. {
  375.     P:1("hook Timers_OnPlayerConnect called: %d", playerid);
  376.     // Loop through all the per-player timers.  Correctly finds them all from a
  377.     // linked list hidden in static variables (which are really global).
  378.     new
  379.         cur = YSI_g_sPlayerTimers,
  380.         data;
  381.     while (cur != -1)
  382.     {
  383.         #emit LREF.S.pri  cur
  384.         #emit STOR.S.pri  data
  385.         P:6("Timers_OnPlayerConnect: func: %x", data);
  386.         // Start this timer for this player.
  387.         #emit PUSH.S     playerid
  388.         #emit PUSH.C     1
  389.         // Push the parameter count (in bytes).  This is actually passed to
  390.         // native functions directly.
  391.         #emit PUSH.C     8
  392.         // Call the function currently in the list to trigger the repeating
  393.         // timer.  This involves getting the current "cip" address, modifying it
  394.         // to get the return address then modifying "cip" to call the function.
  395.         #emit LCTRL      6
  396.         #emit ADD.C      28
  397.         #emit PUSH.pri
  398.         #emit LOAD.S.pri data
  399.         #emit SCTRL      6
  400.         // Returned, get the next list element.
  401.         cur += 4;
  402.         #emit LREF.S.pri  cur
  403.         #emit STOR.S.pri  cur
  404.     }
  405.     P:1("hook Timers_OnPlayerConnect ended");
  406. }
  407.  
  408. hook OnPlayerDisconnect(playerid, reason)
  409. {
  410.     P:1("hook Timers_OnPlayerDisconnect called: %d, %d, playerid, reason");
  411.     // Loop through all the per-player timers.  Correctly finds them all from a
  412.     // linked list hidden in static variables (which are really global).
  413.     new
  414.         cur = YSI_g_sPlayerTimers,
  415.         data;
  416.     while (cur != -1)
  417.     {
  418.         #emit LREF.S.pri  cur
  419.         #emit STOR.S.pri  data
  420.         P:6("Timers_OnPlayerDisconnect: func: %x", data);
  421.         // End this timer for this player.
  422.         #emit PUSH.S     playerid
  423.         #emit PUSH.C     0
  424.         // Push the parameter count (in bytes).  This is actually passed to
  425.         // native functions directly.
  426.         #emit PUSH.C     8
  427.         // Call the function currently in the list to trigger the repeating
  428.         // timer.  This involves getting the current "cip" address, modifying it
  429.         // to get the return address then modifying "cip" to call the function.
  430.         #emit LCTRL      6
  431.         #emit ADD.C      28
  432.         #emit PUSH.pri
  433.         #emit LOAD.S.pri data
  434.         #emit SCTRL      6
  435.         // Returned, get the next list element.
  436.         cur += 4;
  437.         #emit LREF.S.pri  cur
  438.         #emit STOR.S.pri  cur
  439.     }
  440.     P:1("hook Timers_OnPlayerDisconnect ended");
  441. }
  442.  
  443. stock _Timer_I(func[], interval, action, &result)
  444. {
  445.     P:3("_Timer_I called");
  446.     switch (action)
  447.     {
  448.         case 0:
  449.         {
  450.             if (result != -1)
  451.             {
  452.                 KillTimer(result),
  453.                 result =- 1;
  454.             }
  455.         }
  456.         case 1:
  457.         {
  458.             if (result == -1)
  459.             {
  460.                 result = SetTimer(func, interval, 1);
  461.             }
  462.         }
  463.     }
  464.     return interval;
  465. }
  466.  
  467. // Attempt to stop or start a task, possibly for a single player.
  468. stock _Timer_D(func[], interval, const action, who, results[MAX_PLAYERS], &pause, a[2])
  469. {
  470.     P:3("_Timer_D called");
  471.     switch (action)
  472.     {
  473.         case -1:
  474.         {
  475.             if (who)
  476.             {
  477.                 a[0] = who;
  478.                 a[1] = YSI_g_sPlayerTimers;
  479.                 // Store the address of the global array.
  480.                 #emit LOAD.S.pri  a
  481.                 #emit STOR.pri    YSI_g_sPlayerTimers
  482.             }
  483.         }
  484.         case 0:
  485.         {
  486.             // Stop the timer.
  487.             if (who == -1)
  488.             {
  489.                 pause = 0;
  490.             }
  491.             else if (results[who] != -1)
  492.             {
  493.                 KillTimer(results[who]);
  494.                 results[who] = -1;
  495.             }
  496.         }
  497.         case 1:
  498.         {
  499.             // Start the timer.
  500.             if (who == -1)
  501.             {
  502.                 pause = 1;
  503.             }
  504.             else if (results[who] == -1)
  505.             {
  506.                 results[who] = SetTimerEx(func, interval, true, "i", who);
  507.             }
  508.         }
  509.     }
  510.     // No global interval for per-player timers.
  511.     return -1;
  512. }
  513.  
  514. static stock Alloc:Timer_GetSingleSlot(len)
  515. {
  516.     // Allocates memory and secretly appends data to the start.
  517.     P:4("Timer_GetSingleSlot called: %d", len);
  518.     new
  519.         Alloc:slot = malloc(len + 1);
  520.     if (slot == NO_ALLOC)
  521.     {
  522.         return NO_ALLOC;
  523.     }
  524.     P:5("Timer_GetSingleSlot: %d, %d, %d", _:YSI_g_sFirstSlot, _:YSI_g_sLastSlot, _:slot);
  525.     // Standard linked list.
  526.     if (YSI_g_sFirstSlot == NO_ALLOC)
  527.     {
  528.         YSI_g_sFirstSlot = slot;
  529.     }
  530.     else
  531.     {
  532.         mset(YSI_g_sLastSlot, 0, _:slot);
  533.     }
  534.     YSI_g_sLastSlot = slot;
  535.     mset(YSI_g_sLastSlot, 0, -1);
  536.     return slot;// + Alloc:1;
  537. }
  538.  
  539. // Allocate memory to store a string.
  540. stock _Timer_S(string:str[])
  541. {
  542.     P:3("_Timer_S called");
  543.     new
  544.         len = strlen(str);
  545.     if (len & 0x0F)
  546.     {
  547.         len = (len & ~0x0F) + 32;
  548.     }
  549.     new
  550.         Alloc:slot = Timer_GetSingleSlot(len + 1);
  551.     if (slot != NO_ALLOC)
  552.     {
  553.         msets(slot, 1, str);
  554.     }
  555.     P:5("str: %d", _:slot);
  556.     return _:slot + 1;
  557. }
  558.  
  559. // Allocate memory to store an array.
  560. stock _Timer_A(str[], len)
  561. {
  562.     P:3("_Timer_A called");
  563.     new
  564.         Alloc:slot = Timer_GetSingleSlot(len);
  565.     if (slot != NO_ALLOC)
  566.     {
  567.         mseta(slot, 1, str, len);
  568.     }
  569.     P:5("str: %d", _:slot);
  570.     return _:slot + 1;
  571. }
  572.  
  573. stock
  574.     I@ = -1;
  575.  
  576. // Create the timer setup.
  577. stock _Timer_C(timer, g)
  578. {
  579.     P:3("_Timer_C called: %d, %d", timer, g);
  580.     //P:3("_Timer_C called: %d", timer);
  581.     // This is done here for convenience.
  582.     I@ = -1;
  583.     // Only repeating timers are freed like this.
  584.     // UPDATE: Now all timers with array parameters, regardless of repeat status
  585.     // are freed like this.  Only timers with no malloc aren't.
  586.     if (g)
  587.     {
  588.         new
  589.             Alloc:slot = Timer_GetSingleSlot(1);
  590.         P:5("_Timer_C: slot = %d", _:slot);
  591.         if (slot == NO_ALLOC)
  592.         {
  593.             // Not a graceful fail!
  594.             return 0;
  595.         }
  596.         mset(slot, 1, timer);
  597.         // Just so it isn't a real timer ID (or possibly isn't).
  598.         slot = ~YSI_g_sFirstSlot;// ^ Alloc:-1;
  599.         YSI_g_sFirstSlot = NO_ALLOC;
  600.         YSI_g_sLastSlot = NO_ALLOC;
  601.         return _:slot;
  602.     }
  603.     // Reset these variables on all timers, including self-cleaning ones.
  604.     YSI_g_sFirstSlot = NO_ALLOC;
  605.     YSI_g_sLastSlot = NO_ALLOC;
  606.     return timer;
  607. }
  608.  
  609. // Free all timer resources.
  610. stock _Timer_F(slot)
  611. {
  612.     P:3("_Timer_F called");
  613.     // This is done here for convenience.
  614.     if (slot & 0x80000000)
  615.     {
  616.         new
  617.             next;
  618.         slot = ~slot; //^= -1;
  619.         for ( ; ; )
  620.         {
  621.             next = mget(Alloc:slot, 0);
  622.             P:6("_Timer_F: slot = %d, next = %d", slot, next);
  623.             // Out of stored strings and arrays.
  624.             if (next == -1)
  625.             {
  626.                 KillTimer(mget(Alloc:slot, 1));
  627.                 free(Alloc:slot);
  628.                 break;
  629.             }
  630.             free(Alloc:slot);
  631.             slot = next;
  632.         }
  633.     }
  634.     else
  635.     {
  636.         KillTimer(slot);
  637.     }
  638.     return 1;
  639. }
  640.  
  641. // Free one timer resource.
  642. /*stock _Timer_H(slot)
  643. {
  644.     P:3("_Timer_H called");
  645.     // This is done here for convenience.
  646.     free(Alloc:(slot - 1));
  647. }*/
  648.  
  649. // Free one timer resource.  Now actually frees many, not just one.
  650. /*stock _Timer_H(...)
  651. {
  652.     P:3("_Timer_H called");
  653.     new
  654.         c = numargs();
  655.     while (c--)
  656.     {
  657.         // This is done here for convenience.
  658.         free(Alloc:(getarg(c) - 1));
  659.     }
  660. }*/
  661.  
  662. stock _Timer_H(slot)
  663. {
  664.     _Timer_F(~(slot - 1));
  665. }
  666.  
  667. // These are the tag-type definitions for the various possible parameter types.
  668. // Array-like definitions.
  669. #define @Yf:@Yg:@Yh:#%0#%1|||%3[%4]|||%5,%6;%8>%9||| @Ye:@Yw:#%0#%1|||%3[%4]|||%5,%6;%9|||
  670.  
  671. #define @Ye:@Yw:#%0#%1|||%2string:%3[%4]|||%5,%6;%9||| @Yf:@Yg:@Yh:#%0d#%1,_Timer_S(%3)|||%5|||%6;1>%9,@Yv&%3&|||
  672.  
  673. // This one has an extra parameter because arrays must always be followed by
  674. // their length.
  675. #define @Yw:#%0#%1|||%3[%4]|||%5,%6,%7;%9||| @Yf:@Yg:@Yh:#%0d#%1,_Timer_A(%3,%5)|||%5|||%6,%7;1>%9,@Yv&%3&|||
  676.  
  677. // Tag-like definitions.
  678. #define @Yg:@Yh:#%0#%1|||%2:%3|||%5,%6;%8>%9||| @Yf:@Yg:@Yh:#%0d#%1,%2:%3|||%5|||%6;%8>%9,%2:%3|||
  679.  
  680. // Others.
  681. #define @Yh:#%0#%1|||%3|||%5,%6;%8>%9||| @Yf:@Yg:@Yh:#%0d#%1,%3|||%5|||%6;%8>%9,%3|||
  682.  
  683. // Main entry point for defer type determination.
  684. #define _YT@CR:%0,%1)%8>%2||| @Yf:@Yg:@Yh:#i#,@Yx:J@|||%0|||%1;%8>%2|||
  685.  
  686. // Define for "defer" with timer, parameters and main function.
  687. #define timer%0[%1]%3(%2) stock%0_yT@(%2)return _Timer_C(O@(#%0@_yT,I@==-1?(%1):I@,J@,_YT@CR:%2,,)0>%0|||%0|||(%2)
  688.  
  689. // Expand additional parameters out to three functions after processing.
  690. //#define @Yx:%0||||||;%1,%2|||%4||| %0),1);@Yu:%1@_yT(%2);public @Yu:%1@_yT(%2){%4(%2);}%4
  691. #define @Yx:%0||||||;%8>%1,%2|||%4||| %0),%8);@Yj:%1@_yT(__r,%2);public @Yj:%1@_yT(__r,%2){%4(%2);}%4
  692.  
  693. // Can't believe I never thought of this before!  If only there was a way to
  694. // make it less generic than "id".
  695. #define id#,@Yx:J@,||||||;%8>%1,%2|||%4||| ),0);%1@_yT();public%1@_yT(){%4();}%4
  696.  
  697. // Remove excess "_Timer_G" and "_Timer_B".
  698. #define @Yj:%0{%1(%8&%2&%3)%9} @Yj:%0{%1(%8:YSI_gMallocMemory[%2]%3);@Yl(@Yk:%2)%9}
  699. //#define @Yu:%0{%1(%8&%2&%3)%9} @Yu:%0{%1(%8:YSI_gMallocMemory[%2]%3)%9}
  700. #define @Yv&%0& %0
  701.  
  702. //#define @Yk:%0);@Yl(@Yk:%1); %0,@Yk:%1);
  703. // I'm not entirely sure why this works in reverse order, but I'm glad it does!
  704. #define @Yk:%0);@Yl(@Yk:%1); @Yk:%0);
  705. #define @Yl if(!__r)_Timer_H
  706.  
  707. #define string:
  708.  
  709. #define defer%0(%1) (J@=0,Timer:%0_yT@(%1))
  710.  
  711. #define repeat%0(%1) (J@=1,Timer:%0_yT@(%1))
  712.  
  713. #define Timer:%0[%1]_yT@(%2) I@=%1,Timer:%0_yT@(%2)
  714.  
  715. #define stop%0; {_Timer_F(_:%0);}
  716.  
  717. #endif
  718.  
  719. /*============================================================================*\
  720. *==============================================================================*
  721. ================================================================================
  722. ||||                                                                        ||||
  723. ||||                     HERE BEGINS THE OLD VERSION 2!                     ||||
  724. ||||                                                                        ||||
  725. ================================================================================
  726. *==============================================================================*
  727. \*============================================================================*/
  728.  
  729. #endinput
  730.  
  731. //#define _Timer_G(%0) YSI_gMallocMemory[%0]
  732. //#define _Timer_B _Timer_G
  733.  
  734. /*#define pause_task%0; {%0@yT_(0,-1);}
  735. #define resume_task%0; {%0@yT_(1,-1);}
  736. #define pause_ptask%0; {%0@yT_(0,%1);}
  737. #define resume_ptask%0; {J@=_:@Ym:%0@yT_(1,%1);}*/
  738.  
  739. // These are the tag-type definitions for the various possible parameter types.
  740. //#define @Ya:@Yb:@Yc:@Yd:@Yz:#%0#%1|||%2string:%3[%4]|||%5,%6;%9||| @Ya:@Yb:@Yc:@Yd:@Yz:#%0d#%1,_Timer_S(%3)|||%5|||%6;%9,@Yv<<<%3>>>|||
  741. // This one has an extra parameter because arrays must always be followed by
  742. // their length.
  743. #define @Yb:@Yc:@Yd:@Yz:#%0#%1|||%3[%4]|||%5,%6;%9||| @Ya:@Yy:#%0#%1|||%3[%4]|||%5,%6;%9|||
  744. //@Ya:@Yb:@Yc:@Yd:@Yz:#%0d#%1,_Timer_A(%3,%5)|||%5|||%6,%7;%9,@Yv<<<%3>>>|||
  745.  
  746. #define @Ya:@Yy:#%0#%1|||%2string:%3[%4]|||%5,%6;%9||| @Yb:@Yc:@Yd:@Yz:#%0d#%1,_Timer_S(%3)|||%5|||%6;%9,@Yv&%3&|||
  747.  
  748. #define @Yy:#%0#%1|||%3[%4]|||%5,%6,%7;%9||| @Yb:@Yc:@Yd:@Yz:#%0d#%1,_Timer_A(%3,%5)|||%5|||%6,%7;%9,@Yv&%3&|||
  749.  
  750. #define @Yc:@Yd:@Yz:#%0#%1|||%2:%3|||%5,%6;%9||| @Yb:@Yc:@Yd:@Yz:#%0d#%1,_:%3|||%5|||%6;%9,%2:%3|||
  751.  
  752. #define @Yd:@Yz:#%0#%1|||%3|||%5,%6;%9||| @Yb:@Yc:@Yd:@Yz:#%0d#%1,%3|||%5|||%6;%9,%3|||
  753.  
  754. // Main entry point for defer type determination.
  755. #define _YT@CT:%0,%1)%3;%2||| @Yb:@Yc:@Yd:@Yz:##|||%0|||%1;%2|||
  756.  
  757. // Detect zero parameters.
  758. #define O@(#%0,%1,%2,%6:,,)%7;%3|||%5||| K@(#%0,%1,%2),%7);%3@_yT();public%3@_yT(){%5();}%5
  759. //#define @Ye:__@Yf=%4)%5O@(#%0#__@Yf,%2,_YT@CT:,,;%3||| __@Yg=%4)return K@(#%0#,__@Yg,%2);%3@_yT();public%3@_yT(){%3_yT@();}
  760.  
  761. // Define for "defer" with timer, parameters and main function.
  762. #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)
  763.  
  764. // This is called if we need to add a leading comma to the time parameter.
  765. //#define __@Yf ,__@Yg
  766.  
  767. // Expand additional parameters out to three functions after processing.
  768. //#define @Yz:%0||||||;%1,%2|||%3|||%4||| @Yy:@Yw:%0),0);%1@_yT(%2);public%1@_yT(%2){%4(%2);}%3%4
  769. #define @Yz:%0||||||;%1,%2|||%4||| %0),0);@Yj:%1@_yT(%2);public @Yj:%1@_yT(%2){%4(%2);}%4
  770.  
  771. // Remove excess "_Timer_G" and "_Timer_B".
  772. //#define @Yy:@Yw:%0;%1(%2_Timer_G(%3)%4);%5(%6_Timer_G(%7)%8){%9} @Yy:@Yw:%0;%1(%2%3%4);%5(%6%7%8){%9_Timer_H(%3);}
  773. //#define @Yw:%0;%1(%2_Timer_B(%3)%4);%5(%6_Timer_B(%7)%8){%9} @Yy:@Yw:%0;%1(%2%3%4);%5(%6%7%8){%9_Timer_H(%3);}
  774.  
  775. // Define for "force" to call function quickly.
  776. //#define force%0[%1](%2) (J@=_:@Yr:@Yq:%0:%1(%2))
  777. #define force%0(%2) (%0_yT@(%2))
  778.  
  779. #define @Yr:@Yq:%0:%2-1(%2) %0_yT@(%2)
  780.  
  781. #define @Yq:%0:%1(%2) (I@=(%1),%0(%2))
  782.  
  783. #define @%0:%1(%2) (@Yr:@Yq:%1:%0(%2))
  784. #define after%0(%2) (I@=0,%0(%2))
  785.  
  786. // This is the start of the "repeat" code - code for looping timers.
  787.  
  788. // These are the tag-type definitions for the various possible parameter types.
  789. #define @Yf:@Yg:@Yh:@Yx:#%0#%1|||%3[%4]|||%5,%6;%9||| @Ye:@Yw:#%0#%1|||%3[%4]|||%5,%6;%9|||
  790.  
  791. #define @Ye:@Yw:#%0#%1|||%2string:%3[%4]|||%5,%6;%9||| @Yf:@Yg:@Yh:@Yx:#%0d#%1,_Timer_S(%3)|||%5|||%6;%9,@Yv&%3&|||
  792.  
  793. #define @Yw:#%0#%1|||%3[%4]|||%5,%6,%7;%9||| @Yf:@Yg:@Yh:@Yx:#%0d#%1,_Timer_A(%3,%5)|||%5|||%6,%7;%9,@Yv&%3&|||
  794. // This one has an extra parameter because arrays must always be followed by
  795. // their length.
  796. //#define @Yf:@Yg:@Yh:@Yx:#%0#%1|||%3[%4]|||%5,%6,%7;%9||| @Yf:@Yg:@Yh:@Yx:#%0d#%1,_Timer_A(%3,%5)|||%5|||%6,%7;%9,@Yv<<<%3>>>|||
  797.  
  798. #define @Yg:@Yh:@Yx:#%0#%1|||%2:%3|||%5,%6;%9||| @Yf:@Yg:@Yh:@Yx:#%0d#%1,%2:%3|||%5|||%6;%9,%2:%3|||
  799.  
  800. #define @Yh:@Yx:#%0#%1|||%3|||%5,%6;%9||| @Yf:@Yg:@Yh:@Yx:#%0d#%1,%3|||%5|||%6;%9,%3|||
  801.  
  802. // Main entry point for defer type determination.
  803. #define _YT@CR:%0,%1)%3;%2||| @Yf:@Yg:@Yh:@Yx:##|||%0|||%1;%2|||
  804.  
  805. //#define O@(#%0,%1,%2,%6:,,)%7;%3|||%4|||%5||| K@(#%0,%1,%2),%7);%3@_yT();public%3@_yT(){%5();}%4%5
  806. // Define for "defer" with timer, parameters and main function.
  807. //#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)
  808. #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)
  809.  
  810. //#define @Yi(%0) return _Timer_F(%0);
  811.  
  812. // This is called if we need to add a leading comma to the time parameter.
  813. //#define __@Yf ,__@Yg
  814.  
  815. // Expand additional parameters out to three functions after processing.
  816. //#define @Yx:%0||||||;%1,%2|||%3|||%4||| @Yu:@Yv:%0),1);%1@_yT(%2);public%1@_yT(%2){%4(%2);}%3%4
  817. #define @Yx:%0||||||;%1,%2|||%4||| %0),1);@Yu:%1@_yT(%2);public @Yu:%1@_yT(%2){%4(%2);}%4
  818.  
  819. // Remove excess "_Timer_G" and "_Timer_B".
  820. //#define @Yu:@Yv:%0;%1(%2_Timer_G(%3)%4);%5(%6_Timer_G(%7)%8) @Yu:@Yv:%0;%1(%2%3%4);%5(%6%7%8)
  821. //#define @Yv:%0;%1(%2_Timer_B(%3)%4);%5(%6_Timer_B(%7)%8) @Yu:@Yv:%0;%1(%2%3%4);%5(%6%7%8)
  822.  
  823. #define @Yj:%0{%1(%8&%2&%3)%9} @Yj:%0{%1(%8:YSI_gMallocMemory[%2]%3);@Yl(@Yk:%2)%9}
  824. #define @Yu:%0{%1(%8&%2&%3)%9} @Yu:%0{%1(%8:YSI_gMallocMemory[%2]%3)%9}
  825. #define @Yv&%0& %0
  826.  
  827. #define @Yk:%0);@Yl(@Yk:%1); %0,@Yk:%1);
  828. #define @Yl _Timer_H
  829.  
  830. //#define start%0(%1) (J@=%0_yT@(%1))
  831. #define start%0(%1) (Timer:%0_yT@(%1))
  832. #define stop%1; {_Timer_F(%1);}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement