src/weapon/ninja_rope.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002  *  Wormux is a convivial mass murder game.
00003  *  Copyright (C) 2001-2004 Lawrence Azzoug.
00004  *
00005  *  This program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2 of the License, or
00008  *  (at your option) any later version.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
00018  ******************************************************************************
00019  * Ninja-rope: les skins se balancent au bout d'une corde pour se balader sur le terrain
00020  *****************************************************************************/
00021 
00022 #include "ninja_rope.h"
00023 #include <math.h>
00024 #include "explosion.h"
00025 #include "../game/config.h"
00026 #include "../game/game.h"
00027 #include "../game/game_loop.h"
00028 #include "../game/time.h"
00029 #include "../include/app.h"
00030 #include "../map/camera.h"
00031 #include "../map/map.h"
00032 #include "../sound/jukebox.h"
00033 #include "../team/teams_list.h"
00034 #include "../tool/math_tools.h"
00035 #include "../tool/i18n.h"
00036 
00037 const int DT_MVT  = 15 ; //delta_t bitween 2 up/down/left/right mvt
00038 const int DST_MIN = 6 ;  //dst_minimal bitween 2 nodes
00039 const uint MAX_ROPE_LEN = 450 ; // Max rope length in pixels
00040 const uint ROPE_DRAW_SPEED = 12 ; // Pixel per 1/100 second.
00041 const int ROPE_PUSH_FORCE = 10;
00042 
00043 bool find_first_contact_point (int x1, int y1, double angle, int length,
00044                                int skip, int &cx, int &cy)
00045 {
00046   double x, y, x_step, y_step ;
00047   int x2, y2 ;
00048 
00049   x_step = cos(angle) ;
00050   y_step = sin(angle) ;
00051 
00052   x1 += (int)(skip * x_step) ;
00053   y1 += (int)(skip * y_step) ;
00054 
00055   x = (double)x1 ;
00056   y = (double)y1 ;
00057   cx = x1 ;
00058   cy = y1 ;
00059 
00060   length -= skip;
00061 
00062   x2 = x1 + (int)(length * cos(angle));
00063   y2 = y1 + (int)(length * sin(angle));
00064 
00065   while(!world.EstHorsMondeXY(cx, cy) &&
00066         (length > 0))
00067     {
00068       if (!world.EstDansVide(cx, cy))
00069         return true ;
00070 
00071       x += x_step ;
00072       y += y_step ;
00073       cx = (int)round(x) ;
00074       cy = (int)round(y) ;
00075       length-- ;
00076     }
00077 
00078   return false ;
00079 }
00080 
00081 NinjaRope::NinjaRope() : Weapon(WEAPON_NINJA_ROPE, "ninjarope", new WeaponConfig())
00082 {
00083   m_name = _("Ninjarope");
00084   override_keys = true ;
00085   use_unit_on_first_shoot = false;
00086 
00087   m_hook_sprite = resource_manager.LoadSprite(weapons_res_profile,"ninjahook");
00088   m_hook_sprite->EnableRotationCache(32);
00089   m_node_sprite = resource_manager.LoadSprite(weapons_res_profile,"ninjanode");
00090 
00091   m_is_active = false;
00092   m_attaching = false;
00093   m_rope_attached = false;
00094   go_left = false ;
00095   go_right = false ;
00096   delta_len = 0 ;
00097 }
00098 
00099 bool NinjaRope::p_Shoot()
00100 {
00101   last_broken_node_angle = 100;
00102 
00103   last_node = 0 ;
00104   m_attaching = true;
00105   m_launch_time = Time::GetInstance()->Read() ;
00106   m_initial_angle = ActiveCharacter().GetFiringAngle();
00107   last_mvt=Time::GetInstance()->Read();
00108   return true ;
00109 }
00110 
00111 void NinjaRope::TryAttachRope()
00112 {
00113   int x, y;
00114   uint length;
00115   uint delta_time = Time::GetInstance()->Read() - m_launch_time;
00116   double angle ;
00117 
00118   // The rope is being launching. Increase the rope length and check
00119   // collisions.
00120 
00121   Point2i handPos = ActiveCharacter().GetHandPosition();
00122   x = handPos.x;
00123   y = handPos.y;
00124 
00125   length = ROPE_DRAW_SPEED * delta_time / 10;
00126   if (length > MAX_ROPE_LEN)
00127     {
00128       // Hum the roe is too short !
00129       m_attaching = false;
00130       m_is_active = false;
00131       return ;
00132     }
00133 
00134   angle = m_initial_angle;
00135 
00136   if (find_first_contact_point(x, y, angle, length, 4,
00137                                m_fixation_x, m_fixation_y))
00138     {
00139       m_attaching = false;
00140 
00141       int dx, dy;
00142 
00143       // The rope reaches the fixation point. Let's fix it !
00144 
00145       dx = x - ActiveCharacter().GetX() ;
00146       dy = y - ActiveCharacter().GetY() ;
00147 
00148       ActiveCharacter().SetPhysFixationPointXY(
00149                                                m_fixation_x / PIXEL_PER_METER,
00150                                                m_fixation_y / PIXEL_PER_METER,
00151                                                (double)dx / PIXEL_PER_METER,
00152                                                (double)dy / PIXEL_PER_METER);
00153 
00154       rope_node[0].x = m_fixation_x ;
00155       rope_node[0].y = m_fixation_y ;
00156 
00157       ActiveCharacter().ChangePhysRopeSize (-10.0 / PIXEL_PER_METER);
00158       m_hooked_time = Time::GetInstance()->Read();
00159       ActiveCharacter().SetMovement("ninja-rope");
00160 
00161      ActiveCharacter().SetFiringAngle(-M_PI / 3);
00162 
00163     }
00164   else
00165     {
00166       rope_node[0].x = x + (int)(length * cos(angle));
00167       rope_node[0].y = y + (int)(length * sin(angle));
00168     }
00169 }
00170 
00171 void NinjaRope::UnattachRope()
00172 {
00173   ActiveCharacter().UnsetPhysFixationPoint() ;
00174   last_node = 0;
00175 }
00176 
00177 bool NinjaRope::TryAddNode(int CurrentSense)
00178 {
00179   int dx, dy, lg, cx, cy;
00180   Point2d V;
00181   bool AddNode = false ;
00182   double angle, rope_angle;
00183 
00184   Point2i handPos = ActiveCharacter().GetHandPosition();
00185 
00186   // Compute distance between hands and rope fixation point.
00187 
00188   V.x = handPos.x - m_fixation_x;
00189   V.y = handPos.y - m_fixation_y;
00190   angle = V.ComputeAngle();
00191   lg = (int)V.Norm();
00192 
00193   if (lg < DST_MIN)
00194     return false;
00195 
00196   // Check if the rope collide something
00197 
00198   if (find_first_contact_point(m_fixation_x, m_fixation_y, angle, lg, 4,cx,cy))
00199     {
00200       rope_angle = ActiveCharacter().GetRopeAngle() ;
00201 
00202       if ( (last_broken_node_sense * CurrentSense > 0) &&
00203            (fabs(last_broken_node_angle - rope_angle) < 0.1))
00204         return false ;
00205 
00206       // The rope has collided something...
00207       // Add a node on the rope and change the fixation point.
00208 
00209       dx = handPos.x - ActiveCharacter().GetX();
00210       dy = handPos.y - ActiveCharacter().GetY();
00211 
00212       ActiveCharacter().SetPhysFixationPointXY(cx / PIXEL_PER_METER,
00213                                                cy / PIXEL_PER_METER,
00214                                                (double)dx / PIXEL_PER_METER,
00215                                                (double)dy / PIXEL_PER_METER);
00216 
00217       m_fixation_x = cx ;
00218       m_fixation_y = cy ;
00219       last_node++ ;
00220       rope_node[last_node].x = m_fixation_x ;
00221       rope_node[last_node].y = m_fixation_y ;
00222       rope_node[last_node].angle = rope_angle ;
00223       rope_node[last_node].sense = CurrentSense ;
00224 
00225       AddNode = true ;
00226     }
00227 
00228   return AddNode ;
00229 }
00230 
00231 bool NinjaRope::TryBreakNode(int CurrentSense)
00232 {
00233   double CurrentAngle, NodeAngle ;
00234   int NodeSense ;
00235   double AngularSpeed ;
00236   bool BreakNode = false ;
00237   int dx, dy ;
00238 
00239   // Check if we can break a node.
00240 
00241   NodeSense = rope_node[last_node].sense ;
00242   NodeAngle = rope_node[last_node].angle ;
00243   AngularSpeed = ActiveCharacter().GetAngularSpeed() ;
00244   CurrentAngle = ActiveCharacter().GetRopeAngle() ;
00245 
00246   if ( (last_node != 0) &&              // We cannot break the initial node.
00247        (NodeSense * CurrentSense < 0) ) // Cannot break a node if we are in the
00248                                         // same sense of the node.
00249     {
00250       if ( (CurrentAngle > 0) &&
00251            (AngularSpeed > 0) &&
00252            (CurrentAngle > NodeAngle))
00253         BreakNode = true ;
00254 
00255       if ( (CurrentAngle > 0) &&
00256            (AngularSpeed < 0) &&
00257            (CurrentAngle < NodeAngle))
00258         BreakNode = true ;
00259 
00260       if ( (CurrentAngle < 0) &&
00261            (AngularSpeed > 0) &&
00262            (CurrentAngle > NodeAngle))
00263         BreakNode = true ;
00264 
00265       if ( (CurrentAngle < 0) &&
00266            (AngularSpeed < 0) &&
00267            (CurrentAngle < NodeAngle))
00268         BreakNode = true ;
00269     }
00270 
00271   // We can break the current node... Let's do it !
00272 
00273   if (BreakNode)
00274     {
00275       last_broken_node_angle = CurrentAngle ;
00276       last_broken_node_sense = CurrentSense ;
00277 
00278       last_node-- ;
00279 
00280       m_fixation_x = rope_node[last_node].x ;
00281       m_fixation_y = rope_node[last_node].y ;
00282 
00283       Point2i handPos = ActiveCharacter().GetHandPosition();
00284       dx = handPos.x - ActiveCharacter().GetX();
00285       dy = handPos.y - ActiveCharacter().GetY();
00286 
00287       ActiveCharacter().SetPhysFixationPointXY(m_fixation_x / PIXEL_PER_METER,
00288                                                m_fixation_y / PIXEL_PER_METER,
00289                                                (double)dx / PIXEL_PER_METER,
00290                                                (double)dy / PIXEL_PER_METER);
00291 
00292     }
00293 
00294   return BreakNode ;
00295 }
00296 
00297 void NinjaRope::NotifyMove(bool collision)
00298 {
00299   bool AddNode = false ;
00300   double AngularSpeed ;
00301   int CurrentSense ;
00302 
00303   if (!m_is_active)
00304     return ;
00305 
00306   // Check if the character collide something.
00307 
00308   if (collision)
00309     {
00310       // Yes there has been a collision.
00311       if (delta_len != 0)
00312         {
00313           // The character tryed to change the rope size.
00314           // There has been a collision, so we cancel the rope length change.
00315           ActiveCharacter().ChangePhysRopeSize (-delta_len);
00316           delta_len = 0 ;
00317         }
00318       return ;
00319     }
00320 
00321   AngularSpeed = ActiveCharacter().GetAngularSpeed() ;
00322   CurrentSense = (int)(AngularSpeed / fabs(AngularSpeed)) ;
00323 
00324   // While there is nodes to add, we add !
00325   while (TryAddNode(CurrentSense))
00326     AddNode = true ;
00327 
00328   // If we have created nodes, we exit to avoid breaking what we
00329   // have just done !
00330   if (AddNode)
00331     return ;
00332 
00333   // While there is nodes to break, we break !
00334   while (TryBreakNode(CurrentSense)) ;
00335 }
00336 
00337 void NinjaRope::Refresh()
00338 {
00339   if (!m_is_active)
00340     return ;
00341 
00342   ActiveCharacter().UpdatePosition();
00343 }
00344 
00345 void NinjaRope::GoUp()
00346 {
00347   if(Time::GetInstance()->Read()<last_mvt+DT_MVT)
00348     return;
00349   last_mvt = Time::GetInstance()->Read();
00350 
00351   delta_len = -0.1 ;
00352   ActiveCharacter().ChangePhysRopeSize (delta_len);
00353   ActiveCharacter().UpdatePosition();
00354   delta_len = 0 ;
00355 }
00356 
00357 void NinjaRope::GoDown()
00358 {
00359   if(Time::GetInstance()->Read()<last_mvt+DT_MVT)
00360     return;
00361   last_mvt = Time::GetInstance()->Read();
00362 
00363   if (ActiveCharacter().GetRopeLength() >= MAX_ROPE_LEN / PIXEL_PER_METER)
00364     return;
00365 
00366   delta_len = 0.1 ;
00367   ActiveCharacter().ChangePhysRopeSize (delta_len) ;
00368   ActiveCharacter().UpdatePosition() ;
00369   delta_len = 0 ;
00370 }
00371 
00372 void NinjaRope::GoRight()
00373 {
00374   go_right = true ;
00375   ActiveCharacter().SetExternForce(ROPE_PUSH_FORCE,0);
00376   ActiveCharacter().SetDirection(Body::DIRECTION_RIGHT);
00377 }
00378 
00379 void NinjaRope::StopRight()
00380 {
00381   go_right = false ;
00382 
00383   if (go_left || go_right)
00384     return ;
00385 
00386   ActiveCharacter().SetExternForce(0,0);
00387 }
00388 
00389 void NinjaRope::GoLeft()
00390 {
00391   go_left = true ;
00392   ActiveCharacter().SetExternForce(-ROPE_PUSH_FORCE,0);
00393   ActiveCharacter().SetDirection(Body::DIRECTION_LEFT);
00394 }
00395 
00396 void NinjaRope::StopLeft()
00397 {
00398   go_left = false ;
00399 
00400   if (go_left || go_right)
00401     return ;
00402 
00403   ActiveCharacter().SetExternForce(0,0);
00404 }
00405 
00406 void NinjaRope::Draw()
00407 {
00408   int i, x, y;
00409   double angle, prev_angle;
00410 
00411   struct CL_Quad {Sint16 x1,x2,x3,x4,y1,y2,y3,y4;} quad;
00412 
00413   if (!m_is_active)
00414   {
00415     Weapon::Draw();
00416     return ;
00417   }
00418 
00419   if (m_attaching)
00420     {
00421       TryAttachRope();
00422       if (!m_is_active)
00423               return ;
00424       if(m_attaching)
00425         angle = m_initial_angle + M_PI/2;
00426       else
00427         angle = ActiveCharacter().GetRopeAngle();
00428     }
00429   else
00430     angle = ActiveCharacter().GetRopeAngle();
00431   prev_angle = angle;
00432 
00433 
00434   // Draw the rope.
00435 
00436   Point2i handPos = ActiveCharacter().GetHandPosition();
00437   x = handPos.x;
00438   y = handPos.y;
00439 
00440   quad.x1 = (int)round((double)x - 2 * cos(angle));
00441   quad.y1 = (int)round((double)y + 2 * sin(angle));
00442   quad.x2 = (int)round((double)x + 2 * cos(angle));
00443   quad.y2 = (int)round((double)y - 2 * sin(angle));
00444 
00445   for (i = last_node ; i >= 0; i--)
00446     {
00447       quad.x3 = (int)round((double)rope_node[i].x + 2 * cos(angle));
00448       quad.y3 = (int)round((double)rope_node[i].y - 2 * sin(angle));
00449       quad.x4 = (int)round((double)rope_node[i].x - 2 * cos(angle));
00450       quad.y4 = (int)round((double)rope_node[i].y + 2 * sin(angle));
00451 
00452       float dx = sin(angle) * (float)m_node_sprite->GetHeight();
00453       float dy = cos(angle) * (float)m_node_sprite->GetHeight();
00454       int step = 0;
00455       int size = (quad.x1-quad.x4) * (quad.x1-quad.x4)
00456                 +(quad.y1-quad.y4) * (quad.y1-quad.y4);
00457       size -= m_node_sprite->GetHeight();
00458       while( (step*dx*step*dx)+(step*dy*step*dy) < size )
00459       {
00460         if(m_attaching)
00461           m_node_sprite->Draw(
00462                                   Point2i(
00463                                   quad.x1 + (int)((float) step * dx),
00464                                   quad.y1 - (int)((float) step * dy)) );
00465         else
00466           m_node_sprite->Draw( Point2i(
00467                                           quad.x4 + (int)((float) step * dx),
00468                       quad.y4 + (int)((float) step * dy)) );
00469         step++;
00470       }
00471       quad.x1 = quad.x4 ;
00472       quad.y1 = quad.y4 ;
00473       quad.x2 = quad.x3 ;
00474       quad.y2 = quad.y3 ;
00475       prev_angle = angle;
00476       angle = rope_node[i].angle ;
00477 
00478     }
00479 
00480   m_hook_sprite->SetRotation_rad(-prev_angle);
00481   m_hook_sprite->Draw( Point2i(rope_node[0].x, rope_node[0].y)
00482                   - m_hook_sprite->GetSize()/2);
00483 }
00484 
00485 void NinjaRope::p_Deselect()
00486 {
00487   m_is_active = false;
00488   ActiveCharacter().Show();
00489   ActiveCharacter().SetExternForce(0,0);
00490   ActiveCharacter().UnsetPhysFixationPoint() ;
00491 }
00492 
00493 void NinjaRope::HandleKeyEvent(Action::Action_t action, Keyboard::Key_Event_t event_type)
00494 {
00495   switch (action) {
00496     case Action::ACTION_UP:
00497       if (event_type != Keyboard::KEY_RELEASED)
00498         GoUp();
00499       break ;
00500 
00501     case Action::ACTION_DOWN:
00502       if (event_type != Keyboard::KEY_RELEASED)
00503         GoDown();
00504       break ;
00505 
00506     case Action::ACTION_MOVE_LEFT:
00507       if (event_type == Keyboard::KEY_PRESSED)
00508         GoLeft();
00509       else
00510         if (event_type == Keyboard::KEY_RELEASED)
00511           StopLeft();
00512       break ;
00513 
00514     case Action::ACTION_MOVE_RIGHT:
00515       if (event_type == Keyboard::KEY_PRESSED)
00516         GoRight();
00517       else
00518         if (event_type == Keyboard::KEY_RELEASED)
00519           StopRight();
00520       break ;
00521 
00522     case Action::ACTION_SHOOT:
00523       if (event_type == Keyboard::KEY_PRESSED)
00524         UseAmmoUnit();
00525       break ;
00526 
00527     default:
00528       break ;
00529   } ;
00530 }
00531 
00532 void NinjaRope::SignalTurnEnd()
00533 {
00534   p_Deselect();
00535 }
00536 
00537 EmptyWeaponConfig& NinjaRope::cfg()
00538 {
00539   return static_cast<EmptyWeaponConfig&>(*extra_params);
00540 }

Generated on Mon Jan 1 13:11:00 2007 for Wormux by  doxygen 1.4.7