There is a new version of the forums ready for testing. Please post here if you're willing to help test! We could also use the help of coders!

Author Topic: MODULE: Mouse Gesture System v1.0  (Read 5079 times)

Besh

  • Save the nature ... kill yourself.
    • I can help with translating
    • Besh worked on one or more games that was nominated for an AGS Award!
MODULE: Mouse Gesture System v1.0
« on: 09 Jun 2006, 13:17 »
MOUSE GESTURE SYSTEM script module

The idea of this system was born when I start to work to "Child of the Moon". I coded this to cast spell in a way that looks like "Black & White" miracles.

This first version recognizes 20 different gestures (4 lines, 8 circles, 8 arrows).

Download MGS 1.0 (requires AGS 2.71 or later, not tested on previous versions)
Simple demo (requires AGS 2.71 or later, not tested on previous versions)

Code: [Select]
// Script header for module 'Mouse Gesture System'
//
// Author: Gabriel Ferri (Besh)
//   Please contact me about problems with this module.
//
// Abstract: This system recognizes the mouse movements.
//
// Dependencies: AGS 2.71 or later (not tested on previous versions)
//
// Functions:
// MouseGesture.Activate(bool state)
//      Activates/deactivated Mouse Gesture System.
//
//   MouseGesture.SetMouseButton(MouseButton button)
//      Sets the mouse button used for the gesture. The default is LEFT mouse button.
// Actually, only LEFT and RIGHT mouse buttons are allowed.
//
//   MouseGesture.AddLine(GesturePoint direction, float tolerance, String name)
//      This adds a simple line gesture.
// direction: specifies the direction of the movement (eLeft, eRight, eUp, eDown).
// tolerance: is an absolute value used to simplify the movement (from 0.0 impossible to 4.0/5.0 simple)
// name: is the value returned by the system if this gesture is recognized.
//     
//   MouseGesture.AddCircle(GesturePoint start, GestureDirection direction, float tolerance, String name)
//      This adds a circle gesture.
// start: specifies the gesture starting point (eLeft, eRight, eUp, eDown).
// direction: specifies the direction of the movement (eClockwise, eCounterClockwise).
// tolerance: is an absolute value used to simplify the movement (from 0.0 impossible to 15.0/20.0 simple)
// name: is the value returned by the system if this gesture is recognized.
//
//   MouseGesture.AddArrow(GesturePoint arrowhead, GestureDirection direction, float tolerance, String name)
//      This adds an arrow gesture.
// arrowhead: specifies where the arrow is aiming (eLeft, eRight, eUp, eDown).
// direction: specifies the direction of the movement (eClockwise, eCounterClockwise).
// tolerance: is an absolute value used to simplify the movement (from 0.0 impossible to 10.0/15.0 simple)
// name: is the value returned by the system if this gesture is recognized.
//
// Srting MouseGesture.Name
// Contains the name of the recognized gesture.
//
// float MouseGesture.Vote
// Contains the vote of the recognized gesture (from 0.0 no gesture to 1.0 perfect gesture).
//
// bool MouseGesture.isGesture
// Sets to 1 when by the system when a new gesture is recognized.
//
//
//
// Use:
//    Add gestures and give them a name. Remenber to activate the system.
//
// IMPORTANT - in repeaditely_execute function add:
// if (MouseGesture.isGesture) {
// MouseGesture.isGesture = false;
// ...
// ...
// }
//
// This code is needful to capture recognized gesture (not a great solution but works fine :-))
//
// Example:
// MouseGesture.AddArrow(eUp, eClockwise, 10.0, "ArrowUp");
//   MouseGesture.AddCircle(eRight, eCounterClockwise, 15.0, "Circle");
//   MouseGesture.AddLine(eLeft, 5.0, "LineSX");
// MouseGesture.AddLine(eRight, 5.0, "LineDX");
//
// ...
//
// //script for Room: Repeatedly execute
//  if (MouseGesture.isGesture) {
//    MouseGesture.isGesture = false;
// 
// if (MouseGesture.Name == "ArrowUp")
// Function1();
// else if ((MouseGesture.Name == "Circle") && (MouseGesture.Vote >= 0.6))
// Function2();
// else if (MouseGesture.Name == "LineDX")
// Function3();
// else if (MouseGesture.Name == "")
// // no gesture recognized
// }
//
//
//
// Revision History:
//
// 09 Jun 06: v1.0  First release of Mouse Gesture System module
//
// Licence:
//
//   AGS Mouse Gesture System script module
//   Copyright (C) 2005-2006 Gabriel Ferri
//
//   This library is free software; you can redistribute it and/or
//   modify it under the terms of the GNU Lesser General Public
//   License as published by the Free Software Foundation; either
//   version 2.1 of the License, or (at your option) any later version.
//
//   This library is distributed in the hope that it will be useful,
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//   Lesser General Public License for more details.
//
//   You should have received a copy of the GNU Lesser General Public
//   License along with this library; if not, write to the Free Software
//   Foundation, Inc, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//=========================================================


