hedgewars/GSHandlers.inc
changeset 4092 bf13068194b3
parent 4076 7ca17cb94992
child 4103 aa932f2e6349
equal deleted inserted replaced
4091:f89b8d0afbe1 4092:bf13068194b3
  3341 
  3341 
  3342 procedure doStepPortal(Gear: PGear);
  3342 procedure doStepPortal(Gear: PGear);
  3343 var 
  3343 var 
  3344     iterator, conPortal: PGear;
  3344     iterator, conPortal: PGear;
  3345     s, r, nx, ny, ox, oy, poffs, noffs, pspeed, nspeed: hwFloat;
  3345     s, r, nx, ny, ox, oy, poffs, noffs, pspeed, nspeed: hwFloat;
  3346     hasdxy, isbullet: Boolean;
  3346     hasdxy, isbullet, iscake: Boolean;
  3347 begin
  3347 begin
  3348     doPortalColorSwitch();
  3348     doPortalColorSwitch();
  3349 
  3349 
  3350     // destroy portal if ground it was attached too is gone
  3350     // destroy portal if ground it was attached too is gone
  3351     if ((Land[hwRound(Gear^.Y), hwRound(Gear^.X)] and $FF00) = 0)
  3351     if ((Land[hwRound(Gear^.Y), hwRound(Gear^.X)] and $FF00) = 0)
  3387         if iterator = nil then
  3387         if iterator = nil then
  3388             break;
  3388             break;
  3389 
  3389 
  3390         // don't port portals or other gear that wouldn't make sense
  3390         // don't port portals or other gear that wouldn't make sense
  3391         if (iterator^.Kind in [gtPortal, gtRope, gtRCPlane])
  3391         if (iterator^.Kind in [gtPortal, gtRope, gtRCPlane])
  3392             or (iterator^.PortalCounter > 20) then
  3392             or (iterator^.PortalCounter > 32) then
  3393              continue;
  3393              continue;
  3394 
  3394 
  3395         // don't port hogs on rope
  3395         // don't port hogs on rope
       
  3396         // TODO: this will also prevent hogs while falling after rope use from
       
  3397         //       falling through portals... fix that!
  3396         if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil)
  3398         if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil)
  3397            and (iterator = CurrentHedgehog^.Gear) and (CurAmmoGear <> nil) and (CurAmmoGear^.Kind =
  3399            and (iterator = CurrentHedgehog^.Gear) and (CurAmmoGear <> nil) and (CurAmmoGear^.Kind =
  3398            gtRope) then
  3400            gtRope) then
  3399             continue;
  3401             continue;
  3400 
  3402 
  3410            or (iterator^.X > Gear^.X + r)
  3412            or (iterator^.X > Gear^.X + r)
  3411            or (iterator^.Y < Gear^.Y - r)
  3413            or (iterator^.Y < Gear^.Y - r)
  3412            or (iterator^.Y > Gear^.Y + r) then
  3414            or (iterator^.Y > Gear^.Y + r) then
  3413             continue;
  3415             continue;
  3414 
  3416 
  3415         hasdxy := ((iterator^.dX.QWordValue <> 0) or (iterator^.dY.QWordValue <> 0));
  3417         hasdxy := (((iterator^.dX.QWordValue <> 0) or (iterator^.dY.QWordValue <> 0))
  3416 
  3418                     or ((iterator^.State or gstMoving) = 0));
  3417         // in case the object is not moving, let's asume it's moving towards the portal
  3419 
       
  3420         // in case the object is not moving, let's asume it's falling towards the portal
  3418         if not hasdxy then
  3421         if not hasdxy then
  3419         begin
  3422         begin
       
  3423             if Gear^.Y < iterator^.Y then
       
  3424                 continue;
  3420             ox:= Gear^.X - iterator^.X;
  3425             ox:= Gear^.X - iterator^.X;
  3421             oy:= Gear^.Y - iterator^.Y;
  3426             oy:= Gear^.Y - iterator^.Y;
  3422         end
  3427         end
  3423         else
  3428         else
  3424         begin
  3429         begin
  3425             ox:= iterator^.dX;
  3430             ox:= iterator^.dX;
  3426             oy:= iterator^.dY;
  3431             oy:= iterator^.dY;
  3427         end;
  3432         end;
  3428 
  3433 
       
  3434         // cake will need extra treatment... it's so delicious and moist!
       
  3435         iscake:= (iterator^.Kind = gtCake);
       
  3436 
  3429         // won't port stuff that does not move towards the front/portal entrance
  3437         // won't port stuff that does not move towards the front/portal entrance
  3430         if not (Gear^.dX*ox + Gear^.dY*oy).isNegative then
  3438         if iscake then
       
  3439         begin
       
  3440             if not ((iterator^.X - Gear^.X)*ox + (iterator^.Y - Gear^.Y)*oy).isNegative then
  3431                 continue;
  3441                 continue;
       
  3442         end
       
  3443         else
       
  3444             if not (Gear^.dX*ox + Gear^.dY*oy).isNegative then
       
  3445                 continue;
  3432 
  3446 
  3433         isbullet:= (iterator^.Kind in [gtShotgunShot, gtDEagleShot, gtSniperRifleShot, gtSineGunShot]);
  3447         isbullet:= (iterator^.Kind in [gtShotgunShot, gtDEagleShot, gtSniperRifleShot, gtSineGunShot]);
  3434 
  3448 
  3435         r:= int2hwFloat(iterator^.Radius);
  3449         r:= int2hwFloat(iterator^.Radius);
  3436 
  3450 
  3437         if not isbullet and (iterator^.Kind <> gtCake) then
  3451         if not (isbullet or iscake) then
  3438         begin
  3452         begin
  3439             // wow! good candidate there, let's see if the distance and direction is okay!
  3453             // wow! good candidate there, let's see if the distance and direction is okay!
  3440             if hasdxy then
  3454             if hasdxy then
  3441             begin
  3455             begin
  3442                 s := r / Distance(iterator^.dX, iterator^.dY);
  3456                 s := r / Distance(iterator^.dX, iterator^.dY);
  3451 
  3465 
  3452             if (hwRound(Distance(Gear^.X-ox,Gear^.Y-oy)) > Gear^.Radius + 1 ) then
  3466             if (hwRound(Distance(Gear^.X-ox,Gear^.Y-oy)) > Gear^.Radius + 1 ) then
  3453                 continue;
  3467                 continue;
  3454         end;
  3468         end;
  3455 
  3469 
  3456 (*
       
  3457         noTrap := ((not Gear^.dY.isNegative or (Gear^.dY.QWordValue = 0))
       
  3458                   // can't be entered from above
       
  3459                   or ((conPortal^.dY.isNegative and not (conPortal^.dY.QWordValue = 0))));
       
  3460         // can't be left downwards; 
       
  3461 
       
  3462         // prevent getting stuck in a ground portal loop       
       
  3463         if noTrap and (iterator^.dY.QWordValue < _0_08.QWordValue) then
       
  3464             continue; *)
       
  3465 
       
  3466         // calc gear offset in portal vector direction
  3470         // calc gear offset in portal vector direction
  3467         ox := (iterator^.X - Gear^.X);
  3471         ox := (iterator^.X - Gear^.X);
  3468         oy := (iterator^.Y - Gear^.Y);
  3472         oy := (iterator^.Y - Gear^.Y);
  3469         poffs:= (Gear^.dX * ox + Gear^.dY * oy);
  3473         poffs:= (Gear^.dX * ox + Gear^.dY * oy);
  3470 
  3474 
  3472             continue;
  3476             continue;
  3473 
  3477 
  3474         //
  3478         //
  3475         // gears that make it till here will definately be ported
  3479         // gears that make it till here will definately be ported
  3476         //
  3480         //
  3477 
       
  3478         if isbullet then
       
  3479             poffs:= _1_5;
       
  3480 
  3481 
  3481         // create a normal of the portal vector, but ...
  3482         // create a normal of the portal vector, but ...
  3482         nx := Gear^.dY;
  3483         nx := Gear^.dY;
  3483         ny := Gear^.dX;
  3484         ny := Gear^.dX;
  3484         // ... decide where the top is based on the hog's direction when firing the portal
  3485         // ... decide where the top is based on the hog's direction when firing the portal
  3488             ny.isNegative := not ny.isNegative;
  3489             ny.isNegative := not ny.isNegative;
  3489 
  3490 
  3490         // calc gear offset in portal normal vector direction
  3491         // calc gear offset in portal normal vector direction
  3491         noffs:= (nx * ox + ny * oy);
  3492         noffs:= (nx * ox + ny * oy);
  3492 
  3493 
  3493         // move stuff with high normal offset close to the portal's center
  3494         // avoid gravity related loops of not really moving gear
  3494         if not isbullet then
  3495         if not iscake and (Gear^.dY.isNegative) and (conPortal^.dY.isNegative)
  3495         begin
  3496             and ((iterator^.dX.QWordValue + iterator^.dY.QWordValue) < _0_08.QWordValue)
  3496             s := hwAbs(noffs) + r - int2hwFloat(Gear^.Radius);
  3497             and (iterator^.PortalCounter > 0) then
  3497             if s > _0 then
  3498              continue;
  3498                 noffs:= noffs - SignAs(s,noffs)
       
  3499         end;
       
  3500 
       
  3501         iterator^.Active := true;
       
  3502         iterator^.State := iterator^.State or gstMoving;
       
  3503         DeleteCI(iterator);
       
  3504 
  3499 
  3505         // Until loops are reliably broken
  3500         // Until loops are reliably broken
  3506         inc(iterator^.PortalCounter);
  3501         inc(iterator^.PortalCounter);
  3507 
  3502 
  3508         // calc gear speed along to the vector and the normal vector of the portal
  3503         // calc gear speed along to the vector and the normal vector of the portal
  3509         pspeed:= (Gear^.dX * iterator^.dX + Gear^.dY * iterator^.dY);
  3504         if hasdxy then
  3510         nspeed:= (nx * iterator^.dX + ny * iterator^.dY);
  3505         begin
       
  3506             pspeed:= (Gear^.dX * iterator^.dX + Gear^.dY * iterator^.dY);
       
  3507             nspeed:= (nx * iterator^.dX + ny * iterator^.dY);
       
  3508         end
       
  3509         else
       
  3510         begin
       
  3511             pspeed:= hwAbs(cGravity * oy);
       
  3512             nspeed:= _0;
       
  3513         end;
  3511 
  3514 
  3512         // creating normal vector of connected (exit) portal
  3515         // creating normal vector of connected (exit) portal
  3513         nx := conPortal^.dY;
  3516         nx := conPortal^.dY;
  3514         ny := conPortal^.dX;
  3517         ny := conPortal^.dX;
  3515         if conPortal^.Elasticity.isNegative then
  3518         if conPortal^.Elasticity.isNegative then
  3516             nx.isNegative := not nx.isNegative
  3519             nx.isNegative := not nx.isNegative
  3517         else
  3520         else
  3518             ny.isNegative := not ny.isNegative;
  3521             ny.isNegative := not ny.isNegative;
  3519 
  3522 
       
  3523         // inverse cake's normal movement direction,
       
  3524         // as if it just walked through a hole
       
  3525         if iscake then
       
  3526             nspeed.isNegative:= not nspeed.isNegative;
       
  3527 
  3520 //AddFileLog('poffs:'+cstr(poffs)+' noffs:'+cstr(noffs)+' pspeed:'+cstr(pspeed)+' nspeed:'+cstr(nspeed));
  3528 //AddFileLog('poffs:'+cstr(poffs)+' noffs:'+cstr(noffs)+' pspeed:'+cstr(pspeed)+' nspeed:'+cstr(nspeed));
  3521         iterator^.dX := -pspeed * conPortal^.dX + nspeed * nx;
  3529         iterator^.dX := -pspeed * conPortal^.dX + nspeed * nx;
  3522         iterator^.dY := -pspeed * conPortal^.dY + nspeed * ny;
  3530         iterator^.dY := -pspeed * conPortal^.dY + nspeed * ny;
  3523         if iterator^.Kind = gtCake then
  3531 
  3524             poffs := poffs * _0_5
  3532         // make the gear's exit position close to the portal while
  3525         else
  3533         // still respecting the movement direction
  3526         if poffs < r + _1_5 then
  3534 
  3527             poffs := r + _1_5;
  3535          // determine the distance (in exit vector direction)
       
  3536          // that we want the gear at
       
  3537          if iscake then
       
  3538              ox:= (r - _0_7)
       
  3539          else
       
  3540              ox:= (r + _1_9);
       
  3541          s:= ox / poffs;
       
  3542          poffs:= ox;
       
  3543          if (nspeed.QWordValue <> 0) and (pspeed > _0) then
       
  3544              noffs:= noffs * s * (nspeed / pspeed);
       
  3545 
       
  3546         // move stuff with high normal offset closer to the portal's center
       
  3547         if not isbullet then
       
  3548         begin
       
  3549             s := hwAbs(noffs) + r - int2hwFloat(Gear^.Radius);
       
  3550             if s > _0 then
       
  3551                 noffs:= noffs - SignAs(s,noffs)
       
  3552         end;
       
  3553 
  3528         iterator^.X := conPortal^.X + poffs * conPortal^.dX + noffs * nx;
  3554         iterator^.X := conPortal^.X + poffs * conPortal^.dX + noffs * nx;
  3529         iterator^.Y := conPortal^.Y + poffs * conPortal^.dY + noffs * ny;
  3555         iterator^.Y := conPortal^.Y + poffs * conPortal^.dY + noffs * ny;
       
  3556 
       
  3557         if not hasdxy and not (conPortal^.dY.isNegative) then
       
  3558         begin
       
  3559             iterator^.dY:= iterator^.dY + hwAbs(cGravity * (iterator^.Y - conPortal^.Y))
       
  3560         end;
  3530 
  3561 
  3531         if not isbullet then
  3562         if not isbullet then
  3532             FollowGear := iterator;
  3563             FollowGear := iterator;
  3533 //AddFileLog('portal''d');
  3564 //AddFileLog('portal''d');
  3534 
  3565 
  3545                 begin
  3576                 begin
  3546                 iterator^.Active:= true;
  3577                 iterator^.Active:= true;
  3547                 if iterator^.dY.QWordValue = _0.QWordValue then iterator^.dY.isNegative:= false;
  3578                 if iterator^.dY.QWordValue = _0.QWordValue then iterator^.dY.isNegative:= false;
  3548                 iterator^.State:= iterator^.State or gstMoving;
  3579                 iterator^.State:= iterator^.State or gstMoving;
  3549                 DeleteCI(iterator);
  3580                 DeleteCI(iterator);
  3550                 inc(iterator^.dY.QWordValue,10);
  3581                 //inc(iterator^.dY.QWordValue,10);
  3551                 end;
  3582                 end;
  3552             iterator:= iterator^.NextGear
  3583             iterator:= iterator^.NextGear
  3553             end;
  3584             end;
  3554 
  3585 
  3555         if Gear^.Health > 1 then dec(Gear^.Health);
  3586         if Gear^.Health > 1 then dec(Gear^.Health);