00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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 ;
00038 const int DST_MIN = 6 ;
00039 const uint MAX_ROPE_LEN = 450 ;
00040 const uint ROPE_DRAW_SPEED = 12 ;
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
00119
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
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
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
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
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
00207
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
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) &&
00247 (NodeSense * CurrentSense < 0) )
00248
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
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
00307
00308 if (collision)
00309 {
00310
00311 if (delta_len != 0)
00312 {
00313
00314
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
00325 while (TryAddNode(CurrentSense))
00326 AddNode = true ;
00327
00328
00329
00330 if (AddNode)
00331 return ;
00332
00333
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
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 }