What do you think? Let me know.
« Last Edit: 29 Jun 2006, 15:51 by Scorpiorus »
"Spread our codes to the stars,
You can rescue us all"
 - Muse

SSH

  • Flying round the world at the speed of haggis
    • I can help with scripting
    • SSH worked on one or more games that won an AGS Award!
    •  
    • SSH worked on one or more games that was nominated for an AGS Award!
Re: MODULE: Mouse Gesture System 1.0
« Reply #1 on: 09 Jun 2006, 14:48 »
Looks excellent! Good work, besh!

Radiant

  • Mittens Knight
  • AGS Baker
  • Return once more to the Two Kingdoms!
    • I can help with story design
    • I can help with publishing
    • Radiant worked on one or more games that won an AGS Award!
    •  
    • Radiant worked on one or more games that was nominated for an AGS Award!
Re: MODULE: Mouse Gesture System 1.0
« Reply #2 on: 09 Jun 2006, 17:30 »
That's actually a rather nifty idea! I can see some cool games using this...

Re: MODULE: Mouse Gesture System 1.0
« Reply #3 on: 09 Jun 2006, 18:41 »

I tried "child of the moon" and I found the mousing impossibly difficult, maybe some kind of mouse trail would help poor inepts like me.
†œThere is much pleasure to be gained from useless knowledge.†
The Restroom Wall

Re: MODULE: Mouse Gesture System 1.0
« Reply #4 on: 10 Jun 2006, 11:11 »
Looks good, i'll add it to my site around monday.

magintz

  • Mittens Knight
  • Just because I rock doesn't mean I'm made of stone
    • I can help with story design
    • I can help with web design
    • magintz worked on one or more games that was nominated for an AGS Award!
Re: MODULE: Mouse Gesture System v1.0
« Reply #5 on: 08 Jul 2006, 00:48 »
I had something similar in the works a while back where a verb coin type thing would appear and allow you to draw gestures within this GUI. I was working on it picking up angles of movement for general gestures and also speed, so that some puzzles may include throwing a ball or something and require speed and angle.

My main purpose of doing this was to have it like the firefox mouse gestures where "right click and drag" in various directions would perform simple actions such as look at or pick up emminating around the start point, which would be the hotspot...


This project however never progressed. I'm thinking of doing something using the drop down menu module but mixing it with a verb coin style and using context sensitive user actions, such as a window having open window and a candle having light or blow out.
When I was a little kid we had a sand box. It was a quicksand box. I was an only child... eventually.

Babar

  • Creator, Mutator and Defecator
    • I can help with proof reading
    • I can help with scripting
    • I can help with story design
    • I can help with translating
    • Babar worked on one or more games that won an AGS Award!
    •  
    • Babar worked on one or more games that was nominated for an AGS Award!
Re: MODULE: Mouse Gesture System v1.0
« Reply #6 on: 08 Jul 2006, 14:09 »
Not sure if I understand what this does. Is it like the SPELLBOUND game that MrColossal made?
The ultimate Professional Amateur

Now, with his very own game: Alien Time Zone

cat

  • Mittens Baronet
  • Global Moderator
  • AGS Baker
    • Lifetime Achievement Award Winner
    • cat worked on one or more games that won an AGS Award!
    •  
    • cat worked on one or more games that was nominated for an AGS Award!
Re: MODULE: Mouse Gesture System v1.0
« Reply #7 on: 14 Jun 2022, 20:33 »
Long time ago I made a few modifications to this module for my game Kanji Gakusei. I forgot to upload the modifications which is required by the license so here are the files that my project uses:

