home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2009 February / maximum-cd-2009-02.iso / DiscContents / SMC_1.6_win32.exe / src / objects / movingsprite.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2008-09-06  |  23.9 KB  |  1,139 lines

  1. /***************************************************************************
  2.  * movingsprite.cpp  -  moving sprite class
  3.  *
  4.  * Copyright (C) 2003 - 2008 Florian Richter
  5.  ***************************************************************************/
  6. /*
  7.    This program is free software; you can redistribute it and/or modify
  8.    it under the terms of the GNU General Public License as published by
  9.    the Free Software Foundation; either version 3 of the License, or
  10.    (at your option) any later version.
  11.    
  12.    You should have received a copy of the GNU General Public License
  13.    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  14. */
  15.  
  16. #include "../core/globals.h"
  17. #include "../objects/movingsprite.h"
  18. #include "../core/main.h"
  19. #include "../core/framerate.h"
  20. #include "../core/game_core.h"
  21. #include "../core/camera.h"
  22. #include "../level/level.h"
  23. #include "../user/preferences.h"
  24. #include "../input/joystick.h"
  25. #include "../audio/audio.h"
  26. #include "../player/player.h"
  27. #include "../enemies/turtle.h"
  28. #include "../input/keyboard.h"
  29. #include "../objects/box.h"
  30. #include "../video/renderer.h"
  31. #include "../video/gl_surface.h"
  32. #include "../core/sprite_manager.h"
  33.  
  34. /* *** *** *** *** *** *** *** cMovingSprite *** *** *** *** *** *** *** *** *** *** */
  35.  
  36. cMovingSprite :: cMovingSprite( GL_Surface *new_image /* = NULL */, float x /* = 0 */, float y /* = 0 */, bool del_img /* = 0 */ )
  37. : cSprite( new_image, x, y, del_img )
  38. {
  39.     cMovingSprite::Init();
  40. }
  41.  
  42. cMovingSprite :: cMovingSprite( CEGUI::XMLAttributes &attributes )
  43. : cSprite()
  44. {
  45.     cMovingSprite::Init();
  46.     cMovingSprite::Create_from_Stream( attributes );
  47. }
  48.  
  49. cMovingSprite :: ~cMovingSprite( void )
  50. {
  51.     if( delete_image && image )
  52.     {
  53.         delete image;
  54.     }
  55.  
  56.     Collisions_Clear();
  57. }
  58.  
  59. void cMovingSprite :: Init( void )
  60. {
  61.     state = STA_STAY;
  62.  
  63.     velx = 0;
  64.     vely = 0;
  65.     
  66.     direction = DIR_UNDEFINED;
  67.     start_direction = DIR_UNDEFINED;
  68.     ground_object = NULL;
  69.  
  70.     ice_resistance = 0;
  71.     freeze_counter = 0;
  72. }
  73.  
  74. cMovingSprite *cMovingSprite :: Copy( void )
  75. {
  76.     cMovingSprite *moving_sprite = new cMovingSprite( start_image, startposx, startposy );
  77.  
  78.     moving_sprite->type = type;
  79.     moving_sprite->sprite_array = sprite_array;
  80.     moving_sprite->Set_Massive_Type( massivetype );
  81.     moving_sprite->can_be_ground = can_be_ground;
  82.     moving_sprite->Set_Ignore_Camera( no_camera );
  83.     moving_sprite->Set_Shadow_Pos( shadow_pos );
  84.     moving_sprite->Set_Shadow_Color( shadow_color );
  85.  
  86.     return moving_sprite;
  87. }
  88.  
  89. void cMovingSprite :: Set_Image( GL_Surface *new_image, bool new_start_image /* = 0 */, bool del_img /* = 0 */ )
  90. {
  91.     // get a possible collision point change
  92.     GL_point col_pos_change = GL_point();
  93.  
  94.     if( image && new_image )
  95.     {
  96.         col_pos_change = new_image->col_pos - image->col_pos;
  97.     }
  98.  
  99.     cSprite::Set_Image( new_image, new_start_image, del_img );
  100.  
  101.     // handle collision point change
  102.     if( col_pos_change.x != 0 || col_pos_change.y != 0 )
  103.     {
  104.         Move( -col_pos_change.x, -col_pos_change.y, 1 );
  105.     }
  106.  
  107.     // check onground
  108.     Check_on_Ground();
  109. }
  110.  
  111. void cMovingSprite :: Set_Direction( ObjectDirection dir, bool new_start_direction /* = 0 */ )
  112. {
  113.     direction = dir;
  114.  
  115.     // turn velocity if wrong
  116.     if( ( dir == DIR_LEFT && velx > 0 ) || ( dir == DIR_RIGHT && velx < 0 ) )
  117.     {
  118.         velx *= -1;
  119.     }
  120.  
  121.     if( new_start_direction )
  122.     {
  123.         start_direction = dir;
  124.     }
  125. }
  126.  
  127. void cMovingSprite :: Set_Direction( float angle, float speed, bool new_start_direction /* = 0 */ )
  128. {
  129.     velx = cos( angle * 0.01745329f ) * speed;
  130.     vely = sin( angle * 0.01745329f ) * speed;
  131.  
  132.     Update_Direction();
  133.  
  134.     if( new_start_direction )
  135.     {
  136.         start_direction = direction;
  137.     }
  138. }
  139.  
  140. void cMovingSprite :: Auto_Slow_Down( float x_speed, float y_speed /* = 0 */ )
  141. {
  142.     // horizontal slow down
  143.     if( x_speed > 0 )
  144.     {
  145.         if( velx > 0 )
  146.         {
  147.             Add_Velocity( -x_speed, 0 );
  148.  
  149.             if( velx < 0 )
  150.             {
  151.                 velx = 0;
  152.             }
  153.         }
  154.         else if( velx < 0 )
  155.         {
  156.             Add_Velocity( x_speed, 0 );
  157.  
  158.             if( velx > 0 )
  159.             {
  160.                 velx = 0;
  161.             }
  162.         }
  163.     }
  164.  
  165.     // vertical slow down
  166.     if( y_speed > 0 )
  167.     {
  168.         if( vely > 0 )
  169.         {
  170.             Add_Velocity( 0, -y_speed );
  171.  
  172.             if( vely < 0 )
  173.             {
  174.                 vely = 0;
  175.             }
  176.         }
  177.         else if( vely < 0 )
  178.         {
  179.             Add_Velocity( 0, y_speed );
  180.  
  181.             if( vely > 0 )
  182.             {
  183.                 vely = 0;
  184.             }
  185.         }
  186.     }
  187. }
  188.  
  189. void cMovingSprite :: Move( float move_x, float move_y, bool real /* = 0 */ )
  190. {
  191.     cSprite::Move( move_x, move_y, real );
  192.  
  193.     // check/handle if moved out of level rect
  194.     Check_out_of_Level_Hor( move_x, 1 );
  195.     Check_out_of_Level_Ver( move_y, 1 );
  196. }
  197.  
  198. ObjectDirection cMovingSprite :: Col_Move( float move_x, float move_y, bool real /* = 0 */, bool force /* = 0 */, bool check_on_ground /* = 1 */ )
  199. {
  200.     // nothing to move
  201.     if( move_x == 0 && move_y == 0 )
  202.     {
  203.         return DIR_UNDEFINED;
  204.     }
  205.  
  206.     // invalid collision rect
  207.     if( col_rect.w == 0 || col_rect.h == 0 )
  208.     {
  209.         return DIR_UNDEFINED;
  210.     }
  211.  
  212.     // use speedfactor
  213.     if( !real )
  214.     {
  215.         move_x *= pFramerate->speedfactor;
  216.         move_y *= pFramerate->speedfactor;
  217.     }
  218.  
  219.     ObjectDirection collision_dir = DIR_UNDEFINED;
  220.  
  221.     // check for collisions
  222.     if( !force )
  223.     {
  224.         float posx_old = posx;
  225.         float posy_old = posy;
  226.         float posx_final = posx + move_x;
  227.         float posy_final = posy + move_y;
  228.         float check_x = move_x;
  229.         float check_y = move_y;
  230.  
  231.         // check if object collision rect is smaller as the position check size
  232.         if( check_x > col_rect.w )
  233.         {
  234.             check_x = col_rect.w;
  235.         }
  236.         else if( check_x < -col_rect.w )
  237.         {
  238.             check_x = -col_rect.w;
  239.         }
  240.  
  241.         if( check_y > col_rect.h )
  242.         {
  243.             check_y = col_rect.h;
  244.         }
  245.         else if( check_y < -col_rect.h )
  246.         {
  247.             check_y = -col_rect.h;
  248.         }
  249.  
  250.         // collision list if collisions found
  251.         cObjectCollisionType col_list;
  252.  
  253.         /* Checks in both directions simultaneous using collision rects
  254.          * if a collision occurs moves to pixel collision testing
  255.         */
  256.         while( check_x < -0.01f || check_x > 0.01f || check_y < -0.01f || check_y > 0.01f )
  257.         {
  258.             col_list = Collision_Check_Relative( check_x, check_y, 0, 0, COLLIDE_ALLOW_INTERNAL );
  259.  
  260.             if( !col_list.size() )
  261.             {
  262.                 // update horizontal
  263.                 if( check_x != 0 )
  264.                 {
  265.                     posx += check_x;
  266.  
  267.                     if( ( check_x > 0 && posx_final <= posx ) || ( check_x < 0 && posx_final >= posx ) )
  268.                     {
  269.                         posx = posx_final;
  270.                         check_x = 0;
  271.                     }
  272.                 }
  273.  
  274.                 // update vertical
  275.                 if( check_y != 0 )
  276.                 {
  277.                     posy += check_y;
  278.  
  279.                     if( ( check_y > 0 && posy_final <= posy ) || ( check_y < 0 && posy_final >= posy ) )
  280.                     {
  281.                         posy = posy_final;
  282.                         check_y = 0;
  283.                     }
  284.                 }
  285.  
  286.                 // update collision rects
  287.                 Update_Position_Rect();
  288.             }
  289.             else
  290.             {
  291.                 break;
  292.             }
  293.         }
  294.  
  295.         // if a collision is found enter pixel checking
  296.         if( col_list.size() )
  297.         {
  298.             // change to pixel checking
  299.             if( check_x < -1 )
  300.             {
  301.                 check_x = -1;
  302.             }
  303.             else if( check_x > 1 )
  304.             {
  305.                 check_x = 1;
  306.             }
  307.  
  308.             if( check_y < -1 )
  309.             {
  310.                 check_y = -1;
  311.             }
  312.             else if( check_y > 1 )
  313.             {
  314.                 check_y = 1;
  315.             }
  316.  
  317.             // collision list link for checking
  318.             SpriteList *sprite_list = &col_list.list;
  319.  
  320.             // collision list if collisions found in pixel checking
  321.             cObjectCollisionType col_list_pixel;
  322.  
  323.             /* Checks in both directions simultaneous
  324.              * if a collision occurs it saves the direction
  325.             */
  326.             while( check_x < -0.01f || check_x > 0.01f || check_y < -0.01f || check_y > 0.01f )
  327.             {
  328.                 if( check_x != 0 )
  329.                 {
  330.                     // collision check
  331.                     col_list_pixel = Collision_Check_Relative( check_x, 0, 0, 0, COLLIDE_COMPLETE, sprite_list );
  332.  
  333.                     if( !col_list_pixel.size() )
  334.                     {
  335.                         posx += check_x;
  336.  
  337.                         if( ( check_x > 0 && posx_final <= posx ) || ( check_x < 0 && posx_final >= posx ) )
  338.                         {
  339.                             posx = posx_final;
  340.                             check_x = 0;
  341.                         }
  342.  
  343.                         // update collision rects
  344.                         Update_Position_Rect();
  345.                     }
  346.                     // collision found
  347.                     else
  348.                     {
  349.                         if( collision_dir == DIR_UNDEFINED )
  350.                         {
  351.                             // Collision Left/Right
  352.                             collision_dir = DIR_HORIZONTAL;
  353.                         }
  354.                         else
  355.                         {
  356.                             // Collision Up/Down/Left/Right
  357.                             collision_dir = DIR_ALL;
  358.                         }
  359.                         
  360.                         check_x = 0;
  361.                     }
  362.                 }
  363.  
  364.                 if( check_y != 0 )
  365.                 {
  366.                     // collision check
  367.                     col_list_pixel = Collision_Check_Relative( 0, check_y, 0, 0, COLLIDE_COMPLETE, sprite_list );
  368.  
  369.                     if( !col_list_pixel.size() )
  370.                     {
  371.                         posy += check_y;
  372.  
  373.                         if( ( check_y > 0 && posy_final <= posy ) || ( check_y < 0 && posy_final >= posy ) )
  374.                         {
  375.                             posy = posy_final;
  376.                             check_y = 0;
  377.                         }
  378.  
  379.                         // update collision rects
  380.                         Update_Position_Rect();
  381.                     }
  382.                     // collision found
  383.                     else
  384.                     {
  385.                         if( collision_dir == DIR_UNDEFINED ) 
  386.                         {
  387.                             // Collision Up/Down
  388.                             collision_dir = DIR_VERTICAL;
  389.                         }
  390.                         else
  391.                         {
  392.                             // Collision Up/Down/Left/Right
  393.                             collision_dir = DIR_ALL;
  394.                         }
  395.  
  396.                         check_y = 0;
  397.                     }
  398.                 }
  399.             }
  400.         }
  401.     }
  402.     // don't check for collisions
  403.     else
  404.     {
  405.         posx += move_x;
  406.         posy += move_y;
  407.     }
  408.  
  409.     if( collision_dir == DIR_UNDEFINED )
  410.     {
  411.         // update the position values
  412.         Update_Position_Rect();
  413.     }
  414.  
  415.     // if check on ground
  416.     if( check_on_ground )
  417.     {
  418.         Check_on_Ground();
  419.     }
  420.  
  421.     // check/handle if moved out of level rect
  422.     Check_out_of_Level_Hor( move_x, 1 );
  423.     Check_out_of_Level_Ver( move_y, 1 );
  424.  
  425.     return collision_dir;
  426. }
  427.  
  428. void cMovingSprite :: Set_Velocity( float x, float y )
  429. {
  430.     velx = x;
  431.     vely = y;
  432. }
  433.  
  434. void cMovingSprite :: Add_Velocity( float x, float y, bool real /* = 0 */ )
  435. {
  436.     if( real )
  437.     {
  438.         velx += x;
  439.         vely += y;
  440.     }
  441.     else
  442.     {
  443.         velx += x * pFramerate->speedfactor;
  444.         vely += y * pFramerate->speedfactor;
  445.     }
  446. }
  447.  
  448. void cMovingSprite :: Turn_Around( ObjectDirection col_dir /* = DIR_UNDEFINED */ )
  449. {
  450.     if( col_dir != DIR_UNDEFINED )
  451.     {
  452.         // check if the collision direction is in the front
  453.         if( ( col_dir == DIR_RIGHT && direction != DIR_RIGHT ) || ( col_dir == DIR_LEFT && direction != DIR_LEFT ) ||
  454.             ( col_dir == DIR_UP && direction != DIR_UP ) || ( col_dir == DIR_DOWN && direction != DIR_DOWN ) )
  455.         {
  456.             // collision direction is not in the front
  457.             return;
  458.         }
  459.     }
  460.  
  461.     // reverse velocity
  462.     if( direction == DIR_LEFT || direction == DIR_RIGHT )
  463.     {
  464.         velx *= -1;
  465.     }
  466.     else if( direction == DIR_UP || direction == DIR_DOWN )
  467.     {
  468.         vely *= -1;
  469.     }
  470.  
  471.     Update_Direction();
  472. }
  473.  
  474. void cMovingSprite :: Update( void )
  475. {
  476.     if( freeze_counter > 0 )
  477.     {
  478.         freeze_counter -= pFramerate->speedfactor;
  479.  
  480.         if( freeze_counter <= 0 )
  481.         {
  482.             freeze_counter = 0;
  483.             Update_Valid_Update();
  484.         }
  485.     }
  486. }
  487.  
  488. void cMovingSprite :: Draw( cSurfaceRequest *request /* = NULL */ )
  489. {
  490.     if( !valid_draw )
  491.     {
  492.         return;
  493.     }
  494.  
  495.     bool create_request = 0;
  496.  
  497.     if( !request )
  498.     {
  499.         create_request = 1;
  500.         // create request
  501.         request = new cSurfaceRequest();
  502.     }
  503.  
  504.     cSprite::Draw( request );
  505.  
  506.     if( !editor_enabled )
  507.     {
  508.         // frozen
  509.         if( freeze_counter )
  510.         {
  511.             request->combine_type = GL_ADD;
  512.  
  513.             float counter_add = freeze_counter;
  514.  
  515.             if( counter_add > 1000 )
  516.             {
  517.                 counter_add = 1000;
  518.             }
  519.  
  520.             request->combine_col[0] = counter_add * 0.003f;
  521.             request->combine_col[1] = counter_add * 0.003f;
  522.             request->combine_col[2] = counter_add * 0.0099f;
  523.         }
  524.     }
  525.  
  526.     if( create_request )
  527.     {
  528.         // add request
  529.         pRenderer->Add( request );
  530.     }
  531. }
  532.  
  533. cObjectCollisionType cMovingSprite :: Collision_Check_Relative( const float x, const float y, const float w /* = 0 */, const float h /* = 0 */, const ColCheckType check_type /* = COLLIDE_COMPLETE */, SpriteList *objects /* = NULL */ )
  534. {
  535.     return Collision_Check_Absolute( col_rect.x + x, col_rect.y + y, w, h, check_type, objects );
  536. }
  537.  
  538. cObjectCollisionType cMovingSprite :: Collision_Check_Absolute( const float x, const float y, const float w /* = 0 */, const float h /* = 0 */, const ColCheckType check_type /* = COLLIDE_COMPLETE */, SpriteList *objects /* = NULL */ )
  539. {
  540.     // save original rect
  541.     GL_rect new_rect;
  542.  
  543.     // if given use x position
  544.     if( x != 0 )
  545.     {
  546.         new_rect.x = x;
  547.     }
  548.     else
  549.     {
  550.         new_rect.x = col_rect.x;
  551.     }
  552.  
  553.     // if given use y position
  554.     if( y != 0 )
  555.     {
  556.         new_rect.y = y;
  557.     }
  558.     else
  559.     {
  560.         new_rect.y = col_rect.y;
  561.     }
  562.  
  563.     // if given use width
  564.     if( w > 0 )
  565.     {
  566.         new_rect.w = w;
  567.     }
  568.     else
  569.     {
  570.         new_rect.w = col_rect.w;
  571.     }
  572.  
  573.     // if given use height
  574.     if( h > 0 )
  575.     {
  576.         new_rect.h = h;
  577.     }
  578.     else
  579.     {
  580.         new_rect.h = col_rect.h;
  581.     }
  582.  
  583.     // visual debugging
  584.     if( game_debug )
  585.     {
  586.         // create request
  587.         cRectRequest *request = new cRectRequest();
  588.  
  589.         pVideo->Draw_Rect( &new_rect, posz + 0.00001f, &green, request );
  590.         request->no_camera = 0;
  591.  
  592.         request->blend_sfactor = GL_SRC_COLOR;
  593.         request->blend_dfactor = GL_DST_ALPHA;
  594.  
  595.  
  596.         // add request
  597.         pRenderer->Add( request );
  598.     }
  599.  
  600.     // return collisions list
  601.     return Collision_Check( &new_rect, check_type, objects );
  602. }
  603.     
  604. cObjectCollisionType cMovingSprite :: Collision_Check( const GL_rect *new_rect, const ColCheckType check_type /* = COLLIDE_COMPLETE */, SpriteList *objects /* = NULL */ )
  605. {
  606.     // blocking collisions list
  607.     cObjectCollisionType col_list = cObjectCollisionType();
  608.  
  609.     // no width or height is invalid
  610.     if( new_rect->w == 0 || new_rect->h == 0 )
  611.     {
  612.         return col_list;
  613.     }
  614.  
  615.     // if no object list is given get all objects available
  616.     if( !objects )
  617.     {
  618.         objects = &pActive_Sprite_Manager->objects;
  619.     }
  620.  
  621.     // Check Objects
  622.     for( SpriteList::iterator itr = objects->begin(), itr_end = objects->end(); itr != itr_end; ++itr )
  623.     {
  624.         // get object pointer
  625.         cSprite *level_object = (*itr);
  626.  
  627.         // if the same object or destroyed object
  628.         if( this == level_object || level_object->destroy )
  629.         {
  630.             continue;
  631.         }
  632.  
  633.         // if not Active/Massive/Enemy
  634.         if( !( level_object->sprite_array == ARRAY_ACTIVE || level_object->sprite_array == ARRAY_MASSIVE || level_object->sprite_array == ARRAY_ENEMY ) )
  635.         {
  636.             continue;
  637.         }
  638.  
  639.         // if rects doesn't touch
  640.         if( !Col_Box( new_rect, &level_object->col_rect ) )
  641.         {
  642.             continue;
  643.         }
  644.  
  645.         // if enemy is dead
  646.         if( level_object->sprite_array == ARRAY_ENEMY && static_cast<cEnemy *>(level_object)->dead )
  647.         {
  648.             continue;
  649.         }
  650.  
  651.         // if col_valid is 1 it's an internal collision
  652.         unsigned int col_valid = Validate_Collision( level_object );
  653.  
  654.         // not a valid collision
  655.         if( !col_valid )
  656.         {
  657.             continue;
  658.         }
  659.  
  660.         // ignore internal collisions
  661.         if( check_type == COLLIDE_ALLOW_BLOCKING && col_valid == 1 )
  662.         {
  663.             continue;
  664.         }
  665.  
  666.         // todo : check if check_type should be used instead for validation
  667.         // add to list if full collision
  668.         if( col_valid == 2 )
  669.         {
  670.             col_list.add( level_object );
  671.         }
  672.  
  673.         // ignore full collisions
  674.         if( check_type == COLLIDE_ALLOW_INTERNAL && col_valid == 2 )
  675.         {
  676.             continue;
  677.         }
  678.  
  679.         // if only checking
  680.         if( check_type == COLLIDE_ONLY_CHECK )
  681.         {
  682.             continue;
  683.         }
  684.  
  685.         // add collision
  686.         Collision_Add( this, level_object, pActive_Sprite_Manager->Get_Array_Num( level_object ), Get_Collision_Type( level_object->sprite_array ), ( col_valid == 1 ) ? (1) : (0) );
  687.     }
  688.  
  689.     // Player
  690.     if( type != TYPE_PLAYER && Col_Box( new_rect, &pActive_Player->col_rect ) )
  691.     {
  692.         // if col_valid is 1 it's an internal collision
  693.         unsigned int col_valid = Validate_Collision( pActive_Player );
  694.  
  695.         // ignore internal collisions
  696.         if( check_type == COLLIDE_ALLOW_BLOCKING && col_valid == 1 )
  697.         {
  698.             col_valid = 0;
  699.         }
  700.  
  701.         if( col_valid )
  702.         {
  703.             // full collision
  704.             if( col_valid == 2 )
  705.             {
  706.                 col_list.add( pActive_Player );
  707.             }
  708.  
  709.             // ignore full collisions
  710.             if( !( check_type == COLLIDE_ALLOW_INTERNAL && col_valid == 2 ) )
  711.             {
  712.                 if( check_type != COLLIDE_ONLY_CHECK )
  713.                 {
  714.                     Collision_Add( this, pActive_Player, 0, CO_PLAYER, ( col_valid == 1 ) ? (1) : (0) );
  715.                 }
  716.             }
  717.         }
  718.     }
  719.  
  720.     return col_list;
  721. }
  722.  
  723. bool cMovingSprite :: Check_out_of_Level_Hor( const float move_x, const bool handle /* = 0 */ )
  724. {
  725.     // left
  726.     if( col_rect.x < pActive_Camera->limit_rect.x && col_rect.x - ( move_x - 0.00001f ) >= pActive_Camera->limit_rect.x  )
  727.     {
  728.         if( handle )
  729.         {
  730.             Handle_out_of_Level( DIR_LEFT );
  731.         }
  732.  
  733.         return 1;
  734.     }
  735.     // right
  736.     else if( col_rect.x + col_rect.w > pActive_Camera->limit_rect.x + pActive_Camera->limit_rect.w && col_rect.x + col_rect.w - ( move_x + 0.00001f ) <= pActive_Camera->limit_rect.x + pActive_Camera->limit_rect.w )
  737.     {
  738.         if( handle )
  739.         {
  740.             Handle_out_of_Level( DIR_RIGHT );
  741.         }
  742.  
  743.         return 1;
  744.     }
  745.  
  746.     return 0;
  747. }
  748.  
  749. bool cMovingSprite :: Check_out_of_Level_Ver( const float move_y, const bool handle /* = 0 */ )
  750. {
  751.     // top
  752.     if( col_rect.y < pActive_Camera->limit_rect.y + pActive_Camera->limit_rect.h && col_rect.y - ( move_y - 0.00001f ) >= pActive_Camera->limit_rect.h + pActive_Camera->limit_rect.y )
  753.     {
  754.         if( handle )
  755.         {
  756.             Handle_out_of_Level( DIR_TOP );
  757.         }
  758.  
  759.         return 1;
  760.     }
  761.     // bottom
  762.     else if( col_rect.y + col_rect.h > pActive_Camera->limit_rect.y + game_res_h && col_rect.y + col_rect.h - ( move_y + 0.00001f ) <= pActive_Camera->limit_rect.y + game_res_h  )
  763.     {
  764.         if( handle )
  765.         {
  766.             Handle_out_of_Level( DIR_BOTTOM );
  767.         }
  768.  
  769.         return 1;
  770.     }
  771.  
  772.     return 0;
  773. }
  774.  
  775. void cMovingSprite :: Set_on_Ground( cSprite *obj )
  776. {
  777.     // invalid
  778.     if( !obj )
  779.     {
  780.         return;
  781.     }
  782.  
  783.     // if can't be ground object
  784.     if( !obj->can_be_ground )
  785.     {
  786.         return;
  787.     }
  788.  
  789.     // set groundobject
  790.     ground_object = obj;
  791.     Set_on_Top( ground_object, 0 );
  792. }
  793.  
  794. void cMovingSprite :: Check_on_Ground( void )
  795. {
  796.     if( type != TYPE_PLAYER && sprite_array != ARRAY_ENEMY && sprite_array != ARRAY_ACTIVE )
  797.     {
  798.         return;
  799.     }
  800.  
  801.     // if ground object
  802.     if( ground_object )
  803.     {
  804.         GL_rect rect2( col_rect.x, col_rect.y + col_rect.h, col_rect.w, 1 );
  805.  
  806.         // if on ground object
  807.         if( Col_Box( &ground_object->col_rect, &rect2 ) && ground_object->can_be_ground )
  808.         {
  809.             return;
  810.         }
  811.     }
  812.  
  813.     // don't check if flying
  814.     if( state == STA_FLY )
  815.     {
  816.         return;
  817.     }
  818.  
  819.     // new onground check
  820.     cObjectCollisionType col_objects = Collision_Check_Relative( 0, col_rect.h, 0, 1, COLLIDE_ALLOW_BLOCKING );
  821.  
  822.     Reset_on_Ground();
  823.  
  824.     // possible ground objects
  825.     for( SpriteList::iterator itr = col_objects.list.begin(), itr_end = col_objects.list.end(); itr != itr_end; ++itr )
  826.     {
  827.         cObjectCollision *collision = Collision_Get_last();
  828.  
  829.         // no valid collision
  830.         if( !collision )
  831.         {
  832.             continue;
  833.         }
  834.  
  835.         // ground collision found
  836.         if( collision->direction == DIR_BOTTOM )
  837.         {
  838.             Set_on_Ground( *itr );
  839.             // send collision ( for falling platform )
  840.             Send_Collision( collision );
  841.         }
  842.         
  843.         Collision_Delete( collision );
  844.     }
  845. }
  846.  
  847. void cMovingSprite :: Reset_on_Ground( void )
  848. {
  849.     ground_object = NULL;
  850. }
  851.  
  852. void cMovingSprite :: Update_Anti_Stuck( void )
  853. {
  854.     // collision count
  855.     unsigned int count = Collision_Check( &col_rect, COLLIDE_ALLOW_BLOCKING ).size();
  856.  
  857.     // check collisions
  858.     for( unsigned int i = 0; i < count; i++ )
  859.     {
  860.         cObjectCollision *collision = Collision_Get_last();
  861.  
  862.         if( !collision )
  863.         {
  864.             continue;
  865.         }
  866.  
  867.         cSprite *col_obj = pActive_Sprite_Manager->objects[collision->number];
  868.  
  869.         if( collision->type != CO_ENEMY && !( collision->type == CO_ACTIVE && ( col_obj->massivetype == MASS_HALFMASSIVE || col_obj->massivetype == MASS_CLIMBABLE ) ) )
  870.         {
  871.             debug_print( "Anti Stuck detected object %s on %s side\n", col_obj->name.c_str(), Get_Direction_Name( collision->direction ).c_str() );
  872.  
  873.             if( collision->direction == DIR_LEFT ) 
  874.             {
  875.                 Col_Move( 2, 0, 0, 1 );
  876.             }
  877.             else if( collision->direction == DIR_RIGHT ) 
  878.             {
  879.                 Col_Move( -2, 0, 0, 1 );
  880.             }
  881.             else if( collision->direction == DIR_UP ) 
  882.             {
  883.                 Col_Move( 0, 2, 0, 1 );
  884.             }
  885.             else if( collision->direction == DIR_DOWN ) 
  886.             {
  887.                 Col_Move( 0, -2, 0, 1 );
  888.             }
  889.         }
  890.  
  891.         Collision_Delete( collision );
  892.     }
  893. }
  894.  
  895. void cMovingSprite :: Collide_Move( void )
  896. {
  897.     if( !valid_update || !is_Player_range() )
  898.     {
  899.         return;
  900.     }
  901.  
  902.     // move and create collision data
  903.     Col_Move( velx, vely );
  904.  
  905.     // if the ground object moves also move this sprite
  906.     if( ground_object && ( ground_object->sprite_array == ARRAY_ACTIVE || ground_object->sprite_array == ARRAY_ENEMY ) ) // || ground_object->sprite_array == ARRAY_MASSIVE
  907.     {
  908.         cMovingSprite *moving_ground_object = dynamic_cast<cMovingSprite *>(ground_object);
  909.  
  910.         // if valid moving sprite
  911.         if( moving_ground_object )
  912.         {
  913.             if( moving_ground_object->velx != 0 || moving_ground_object->vely != 0 )
  914.             {
  915.                 // check ground first because the moving object velocity
  916.                 Check_on_Ground();
  917.                 // move
  918.                 Col_Move( moving_ground_object->velx, moving_ground_object->vely, 0, 0, 0 );
  919.             }
  920.         }
  921.     }
  922. }
  923.  
  924. void cMovingSprite :: Freeze( float freeze_time /* = DESIRED_FPS * 10 */ )
  925. {
  926.     freeze_counter = freeze_time;
  927.  
  928.     // apply resistance
  929.     if( ice_resistance > 0 )
  930.     {
  931.         freeze_counter *= ( ice_resistance * -1 ) + 1;
  932.     }
  933.  
  934.     Update_Valid_Update();
  935. }
  936.  
  937. void cMovingSprite :: DownGrade( bool force )
  938. {
  939.     // virtual
  940. }
  941.  
  942. void cMovingSprite :: Update_Direction( void )
  943. {
  944.     if( velx < 0 )
  945.     {
  946.         direction = DIR_LEFT;
  947.     }
  948.     else if( velx > 0 )
  949.     {
  950.         direction = DIR_RIGHT;
  951.     }
  952.     else if( vely < 0 )
  953.     {
  954.         direction = DIR_UP;
  955.     }
  956.     else if( vely > 0 )
  957.     {
  958.         direction = DIR_DOWN;
  959.     }
  960. }
  961.  
  962. void cMovingSprite :: Update_Rotation_Hor_velx( bool start_rotation /* = 0 */ )
  963. {
  964.     // left
  965.     if( velx < 0 )
  966.     {
  967.         roty = 0;
  968.  
  969.         if( start_rotation )
  970.         {
  971.             start_roty = roty;
  972.         }
  973.     }
  974.     // right
  975.     else if( velx > 0 )
  976.     {
  977.         roty = 180;
  978.  
  979.         if( start_rotation )
  980.         {
  981.             start_roty = roty;
  982.         }
  983.     }
  984. }
  985.  
  986. void cMovingSprite :: Update_Rotation_Hor_vely( bool start_rotation /* = 0 */ )
  987. {
  988.     // up
  989.     if( vely < 0 )
  990.     {
  991.         roty = 0;
  992.  
  993.         if( start_rotation )
  994.         {
  995.             start_roty = roty;
  996.         }
  997.     }
  998.     // down
  999.     else if( vely > 0 )
  1000.     {
  1001.         roty = 180;
  1002.  
  1003.         if( start_rotation )
  1004.         {
  1005.             start_roty = roty;
  1006.         }
  1007.     }
  1008. }
  1009.  
  1010. unsigned int cMovingSprite :: Validate_Collision( cSprite *obj )
  1011. {
  1012.     if( obj->massivetype == MASS_MASSIVE )
  1013.     {
  1014.         return 2;
  1015.     }
  1016.     if( obj->massivetype == MASS_HALFMASSIVE )
  1017.     {
  1018.         // if moving downwards and object is on top
  1019.         if( vely >= 0 && Is_on_Top( obj ) )
  1020.         {
  1021.             return 2;
  1022.         }
  1023.     }
  1024.  
  1025.     return 0;
  1026. }
  1027.  
  1028. int cMovingSprite :: Validate_Collision_Ghost( cSprite *obj )
  1029. {
  1030.     if( obj->type == TYPE_BONUSBOX || obj->type == TYPE_SPINBOX )
  1031.     {
  1032.         cBaseBox *box = static_cast<cBaseBox *>(obj);
  1033.  
  1034.         // ghost
  1035.         if( box->box_invisible == 2 )
  1036.         {
  1037.             // maryo is not ghost
  1038.             if( pPlayer->maryo_type != MARYO_GHOST )
  1039.             {
  1040.                 return 0;
  1041.             }
  1042.         }
  1043.     }
  1044.  
  1045.     return -1;
  1046. }
  1047.  
  1048. void cMovingSprite :: Send_Collision( cObjectCollision *collision )
  1049. {
  1050.     // empty collision
  1051.     if( !collision )
  1052.     {
  1053.         return;
  1054.     }
  1055.  
  1056.     // if no target object number is available
  1057.     if( collision->number < 0 )
  1058.     {
  1059.         return;
  1060.     }
  1061.  
  1062.     /* if collision is received ignore
  1063.      * a received collision can't create a received collision
  1064.      * only a self detected collision can create a received collision
  1065.     */
  1066.     if( collision->received )
  1067.     {
  1068.         return;
  1069.     }
  1070.  
  1071.     // create a new collision
  1072.     cObjectCollision *ncollision = new cObjectCollision();
  1073.  
  1074.     // this is a received collision
  1075.     ncollision->received = 1;
  1076.     // set object manager id
  1077.     if( type != TYPE_PLAYER )
  1078.     {
  1079.         ncollision->number = pActive_Sprite_Manager->Get_Array_Num( this );
  1080.  
  1081.         // object not available
  1082.         if( ncollision->number < 0 )
  1083.         {
  1084.             debug_print( "Warning : Object did send Collision but doesn't exists in Manager\n" );
  1085.  
  1086.             delete ncollision;
  1087.             return;
  1088.         }
  1089.     }
  1090.  
  1091.     // set direction
  1092.     if( collision->direction != DIR_UNDEFINED )
  1093.     {
  1094.         ncollision->direction = Get_Opposite_Direction( collision->direction );
  1095.     }
  1096.  
  1097.     // set type
  1098.     if( type != TYPE_PLAYER )
  1099.     {
  1100.         ncollision->type = Get_Collision_Type( sprite_array );
  1101.     }
  1102.     // from player
  1103.     else
  1104.     {
  1105.         ncollision->type = CO_PLAYER;
  1106.     }
  1107.     
  1108.     // add collision to the list
  1109.     if( collision->type == CO_PLAYER )
  1110.     {
  1111.         pActive_Player->Collision_Add( ncollision, 1 );
  1112.     }
  1113.     else
  1114.     {
  1115.         pActive_Sprite_Manager->Get_Pointer( collision->number )->Collision_Add( ncollision, 1 );
  1116.     }
  1117. }
  1118.  
  1119. void cMovingSprite :: Handle_Collision( cObjectCollision *collision )
  1120. {
  1121.     // ignore player/enemy if frozen
  1122.     if( collision->type == CO_PLAYER || collision->type == CO_ENEMY )
  1123.     {
  1124.         if( freeze_counter )
  1125.         {
  1126.             return;
  1127.         }
  1128.     }
  1129.  
  1130.     cSprite::Handle_Collision( collision );
  1131. }
  1132.  
  1133. void cMovingSprite :: Handle_out_of_Level( ObjectDirection dir )
  1134. {
  1135.     // virtual
  1136. }
  1137.  
  1138. /* *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** */
  1139.