3340 end; |
3340 end; |
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, acptRadius, nx, ny, ox, oy, poffs, noffs, pspeed, nspeed: hwFloat; |
3345 s, r, nx, ny, ox, oy, poffs, noffs, pspeed, nspeed: hwFloat; |
3346 hasdxy: Boolean; |
3346 hasdxy, isbullet: 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) |
3386 // end of list? |
3386 // end of list? |
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 = gtPortal) or (iterator^.Kind = gtRope) |
3391 if (iterator^.Kind in [gtPortal, gtRope, gtRCPlane]) |
3392 or (iterator^.Kind = gtRCPlane) or (iterator^.PortalCounter > 20) then |
3392 or (iterator^.PortalCounter > 20) then |
3393 continue; |
3393 continue; |
3394 |
3394 |
3395 // don't port hogs on rope |
3395 // don't port hogs on rope |
3396 if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) |
3396 if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil) |
3397 and (iterator = CurrentHedgehog^.Gear) and (CurAmmoGear <> nil) and (CurAmmoGear^.Kind = |
3397 and (iterator = CurrentHedgehog^.Gear) and (CurAmmoGear <> nil) and (CurAmmoGear^.Kind = |
3398 gtRope) then |
3398 gtRope) then |
3401 // check if gear fits through portal |
3401 // check if gear fits through portal |
3402 if (iterator^.Radius > Gear^.Radius) then |
3402 if (iterator^.Radius > Gear^.Radius) then |
3403 continue; |
3403 continue; |
3404 |
3404 |
3405 // this is the max range we accept incoming gears in |
3405 // this is the max range we accept incoming gears in |
3406 acptRadius := Int2hwFloat(iterator^.Radius+Gear^.Radius); |
3406 r := Int2hwFloat(iterator^.Radius+Gear^.Radius); |
3407 |
3407 |
3408 // too far away? |
3408 // too far away? |
3409 if (iterator^.X < Gear^.X - acptRadius) |
3409 if (iterator^.X < Gear^.X - r) |
3410 or (iterator^.X > Gear^.X + acptRadius) |
3410 or (iterator^.X > Gear^.X + r) |
3411 or (iterator^.Y < Gear^.Y - acptRadius) |
3411 or (iterator^.Y < Gear^.Y - r) |
3412 or (iterator^.Y > Gear^.Y + acptRadius) then |
3412 or (iterator^.Y > Gear^.Y + r) then |
3413 continue; |
3413 continue; |
3414 |
3414 |
3415 hasdxy := ((iterator^.dX.QWordValue <> 0) or (iterator^.dY.QWordValue <> 0)); |
3415 hasdxy := ((iterator^.dX.QWordValue <> 0) or (iterator^.dY.QWordValue <> 0)); |
3416 |
3416 |
3417 // in case the object is not moving, let's asume it's moving towards the portal |
3417 // in case the object is not moving, let's asume it's moving towards the portal |
3424 begin |
3424 begin |
3425 ox:= iterator^.dX; |
3425 ox:= iterator^.dX; |
3426 oy:= iterator^.dY; |
3426 oy:= iterator^.dY; |
3427 end; |
3427 end; |
3428 |
3428 |
3429 // won't port stuff that moves away from me! |
3429 // won't port stuff that does not move towards the front/portal entrance |
3430 if not (Gear^.dX*ox + Gear^.dY*oy).isNegative then |
3430 if not (Gear^.dX*ox + Gear^.dY*oy).isNegative then |
3431 continue; |
3431 continue; |
3432 |
3432 |
3433 if (iterator^.Kind <> gtCake) then |
3433 isbullet:= (iterator^.Kind in [gtShotgunShot, gtDEagleShot, gtSniperRifleShot, gtSineGunShot]); |
|
3434 |
|
3435 r:= int2hwFloat(iterator^.Radius); |
|
3436 |
|
3437 if not isbullet and (iterator^.Kind <> gtCake) then |
3434 begin |
3438 begin |
3435 // wow! good candidate there, let's see if the distance and direction is okay! |
3439 // wow! good candidate there, let's see if the distance and direction is okay! |
3436 if hasdxy then |
3440 if hasdxy then |
3437 begin |
3441 begin |
3438 s := int2hwFloat(iterator^.Radius) / Distance(iterator^.dX, iterator^.dY); |
3442 s := r / Distance(iterator^.dX, iterator^.dY); |
3439 ox:= iterator^.X + s * iterator^.dX; |
3443 ox:= iterator^.X + s * iterator^.dX; |
3440 oy:= iterator^.Y + s * iterator^.dY; |
3444 oy:= iterator^.Y + s * iterator^.dY; |
3441 end |
3445 end |
3442 else |
3446 else |
3443 begin |
3447 begin |
3444 ox:= iterator^.X; |
3448 ox:= iterator^.X; |
3445 oy:= iterator^.Y + Int2hwFloat(iterator^.Radius); |
3449 oy:= iterator^.Y + r; |
3446 end; |
3450 end; |
3447 |
3451 |
3448 if (hwRound(Distance(Gear^.X-ox,Gear^.Y-oy)) > Gear^.Radius + 1 ) then |
3452 if (hwRound(Distance(Gear^.X-ox,Gear^.Y-oy)) > Gear^.Radius + 1 ) then |
3449 continue; |
3453 continue; |
3450 end; |
3454 end; |
3457 |
3461 |
3458 // prevent getting stuck in a ground portal loop |
3462 // prevent getting stuck in a ground portal loop |
3459 if noTrap and (iterator^.dY.QWordValue < _0_08.QWordValue) then |
3463 if noTrap and (iterator^.dY.QWordValue < _0_08.QWordValue) then |
3460 continue; *) |
3464 continue; *) |
3461 |
3465 |
3462 iterator^.Active := true; |
3466 // calc gear offset in portal vector direction |
3463 iterator^.State := iterator^.State or gstMoving; |
|
3464 DeleteCI(iterator); |
|
3465 |
|
3466 // Until loops are reliably broken |
|
3467 inc(iterator^.PortalCounter); |
|
3468 |
|
3469 // find out how much speed parallel to the portal vector |
|
3470 // the gear has, also get the vector offset |
|
3471 pspeed:= (Gear^.dX * iterator^.dX + Gear^.dY * iterator^.dY); |
|
3472 ox := (iterator^.X - Gear^.X); |
3467 ox := (iterator^.X - Gear^.X); |
3473 oy := (iterator^.Y - Gear^.Y); |
3468 oy := (iterator^.Y - Gear^.Y); |
3474 poffs:= (Gear^.dX * ox + Gear^.dY * oy); |
3469 poffs:= (Gear^.dX * ox + Gear^.dY * oy); |
|
3470 |
|
3471 if poffs < _0 then |
|
3472 continue; |
|
3473 |
|
3474 // don't port stuff that isn't really close; |
|
3475 if not isbullet and (poffs > (r + _3)) then |
|
3476 continue; |
|
3477 |
|
3478 if isbullet then |
|
3479 poffs:= _1_5; |
|
3480 |
3475 // create a normal of the portal vector, but ... |
3481 // create a normal of the portal vector, but ... |
3476 nx := Gear^.dY; |
3482 nx := Gear^.dY; |
3477 ny := Gear^.dX; |
3483 ny := Gear^.dX; |
3478 // ... decide where the top is based on the hog's direction when firing the portal |
3484 // ... decide where the top is based on the hog's direction when firing the portal |
3479 if Gear^.Elasticity.isNegative then |
3485 if Gear^.Elasticity.isNegative then |
3480 nx.isNegative := not nx.isNegative |
3486 nx.isNegative := not nx.isNegative |
3481 else |
3487 else |
3482 ny.isNegative := not ny.isNegative; |
3488 ny.isNegative := not ny.isNegative; |
3483 |
3489 |
3484 // now let's find out how much speed the gear has in the |
3490 // calc gear offset in portal normal vector direction |
3485 // direction of that normal |
3491 noffs:= (nx * ox + ny * oy); |
|
3492 |
|
3493 // don't port stuff that misses the portal entrance |
|
3494 if noffs > (r + _1_5) then |
|
3495 continue; |
|
3496 |
|
3497 // move stuff with high normal offset close to the portal's center |
|
3498 if not isbullet then |
|
3499 begin |
|
3500 s := hwAbs(noffs) + r - int2hwFloat(Gear^.Radius); |
|
3501 if s > _0 then |
|
3502 noffs:= noffs - SignAs(s,noffs) |
|
3503 end; |
|
3504 |
|
3505 // |
|
3506 // gears that make it till here will definately be ported |
|
3507 // |
|
3508 |
|
3509 iterator^.Active := true; |
|
3510 iterator^.State := iterator^.State or gstMoving; |
|
3511 DeleteCI(iterator); |
|
3512 |
|
3513 // Until loops are reliably broken |
|
3514 inc(iterator^.PortalCounter); |
|
3515 |
|
3516 // calc gear speed along to the vector and the normal vector of the portal |
|
3517 pspeed:= (Gear^.dX * iterator^.dX + Gear^.dY * iterator^.dY); |
3486 nspeed:= (nx * iterator^.dX + ny * iterator^.dY); |
3518 nspeed:= (nx * iterator^.dX + ny * iterator^.dY); |
3487 noffs:= (nx * ox + ny * oy); |
3519 |
3488 |
3520 // creating normal vector of connected (exit) portal |
3489 // now let's project those back to the connected portal's vectors |
|
3490 nx := conPortal^.dY; |
3521 nx := conPortal^.dY; |
3491 ny := conPortal^.dX; |
3522 ny := conPortal^.dX; |
3492 if conPortal^.Elasticity.isNegative then |
3523 if conPortal^.Elasticity.isNegative then |
3493 nx.isNegative := not nx.isNegative |
3524 nx.isNegative := not nx.isNegative |
3494 else |
3525 else |
3496 |
3527 |
3497 //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)); |
3498 iterator^.dX := -pspeed * conPortal^.dX + nspeed * nx; |
3529 iterator^.dX := -pspeed * conPortal^.dX + nspeed * nx; |
3499 iterator^.dY := -pspeed * conPortal^.dY + nspeed * ny; |
3530 iterator^.dY := -pspeed * conPortal^.dY + nspeed * ny; |
3500 if iterator^.Kind = gtCake then |
3531 if iterator^.Kind = gtCake then |
3501 poffs := poffs * _0_5; |
3532 poffs := poffs * _0_5 |
|
3533 else |
|
3534 if poffs < r + _1_5 then |
|
3535 poffs := r + _1_5; |
3502 iterator^.X := conPortal^.X + poffs * conPortal^.dX + noffs * nx; |
3536 iterator^.X := conPortal^.X + poffs * conPortal^.dX + noffs * nx; |
3503 iterator^.Y := conPortal^.Y + poffs * conPortal^.dY + noffs * ny; |
3537 iterator^.Y := conPortal^.Y + poffs * conPortal^.dY + noffs * ny; |
3504 |
3538 |
3505 FollowGear := iterator; |
3539 if not isbullet then |
|
3540 FollowGear := iterator; |
3506 //AddFileLog('portal''d'); |
3541 //AddFileLog('portal''d'); |
3507 |
3542 |
3508 { |
3543 { |
3509 s := _0_2 + _0_008 * Gear^.Health; |
3544 s := _0_2 + _0_008 * Gear^.Health; |
3510 iterator^.dX := s * iterator^.dX; |
3545 iterator^.dX := s * iterator^.dX; |
3511 iterator^.dY := s * iterator^.dY; |
3546 iterator^.dY := s * iterator^.dY; |
3512 } |
3547 } |
|
3548 // This jiggles gears, to ensure a portal connection just placed under a gear takes effect. |
|
3549 iterator:= GearsList; |
|
3550 while iterator <> nil do |
|
3551 begin |
|
3552 if iterator^.Kind <> gtPortal then |
|
3553 begin |
|
3554 iterator^.Active:= true; |
|
3555 if iterator^.dY.QWordValue = _0.QWordValue then iterator^.dY.isNegative:= false; |
|
3556 iterator^.State:= iterator^.State or gstMoving; |
|
3557 DeleteCI(iterator); |
|
3558 inc(iterator^.dY.QWordValue,10); |
|
3559 end; |
|
3560 iterator:= iterator^.NextGear |
|
3561 end; |
3513 |
3562 |
3514 if Gear^.Health > 1 then dec(Gear^.Health); |
3563 if Gear^.Health > 1 then dec(Gear^.Health); |
3515 |
3564 |
3516 { // breaks (some) loops |
3565 { // breaks (some) loops |
3517 if Distance(iterator^.dX, iterator^.dY) > _0_96 then |
3566 if Distance(iterator^.dX, iterator^.dY) > _0_96 then |