MouseGestureSystem.ash
Code: Adventure Game Studio
  1. // Script header for module 'Mouse Gesture System'
  2. //
  3. // Author: Gabriel Ferri (Besh)
  4. //   Please contact me about problems with this module.
  5. //
  6. // Enhanced and converted to AGS 3.3.0 by cat
  7. //
  8. // Abstract: This system recognizes the mouse movements.
  9. //
  10. // Dependencies: AGS 3.3.0 or later (not tested on previous versions)
  11. //
  12. // Functions:
  13. //       MouseGesture.Activate(bool state)
  14. //      Activates/deactivated Mouse Gesture System.
  15. //
  16. //   MouseGesture.SetMouseButton(MouseButton button)
  17. //      Sets the mouse button used for the gesture. The default is LEFT mouse button.
  18. //                      Actually, only LEFT and RIGHT mouse buttons are allowed.
  19. //
  20. //   MouseGesture.AddLine(GesturePoint direction, float tolerance, String name)
  21. //      This adds a simple line gesture.
  22. //                              direction: specifies the direction of the movement (eLeft, eRight, eUp, eDown).
  23. //                              tolerance: is an absolute value used to simplify the movement (from 0.0 impossible to 4.0/5.0 simple)
  24. //                              name: is the value returned by the system if this gesture is recognized.
  25. //      
  26. //   MouseGesture.AddCircle(GesturePoint start, GestureDirection direction, float tolerance, String name)
  27. //      This adds a circle gesture.
  28. //                              start: specifies the gesture starting point (eLeft, eRight, eUp, eDown).
  29. //                              direction: specifies the direction of the movement (eClockwise, eCounterClockwise).
  30. //                              tolerance: is an absolute value used to simplify the movement (from 0.0 impossible to 15.0/20.0 simple)
  31. //                              name: is the value returned by the system if this gesture is recognized.
  32. //
  33. //   MouseGesture.AddArrow(GesturePoint arrowhead, GestureDirection direction, float tolerance, String name)
  34. //      This adds an arrow gesture.
  35. //                              arrowhead: specifies where the arrow is aiming (eLeft, eRight, eUp, eDown).
  36. //                              direction: specifies the direction of the movement (eClockwise, eCounterClockwise).
  37. //                              tolerance: is an absolute value used to simplify the movement (from 0.0 impossible to 10.0/15.0 simple)
  38. //                              name: is the value returned by the system if this gesture is recognized.
  39. //
  40. //       Srting MouseGesture.Name
  41. //                      Contains the name of the recognized gesture.
  42. //
  43. //       float MouseGesture.Vote
  44. //                      Contains the vote of the recognized gesture (from 0.0 no gesture to 1.0 perfect gesture).
  45. //
  46. //       bool MouseGesture.isGesture
  47. //                      Sets to 1 when by the system when a new gesture is recognized.
  48. //
  49. //
  50. //
  51. // Use:
  52. //      Add gestures and give them a name. Remenber to activate the system.
  53. //
  54. //      IMPORTANT - in repeaditely_execute function add:
  55. //                      if (MouseGesture.isGesture) {
  56. //                              MouseGesture.isGesture = false;
  57. //                              ...
  58. //                              ...
  59. //                      }
  60. //     
  61. //              This code is needful to capture recognized gesture (not a great solution but works fine :-))
  62. //
  63. // Example:
  64. //              MouseGesture.AddArrow(eUp, eClockwise, 10.0, "ArrowUp");
  65. //        MouseGesture.AddCircle(eRight, eCounterClockwise, 15.0, "Circle");
  66. //        MouseGesture.AddLine(eLeft, 5.0, "LineSX");
  67. //              MouseGesture.AddLine(eRight, 5.0, "LineDX");
  68. //
  69. //              ...
  70. //
  71. //              //script for Room: Repeatedly execute
  72. //      if (MouseGesture.isGesture) {
  73. //      MouseGesture.isGesture = false;
  74. //  
  75. //                      if (MouseGesture.Name == "ArrowUp")
  76. //                              Function1();
  77. //                      else if ((MouseGesture.Name == "Circle") && (MouseGesture.Vote >= 0.6))
  78. //                              Function2();
  79. //                      else if (MouseGesture.Name == "LineDX")
  80. //                              Function3();
  81. //                      else if (MouseGesture.Name == "")
  82. //                              // no gesture recognized
  83. //              }
  84. //
  85. //
  86. //
  87. // Revision History:
  88. //
  89. //              09 Jun 06: v1.0  First release of Mouse Gesture System module
  90. //
  91. // Licence:
  92. //
  93. //   AGS Mouse Gesture System script module
  94. //   Copyright (C) 2005-2006 Gabriel Ferri
  95. //
  96. //   This library is free software; you can redistribute it and/or
  97. //   modify it under the terms of the GNU Lesser General Public
  98. //   License as published by the Free Software Foundation; either
  99. //   version 2.1 of the License, or (at your option) any later version.
  100. //
  101. //   This library is distributed in the hope that it will be useful,
  102. //   but WITHOUT ANY WARRANTY; without even the implied warranty of
  103. //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  104. //   Lesser General Public License for more details.
  105. //
  106. //   You should have received a copy of the GNU Lesser General Public
  107. //   License along with this library; if not, write to the Free Software
  108. //   Foundation, Inc, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  109. //=========================================================
  110.  
  111. enum GesturePoint { eUp, eDown, eRight, eLeft, eUndefined };
  112. enum GestureDirection { eClockwise, eCounterClockwise };
  113. enum GestureRegionViolationAction { eGestureNone, eGestureIgnore, eGestureFail };
  114.  
  115. autoptr managed struct GestureRegion
  116. {
  117.     int Top;
  118.     int Right;
  119.     int Bottom;
  120.     int Left;
  121.    
  122.     import static GestureRegion Create(int top, int right, int bottom, int left);
  123. };
  124.  
  125. struct sMouseGesture {
  126.    import function SetWorkspace(GestureRegion workspace);
  127.    import function Activate(bool state);
  128.         import function SetMouseButton(MouseButton button);
  129.    import function SetRegion(GestureRegion gestureRegion);
  130.         import function AddLine(GesturePoint direction, float tolerance, String name, );
  131.    import function AddCustomLine(float angle, float tolerance, String name);
  132.         import function AddCircle(GesturePoint start, GestureDirection direction, float tolerance, String name);
  133.         import function AddArrow(GesturePoint arrowhead, GestureDirection direction, float tolerance, String name);
  134.    import function AddCustomArrow(float angles[], int arraySize, float tolerance, String name);
  135.    import function Reset();
  136.        
  137.         bool isGesture;
  138.         float Vote;
  139.         String Name;
  140.   GestureRegionViolationAction RegionViolationAction;
  141. };
  142.  
  143. import sMouseGesture MouseGesture;
  144.  

