home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2009 February / maximum-cd-2009-02.iso / DiscContents / SMC_1.6_win32.exe / src / enemies / spika.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2008-09-26  |  8.7 KB  |  446 lines

  1. /***************************************************************************
  2.  * spika.cpp  -  spika, spiked waiting enemy
  3.  *
  4.  * Copyright (C) 2006 - 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 "../enemies/spika.h"
  17. #include "../core/game_core.h"
  18. #include "../player/player.h"
  19. #include "../level/level.h"
  20. #include "../gui/hud.h"
  21. #include "../video/gl_surface.h"
  22. #include "../core/sprite_manager.h"
  23. #include "../core/i18n.h"
  24. #include "../enemies/bosses/turtle_boss.h"
  25.  
  26. /* *** *** *** *** *** *** cSpika *** *** *** *** *** *** *** *** *** *** *** */
  27.  
  28. cSpika :: cSpika( float x, float y )
  29. : cEnemy( x, y )
  30. {
  31.     cSpika::Init();
  32. }
  33.  
  34. cSpika :: cSpika( CEGUI::XMLAttributes &attributes )
  35. : cEnemy()
  36. {
  37.     cSpika::Init();
  38.     cSpika::Create_from_Stream( attributes );
  39. }
  40.  
  41. cSpika :: ~cSpika( void )
  42. {
  43.     //
  44. }
  45.  
  46. void cSpika :: Init( void )
  47. {
  48.     type = TYPE_SPIKA;
  49.     posz = 0.09f;
  50.     can_be_ground = 1;
  51.  
  52.     color_type = COL_DEFAULT;
  53.     speed = 0;
  54.     detection_size = 0;
  55.  
  56.     Set_Color( COL_ORANGE );
  57. }
  58.  
  59. cSpika *cSpika :: Copy( void )
  60. {
  61.     cSpika *spika = new cSpika( startposx, startposy );
  62.     spika->Set_Color( color_type );
  63.  
  64.     return spika;
  65. }
  66.  
  67. void cSpika :: Create_from_Stream( CEGUI::XMLAttributes &attributes )
  68. {
  69.     // position
  70.     Set_Pos( static_cast<float>(attributes.getValueAsInteger( "posx" )), static_cast<float>(attributes.getValueAsInteger( "posy" )), 1 );
  71.     // color
  72.     Set_Color( static_cast<DefaultColor>(Get_Color_Id( attributes.getValueAsString( "color", Get_Color_Name( color_type ) ).c_str() )) );
  73. }
  74.  
  75. void cSpika :: Save_to_Stream( ofstream &file )
  76. {
  77.     // begin enemy
  78.     file << "\t<enemy>" << std::endl;
  79.  
  80.     // name
  81.     file << "\t\t<Property name=\"type\" value=\"spika\" />" << std::endl;
  82.     // position
  83.     file << "\t\t<Property name=\"posx\" value=\"" << static_cast<int>(startposx) << "\" />" << std::endl;
  84.     file << "\t\t<Property name=\"posy\" value=\"" << static_cast<int>(startposy) << "\" />" << std::endl;
  85.     // color
  86.     file << "\t\t<Property name=\"color\" value=\"" << Get_Color_Name( color_type ) << "\" />" << std::endl;
  87.  
  88.     // end enemy
  89.     file << "\t</enemy>" << std::endl;
  90. }
  91.  
  92. void cSpika :: Set_Color( DefaultColor col )
  93. {
  94.     // already set
  95.     if( color_type == col )
  96.     {
  97.         return;
  98.     }
  99.  
  100.     // clear old images
  101.     Clear_Images();
  102.  
  103.     color_type = col;
  104.  
  105.     if( color_type == COL_ORANGE )
  106.     {
  107.         images.push_back( pVideo->Get_Surface( "enemy/spika/orange.png" ) );
  108.  
  109.         speed = 3;
  110.         detection_size = 160;
  111.         kill_points = 50;
  112.  
  113.         fire_resistant = 0;
  114.     }
  115.     else if( color_type == COL_GREEN )
  116.     {
  117.         images.push_back( pVideo->Get_Surface( "enemy/spika/green.png" ) );
  118.  
  119.         speed = 4;
  120.         detection_size = 220;
  121.         kill_points = 200;
  122.  
  123.         fire_resistant = 0;
  124.     }
  125.     else if( color_type == COL_GREY )
  126.     {
  127.         images.push_back( pVideo->Get_Surface( "enemy/spika/grey.png" ) );
  128.  
  129.         speed = 7;
  130.         detection_size = 330;
  131.         kill_points = 500;
  132.  
  133.         fire_resistant = 1;
  134.     }
  135.     else
  136.     {
  137.         printf( "Error : Unknown Spika Color %d\n", color_type );
  138.     }
  139.  
  140.     Set_Image( 0, 1 );
  141.  
  142.     name = "Spika ";
  143.     name += _(Get_Color_Name( color_type ).c_str());
  144. }
  145.  
  146. void cSpika :: DownGrade( bool force /* = 0 */ )
  147. {
  148.     Set_Dead( 1 );
  149.     massivetype = MASS_PASSIVE;
  150.     counter = 0;
  151.     velx = 0;
  152.     vely = 0;
  153.     Set_Scale_Directions( 1, 1, 1, 1 );
  154.  
  155.     // default stomp death
  156.     if( !force )
  157.     {
  158.         Generate_Hit_Animation();
  159.     }
  160.     // falling death
  161.     else
  162.     {
  163.         Set_Rotation_Z( 180 );
  164.     }
  165. }
  166.  
  167. void cSpika :: DieStep( void )
  168. {
  169.     counter += pFramerate->speedfactor * 0.1f;
  170.  
  171.     // falling death
  172.  
  173.     // a little bit upwards first
  174.     if( counter < 0.3f )
  175.     {
  176.         Move( 0, -5 );
  177.     }
  178.     // if not below the screen fall
  179.     else if( posy < game_res_h + col_rect.h )
  180.     {
  181.         Move( 0, 20 );
  182.  
  183.         Add_Scale( -pFramerate->speedfactor * 0.01f );
  184.     }
  185.     // if below disable
  186.     else
  187.     {
  188.         rotz = 0;
  189.         Set_Scale( 1 );
  190.         Set_Visible( 0 );
  191.     }
  192. }
  193.  
  194. void cSpika :: Update( void )
  195. {
  196.     cEnemy::Update();
  197.  
  198.     if( !valid_update || !is_Player_range() )
  199.     {
  200.         return;
  201.     }
  202.  
  203.     // update rotation
  204.     if( velx != 0 )
  205.     {
  206.         Add_Rotation_Z( ( velx / ( image->w * 0.01f ) ) * pFramerate->speedfactor );
  207.     }
  208.  
  209.     // check for player
  210.     GL_rect player_rect = pPlayer->col_rect;
  211.     player_rect.x += ( pPlayer->col_rect.w / 2 );
  212.     player_rect.w = 1;
  213.  
  214.     // rect
  215.     GL_rect rect_left = col_rect;
  216.     rect_left.y -= 10;
  217.     rect_left.h += 10;
  218.  
  219.     GL_rect rect_right = rect_left;
  220.     // left
  221.     rect_left.x -= detection_size + ( col_rect.w / 2 );
  222.     rect_left.w += detection_size;
  223.     // right
  224.     rect_right.x -= col_rect.w / 2;
  225.     rect_right.w += detection_size;
  226.  
  227.  
  228.     // if player is left
  229.     if( pPlayer->maryo_type != MARYO_GHOST && Col_Box( &player_rect, &rect_left ) )
  230.     {
  231.         if( velx > -speed )
  232.         {
  233.             velx -= speed * 0.1f * pFramerate->speedfactor;
  234.  
  235.             if( velx < -speed )
  236.             {
  237.                 velx = -speed;
  238.             }
  239.         }
  240.     }
  241.     // if player is right
  242.     else if( pPlayer->maryo_type != MARYO_GHOST && Col_Box( &player_rect, &rect_right ) )
  243.     {
  244.         if( velx < speed )
  245.         {
  246.             velx += speed * 0.1f * pFramerate->speedfactor;
  247.  
  248.             if( velx > speed )
  249.             {
  250.                 velx = speed;
  251.             }
  252.         }
  253.     }
  254.     // out of range
  255.     else
  256.     {
  257.         // slow down
  258.         velx -= velx * 0.03f * pFramerate->speedfactor;
  259.     }
  260.  
  261.     // play walking sound based on speed
  262.     if( walk_count < rotz - 30 || walk_count > rotz + 30 )
  263.     {
  264.         pAudio->Play_Sound( "enemy/spika/move.ogg" );
  265.  
  266.         walk_count = rotz;
  267.     }
  268.  
  269.     // gravity
  270.     Update_Gravity();
  271. }
  272.  
  273. bool cSpika :: Is_Update_Valid( void )
  274. {
  275.     if( dead || freeze_counter )
  276.     {
  277.         return 0;
  278.     }
  279.  
  280.     return 1;
  281. }
  282.  
  283. unsigned int cSpika :: Validate_Collision( cSprite *obj )
  284. {
  285.     // basic validation checking
  286.     int basic_valid = Validate_Collision_Ghost( obj );
  287.  
  288.     // found valid collision
  289.     if( basic_valid > -1 )
  290.     {
  291.         return basic_valid;
  292.     }
  293.  
  294.     if( obj->massivetype == MASS_MASSIVE )
  295.     {
  296.         if( obj->type == TYPE_ROKKO )
  297.         {
  298.             return 0;
  299.         }
  300.         if( obj->type == TYPE_GEE )
  301.         {
  302.             return 0;
  303.         }
  304.         if( obj->type == TYPE_TURTLE_BOSS )
  305.         {
  306.             return 0;
  307.         }
  308.         if( obj->type == TYPE_STATIC_ENEMY )
  309.         {
  310.             return 0;
  311.         }
  312.  
  313.         if( obj->sprite_array == ARRAY_ENEMY )
  314.         {
  315.             // if moving collide
  316.             if( velx != 0 )
  317.             {
  318.                 // if enemy is spika and more powerful
  319.                 if( obj->type == TYPE_SPIKA && speed < static_cast<cSpika *>(obj)->speed )
  320.                 {
  321.                     return 2;
  322.                 }
  323.  
  324.                 return 1;
  325.             }
  326.  
  327.             return 0;
  328.         }
  329.  
  330.         return 2;
  331.     }
  332.     if( obj->massivetype == MASS_HALFMASSIVE )
  333.     {
  334.         // if moving downwards and object is on top
  335.         if( vely >= 0 && Is_on_Top( obj ) )
  336.         {
  337.             return 2;
  338.         }
  339.     }
  340.  
  341.     return 0;
  342. }
  343.  
  344. void cSpika :: Handle_Collision_Player( cObjectCollision *collision )
  345. {
  346.     pPlayer->DownGrade();
  347.  
  348.     if( collision->direction == DIR_LEFT || collision->direction == DIR_RIGHT )
  349.     {
  350.         velx = 0;
  351.     }
  352. }
  353.  
  354. void cSpika :: Handle_Collision_Enemy( cObjectCollision *collision )
  355. {
  356.     // invalid
  357.     if( collision->number < 0 )
  358.     {
  359.         return;
  360.     }
  361.  
  362.     // only if moving
  363.     if( !velx )
  364.     {
  365.         return;
  366.     }
  367.  
  368.     cEnemy *enemy = static_cast<cEnemy *>(pActive_Sprite_Manager->Get_Pointer( collision->number ));
  369.  
  370.     // already dead
  371.     if( enemy->dead )
  372.     {
  373.         return;
  374.     }
  375.  
  376.     // check spika power
  377.     if( enemy->type == TYPE_SPIKA )
  378.     {
  379.         cSpika *spika = static_cast<cSpika *>(enemy);
  380.  
  381.         // if colliding spika is more powerful
  382.         if( speed < spika->speed )
  383.         {
  384.             //enemy->Send_Collision( collision );
  385.             return;
  386.         }
  387.     }
  388.  
  389.     // state change for turtle boss
  390.     if( enemy->type == TYPE_TURTLE_BOSS )
  391.     {
  392.         // todo : remove hackiness and implement a better generic downgrade handler
  393.         cTurtleBoss *turtle_boss = static_cast<cTurtleBoss *>(enemy);
  394.  
  395.         // downgrade until state change
  396.         for( int i = turtle_boss->hits; i < turtle_boss->max_hits; i++ )
  397.         {
  398.             turtle_boss->DownGrade();
  399.         }
  400.  
  401.         // turtle kills spika
  402.         DownGrade( 1 );
  403.     }
  404.     // kill enemy
  405.     else
  406.     {
  407.         pAudio->Play_Sound( enemy->kill_sound );
  408.         pointsdisplay->Add_Points( enemy->kill_points, posx + image->w / 3, posy - 5, "", static_cast<Uint8>(255), 1 );
  409.         enemy->DownGrade( 1 );
  410.     }
  411. }
  412.  
  413. void cSpika :: Handle_Collision_Massive( cObjectCollision *collision )
  414. {
  415.     if( collision->direction == DIR_RIGHT || collision->direction == DIR_LEFT )
  416.     {
  417.         velx = 0;
  418.     }
  419. }
  420.  
  421. void cSpika :: Handle_Collision_Box( ObjectDirection cdirection, GL_rect *r2 )
  422. {
  423.     if( cdirection == DIR_DOWN )
  424.     {
  425.         vely = -10;
  426.  
  427.         // left
  428.         if( posx > r2->x )
  429.         {
  430.             velx += 10;
  431.         }
  432.         // right
  433.         else if( posx < r2->x )
  434.         {
  435.             velx -= 10;
  436.         }
  437.     }
  438.     // unsupported collision direction
  439.     else
  440.     {
  441.         return;
  442.     }
  443.  
  444.     Reset_on_Ground();
  445. }
  446.