MouseGestureSystem.asc
Code: Adventure Game Studio
  1. // Main script for module 'Mouse Gesture System'
  2. #define MAX_GESTURES 32
  3.  
  4. // internal parameters
  5. #define MAX_POINTS      128
  6. #define MIN_DISTANCE 15.0
  7. #define MAX_SEGMENTS 32
  8.  
  9. // internal struct and variables
  10. enum GestureShape { eLine, eCircle, eArrow, eUser };
  11.  
  12. struct GestureObj {
  13.   GestureShape shape;
  14.   GesturePoint point;
  15.   GestureDirection direction;
  16.   String name;
  17.  
  18.   float tolerance;
  19.   float vangle[MAX_SEGMENTS]; //in degrees
  20.   int vnum;
  21.  
  22.   float vote;
  23. };
  24.  
  25. // module interface
  26. sMouseGesture MouseGesture;
  27. export MouseGesture;
  28.  
  29. // is Mouse Gesture System active
  30. bool isGestureActive;
  31.  
  32. // mouse button that activate the gesture
  33. MouseButton active_button;
  34.  
  35. // region where the gesture is valid
  36. GestureRegion gestureRegion;
  37.  
  38. bool isGestureStarted;
  39. int vx[MAX_POINTS];
  40. int vy[MAX_POINTS];
  41. float vangle[MAX_SEGMENTS];
  42. int vnum;
  43.  
  44. GestureObj vGesture[MAX_GESTURES];
  45. int vGesturenum;
  46.  
  47. // workspace area where clicks are handled
  48. GestureRegion workspace;
  49.  
  50. // PUBLIC FUNCTIONS
  51.  
  52. static GestureRegion GestureRegion::Create(int top, int right, int bottom, int left)
  53. {
  54.     GestureRegion r = new GestureRegion;
  55.     r.Top = top;
  56.     r.Right = right;
  57.     r.Bottom = bottom;
  58.     r.Left = left;
  59.     return r;
  60. }
  61.  
  62. // ignore mouse clicks that are outside the workspace
  63. function sMouseGesture::SetWorkspace(GestureRegion newWorkspace)
  64. {
  65.    workspace = newWorkspace;
  66. }
  67.  
  68. function sMouseGesture::Activate (bool state) {
  69.         if (state) {
  70.                 isGestureStarted = false;
  71.                 MouseGesture.isGesture = false;
  72.         }
  73.  
  74.         isGestureActive = state;
  75. }
  76.  
  77. function sMouseGesture::Reset () {
  78.    vnum = 0;
  79.    vGesturenum = 0;
  80.    isGestureActive = false;
  81.    isGestureStarted = false;
  82.    
  83.    int i = 0;  
  84.    while (i < MAX_GESTURES)
  85.    {
  86.       vGesture[i].direction = eClockwise;
  87.       vGesture[i].name = "";
  88.       vGesture[i].point = eUndefined;
  89.       vGesture[i].shape = eUser;
  90.       vGesture[i].tolerance = 0.0;
  91.       vGesture[i].vnum = 0;
  92.       vGesture[i].vote = 0.0;
  93.      
  94.       int j = 0;
  95.       while (j < MAX_SEGMENTS)
  96.       {
  97.          vGesture[i].vangle[j] = 0.0;
  98.          j++;
  99.       }
  100.      
  101.       i++;
  102.    }
  103. }
  104.  
  105. function sMouseGesture::SetMouseButton(MouseButton button) {
  106.   if (button == eMouseRight)
  107.                 active_button = eMouseRight;
  108.         else
  109.                 active_button = eMouseLeft;    
  110. }
  111.  
  112. function sMouseGesture::SetRegion(GestureRegion newRegion) {
  113.    gestureRegion = newRegion;
  114. }
  115.  
  116. function sMouseGesture::AddLine(GesturePoint direction, float tolerance, String name) {
  117.   if (vGesturenum < MAX_GESTURES) {
  118.                 vGesture[vGesturenum].shape = eLine;
  119.                 vGesture[vGesturenum].point = direction;
  120.                 vGesture[vGesturenum].tolerance = tolerance;
  121.                 vGesture[vGesturenum].name = name;
  122.  
  123.                 if (direction == eRight) {
  124.                   vGesture[vGesturenum].vangle[0] = 90.0;
  125.                 }
  126.                 else if (direction == eLeft) {
  127.                   vGesture[vGesturenum].vangle[0] = -90.0;
  128.                 }
  129.                 else if (direction == eUp) {
  130.                   vGesture[vGesturenum].vangle[0] = 180.0;
  131.                 }
  132.                 else if (direction == eDown) {
  133.                   vGesture[vGesturenum].vangle[0] = 0.0;
  134.                 }
  135.                
  136.                 vGesture[vGesturenum].vnum = 1;
  137.  
  138.                 vGesturenum += 1;
  139.         }
  140. }
  141.  
  142. function sMouseGesture::AddCustomLine(float angle, float tolerance, String name) {
  143.    if (vGesturenum < MAX_GESTURES) {
  144.                 vGesture[vGesturenum].shape = eLine;
  145.                 vGesture[vGesturenum].point = eUndefined;
  146.                 vGesture[vGesturenum].tolerance = tolerance;
  147.                 vGesture[vGesturenum].name = name;
  148.  
  149.                 vGesture[vGesturenum].vangle[0] = angle;
  150.                
  151.                 vGesture[vGesturenum].vnum = 1;
  152.  
  153.                 vGesturenum += 1;
  154.         }
  155. }
  156.  
  157.  
  158. function sMouseGesture::AddCircle(GesturePoint start, GestureDirection direction, float tolerance, String name) {
  159.         if (vGesturenum < MAX_GESTURES) {
  160.                 vGesture[vGesturenum].shape = eCircle;
  161.                 vGesture[vGesturenum].direction = direction;
  162.                 vGesture[vGesturenum].point = start;
  163.                 vGesture[vGesturenum].tolerance = tolerance;
  164.                 vGesture[vGesturenum].name = name;
  165.                
  166.                 // i punti vengono generati a run-time
  167.       // the points are generated at run-time
  168.                 vGesture[vGesturenum].vnum = 0;
  169.                
  170.                 vGesturenum += 1;
  171.         }
  172. }
  173.  
  174.  
  175. function sMouseGesture::AddArrow(GesturePoint arrowhead, GestureDirection direction, float tolerance, String name) {
  176.         if (vGesturenum < MAX_GESTURES) {
  177.                 vGesture[vGesturenum].shape = eArrow;
  178.                 vGesture[vGesturenum].direction = direction;
  179.                 vGesture[vGesturenum].point = arrowhead;
  180.                 vGesture[vGesturenum].tolerance = tolerance;
  181.                 vGesture[vGesturenum].name = name;
  182.                
  183.                 if (arrowhead == eRight) {               
  184.                         if (direction == eClockwise) {
  185.                           vGesture[vGesturenum].vangle[0] = 45.0;
  186.                           vGesture[vGesturenum].vangle[1] = -45.0;
  187.                         }
  188.                         else {
  189.                           vGesture[vGesturenum].vangle[0] = 135.0;
  190.                           vGesture[vGesturenum].vangle[1] = -135.0;
  191.                         }
  192.                 }
  193.                 else if (arrowhead == eLeft) {
  194.                         if (direction == eClockwise) {
  195.                           vGesture[vGesturenum].vangle[0] = -135.0;
  196.                           vGesture[vGesturenum].vangle[1] = 135.0;
  197.                         }
  198.                         else {
  199.                           vGesture[vGesturenum].vangle[0] = -45.0;
  200.                           vGesture[vGesturenum].vangle[1] = 45.0;
  201.                         }
  202.                 }
  203.                 else if (arrowhead == eUp) {
  204.                         if (direction == eClockwise) {
  205.                           vGesture[vGesturenum].vangle[0] = 135.0;
  206.                           vGesture[vGesturenum].vangle[1] = 45.0;
  207.                         }
  208.                         else {
  209.                           vGesture[vGesturenum].vangle[0] = -135.0;
  210.                           vGesture[vGesturenum].vangle[1] = -45.0;
  211.                         }
  212.                 }
  213.                 else if (arrowhead == eDown) {
  214.                         if (direction == eClockwise) {
  215.                           vGesture[vGesturenum].vangle[0] = -45.0;
  216.                           vGesture[vGesturenum].vangle[1] = -135.0;
  217.                         }
  218.                         else {
  219.                           vGesture[vGesturenum].vangle[0] = 45.0;
  220.                           vGesture[vGesturenum].vangle[1] = 135.0;
  221.                         }
  222.                 }
  223.                 vGesture[vGesturenum].vnum = 2;
  224.                
  225.                 vGesturenum += 1;
  226.         }
  227. }
  228.  
  229. function sMouseGesture::AddCustomArrow(float angles[], int arraySize, float tolerance, String name) {
  230.    if (vGesturenum < MAX_GESTURES) {
  231.                 vGesture[vGesturenum].shape = eArrow;
  232.       vGesture[vGesturenum].direction = eClockwise;
  233.                 vGesture[vGesturenum].point = eUndefined;
  234.                 vGesture[vGesturenum].tolerance = tolerance;
  235.                 vGesture[vGesturenum].name = name;
  236.                
  237.       int i = 0;
  238.       while (i < arraySize)
  239.       {
  240.          vGesture[vGesturenum].vangle[i] = angles[i];
  241.          i++;
  242.       }
  243.      
  244.                 vGesture[vGesturenum].vnum = arraySize;
  245.                
  246.                 vGesturenum += 1;
  247.         }
  248. }
  249.  
  250. // INTERNAL FUNCTIONS
  251. function vReduction() {
  252.   int x_min = 320;
  253.   int y_min = 240;
  254.   int x_max = -1;
  255.   int y_max = -1;
  256.  
  257.         int i = 0;
  258.   while (i < vnum) {
  259.     if (x_min > vx[i])
  260.                         x_min = vx[i];
  261.                 if (x_max < vx[i])
  262.                         x_max = vx[i];
  263.                        
  264.                 if (y_min > vy[i])
  265.                         y_min = vy[i];
  266.                 if (y_max < vy[i])
  267.                         y_max = vy[i]; 
  268.  
  269.                 i += 1;
  270.         }
  271.        
  272.         float scale;
  273.         if (x_max - x_min > y_max - y_min)
  274.                 scale = IntToFloat(x_max - x_min) / 100.0;
  275.         else
  276.                 scale = IntToFloat(y_max - y_min) / 100.0;
  277.  
  278.         //
  279.         vx[0] = FloatToInt(IntToFloat(vx[0] - x_min) / scale);
  280.   vy[0] = FloatToInt(IntToFloat(vy[0] - y_min) / scale);
  281.  
  282.         i = 1;
  283.         int c = 1;
  284.         int x, y;
  285.   while (i < vnum && c < MAX_SEGMENTS + 1) {
  286.     x = FloatToInt(IntToFloat(vx[i] - x_min) / scale);
  287.     y = FloatToInt(IntToFloat(vy[i] - y_min) / scale);
  288.    
  289.     if (Maths.Sqrt(IntToFloat((x - vx[c - 1]) * (x - vx[c - 1]) + (y - vy[c - 1]) * (y - vy[c - 1]))) >= MIN_DISTANCE) {
  290.                   vx[c] = x;
  291.                   vy[c] = y;
  292.                  
  293.                   vangle[c - 1] = Maths.ArcTan2(IntToFloat(x - vx[c - 1]), IntToFloat(y - vy[c - 1]));
  294.                   vangle[c - 1] = Maths.RadiansToDegrees(vangle[c - 1]);
  295.  
  296.                   c += 1;
  297.                 }
  298.                 else if (i + 1 == vnum) { //è l'ultimo // it's the last
  299.                   vx[c] = x;
  300.                   vy[c] = y;
  301.                  
  302.                   vangle[c - 1] = Maths.ArcTan2(IntToFloat(x - vx[c - 1]), IntToFloat(y - vy[c - 1]));
  303.                  
  304.                   c += 1;                
  305.                 }
  306.  
  307.     i += 1;
  308.         }      
  309.         vnum = c - 1;
  310. }
  311.  
  312.  
  313. float vote;
  314. function Vote(float a, float b, float tol) {
  315.   float delta = a - b;
  316.  
  317.   // control
  318.         if (delta < -180.0)
  319.                 delta += 360.0;
  320.         else if (delta > 180.0)
  321.                 delta -= 360.0;
  322.  
  323.   // control sign
  324.   if (delta < 0.0)
  325.                 delta = -delta;
  326.        
  327.         if (delta < tol / 2.0)
  328.                 vote = 1.0;
  329.         if (delta < tol)
  330.                 vote = 1.0 - delta / (10.0 * tol);
  331.         else
  332.           vote = 1.0 - delta / (4.0 * tol);
  333. }
  334.  
  335.  
  336. function FindGesture() {
  337.         int c, k, i;
  338.         float votes[MAX_SEGMENTS];
  339.         int types[MAX_SEGMENTS];
  340.        
  341.         i = 0;
  342.         while (i < vGesturenum) {
  343.           // clear votes & types
  344.           c = 0;
  345.           while (c < vnum - 1) {
  346.             votes[c] = 0.0;
  347.             types[c] = -1;
  348.             c += 1;
  349.           }      
  350.          
  351.           // LINE
  352.           if (vGesture[i].shape == eLine) {
  353.             // voting
  354.             c = 0;
  355.             while (c < vnum - 1) {
  356.               Vote(vGesture[i].vangle[0], vangle[c], vGesture[i].tolerance);
  357.               votes[c] = vote;
  358.                        
  359.                                 c += 1;
  360.                         }
  361.                        
  362.                         // voto medio
  363.                         vGesture[i].vote = 0.0;
  364.                         c = 0;
  365.                         while (c < vnum - 1) {
  366.                           vGesture[i].vote += votes[c];
  367.                           c += 1;
  368.                         }
  369.                         vGesture[i].vote = vGesture[i].vote / IntToFloat(vnum - 1);    
  370.                        
  371.                         // controllo forma
  372.                 }
  373.                 // CIRCLE
  374.           else if (vGesture[i].shape == eCircle) {
  375.             if (vnum - 1 >= 8 || vnum - 1 >= 26) {
  376.                                 // genera cerchio in base ai segmenti ottenuti
  377.                                 float delta_angle = 360.0 / IntToFloat(vnum - 1);
  378.                                 float current_angle;
  379.                                
  380.                                 // angolo di partenza
  381.                                 if (vGesture[i].point == eUp)
  382.                                         current_angle = 90.0;
  383.                                 else if (vGesture[i].point == eRight)
  384.                                         current_angle = 0.0;
  385.                                 else if (vGesture[i].point == eDown)
  386.                                         current_angle = -90.0;
  387.                                 else if (vGesture[i].point == eLeft)
  388.                                         current_angle = 180.0;
  389.            
  390.                                 // direzione
  391.                                 if (vGesture[i].direction == eClockwise) {
  392.                                         delta_angle = -delta_angle;
  393.                                         current_angle += delta_angle;
  394.                                 }
  395.                                 else
  396.                                         current_angle = current_angle - 180.0 + delta_angle;
  397.            
  398.                                 // control
  399.                                 if (current_angle < -180.0)
  400.                                         current_angle += 360.0;
  401.                                 else if (current_angle > 180.0)
  402.                                         current_angle -= 360.0;
  403.                                        
  404.                                 // voting
  405.                                 c = 0;
  406.                                 while (c < vnum - 1) {
  407.                                         Vote(current_angle, vangle[c], vGesture[i].tolerance);
  408.                                         votes[c] = vote;
  409.              
  410.                                         //update angle
  411.                                         current_angle += delta_angle;
  412.                                        
  413.                                         // control
  414.                                         if (current_angle < -180.0)
  415.                                                 current_angle += 360.0;
  416.                                         else if (current_angle > 180.0)
  417.                                                 current_angle -= 360.0;
  418.                                
  419.                                         c += 1;
  420.                                 }
  421.                
  422.                                 // voto medio
  423.                                 vGesture[i].vote = 0.0;
  424.                                 c = 0;
  425.                                 while (c < vnum - 1) {
  426.                                         vGesture[i].vote += votes[c];
  427.                                         c += 1;
  428.                                 }
  429.                                 vGesture[i].vote = vGesture[i].vote / IntToFloat(vnum - 1);    
  430.                                
  431.                                 // controllo forma
  432.                                 if (vnum - 1 < 14 || vnum - 1 > 20)
  433.                                         vGesture[i].vote = vGesture[i].vote * 0.25;
  434.                         }
  435.                         else
  436.                                 vGesture[i].vote = 0.0;
  437.                 }
  438.                 // ARROW
  439.                 else if (vGesture[i].shape == eArrow) {
  440.             // voting
  441.             c = 0;
  442.             k = 0;
  443.             while (c < vnum - 1 && k < vGesture[i].vnum) {
  444.               Vote(vGesture[i].vangle[k], vangle[c], vGesture[i].tolerance);
  445.               votes[c] = vote;
  446.              
  447.                                 if (vote < 0.2) {
  448.                                   types[k] = c;
  449.                                         k += 1;
  450.                                         c -= 1;
  451.                                 }
  452.                                
  453.                                 c += 1;
  454.                         }
  455.                        
  456.                         // voto medio
  457.                         vGesture[i].vote = 0.0;
  458.                         c = 0;
  459.                         while (c < vnum - 1) {
  460.                           vGesture[i].vote += votes[c];
  461.                           c += 1;
  462.                         }
  463.                         vGesture[i].vote = vGesture[i].vote / IntToFloat(vnum - 1);    
  464.                        
  465.                         // controllo forma
  466.                         if (types[0] <= 0 || types[1] > -1)
  467.                                 vGesture[i].vote = 0.0;
  468.                         else {
  469.                           float a = IntToFloat(types[0]);
  470.                                        
  471.                           if ((vnum - 1 - types[0]) == 0)
  472.                                         vGesture[i].vote = 0.0;
  473.                                 else {
  474.                                   float b = IntToFloat(vnum - 1 - types[0]);
  475.                                        
  476.                                         if (a / b > 1.4 || b / a > 1.4)
  477.                                                 vGesture[i].vote = vGesture[i].vote * 0.25;
  478.                                 }
  479.                         }
  480.                 }
  481.                 else { // eUser
  482.                 }
  483.  
  484.                 i += 1;
  485.         }
  486. }
  487.  
  488.  
  489. int winner;
  490. function FindWinner() {
  491.         int i = 0;
  492.         float max_vote = 0.0;
  493.         winner = -1;
  494.        
  495.         while (i < vGesturenum) {
  496.           if (vGesture[i].vote > max_vote) {
  497.             max_vote = vGesture[i].vote;
  498.             winner = i;
  499.                 }
  500.  
  501.                 i += 1;
  502.         }
  503.        
  504.         if (winner != -1) {
  505.                 MouseGesture.Vote = max_vote;
  506.                 MouseGesture.Name = vGesture[winner].name;
  507.         }
  508.         else {
  509.           MouseGesture.Vote = 0.0;
  510.                 MouseGesture.Name = "";
  511.         }
  512.        
  513.         MouseGesture.isGesture = true;
  514. }
  515.  
  516.  
  517. function game_start () {
  518.   // init variables
  519.   isGestureActive = false;
  520.   isGestureStarted = false;
  521.   vnum = 0;
  522.   vGesturenum = 0;
  523.   active_button = eMouseLeft;
  524.   MouseGesture.RegionViolationAction = eGestureNone;
  525. }
  526.  
  527. function isOutsideRegion(int x, int y) {
  528.    if (gestureRegion != null &&
  529.       (x < gestureRegion.Left || x > gestureRegion.Right || y < gestureRegion.Top || y > gestureRegion.Bottom)) {
  530.       return true;
  531.    } else {
  532.       return false;
  533.    }
  534. }
  535.  
  536. bool isRegionFail = false;
  537.  
  538. function repeatedly_execute () {
  539.    if (isGestureActive) {
  540.       if (mouse.IsButtonDown(active_button) && isGestureStarted) {
  541.          if (MouseGesture.RegionViolationAction == eGestureIgnore && isOutsideRegion(mouse.x, mouse.y)) {
  542.             // Will be ignored, do nothing here
  543.          } else if (MouseGesture.RegionViolationAction == eGestureFail && isOutsideRegion(mouse.x, mouse.y)) {
  544.             // Remember that it is a fail, but don't stop immediately
  545.             isRegionFail = true;
  546.          }
  547.          // standard behaviour
  548.          else if ((vnum < MAX_POINTS) && ((vx[vnum - 1] != mouse.x) || (vy[vnum - 1] != mouse.y))) {             
  549.             vx[vnum] = mouse.x;
  550.             vy[vnum] = mouse.y;
  551.  
  552.             vnum += 1;
  553.          }
  554.       }
  555.       else if (isGestureStarted) {
  556.          isGestureStarted = false;
  557.  
  558.          // Gesture fails immediately
  559.          if (isRegionFail)
  560.          {
  561.             isRegionFail = false;
  562.             MouseGesture.Vote = 0.0;
  563.             MouseGesture.Name = "";
  564.             MouseGesture.isGesture = true;
  565.          }
  566.          else if (vnum > 3) {
  567.             vReduction();
  568.  
  569.             FindGesture();
  570.             FindWinner();
  571.          }
  572.       }
  573.    }
  574. }
  575.  
  576. function isOutsideWorkspace(int x, int y) {
  577.    if (workspace != null &&
  578.       (x < workspace.Left || x > workspace.Right || y < workspace.Top || y > workspace.Bottom)) {
  579.       return true;
  580.    } else {
  581.       return false;
  582.    }
  583. }
  584.  
  585. function on_mouse_click(MouseButton button) {
  586.    if (IsGamePaused() != 1 && isGestureActive && button == active_button) {
  587.       if (!isOutsideWorkspace(mouse.x, mouse.y))
  588.       {
  589.          vx[0] = mouse.x;
  590.          vy[0] = mouse.y;
  591.  
  592.          vnum = 1;    
  593.          isGestureStarted = true;
  594.       }
  595.    }
  596. }
  597.