hedgewars/GSHandlers.inc
changeset 3576 d85bdd5dc835
parent 3572 c968aacba708
child 3578 00aac66147c8
equal deleted inserted replaced
3568:ae89cf0735dc 3576:d85bdd5dc835
    13  *
    13  *
    14  * You should have received a copy of the GNU General Public License
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program; if not, write to the Free Software
    15  * along with this program; if not, write to the Free Software
    16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
    16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
    17  *)
    17  *)
       
    18 
       
    19 procedure doStepPerPixel(Gear: PGear; step: TGearStepProcedure; onlyCheckIfChanged: boolean);
       
    20 var
       
    21     dX, dY, sX, sY: hwFloat;
       
    22     i, steps: LongWord;
       
    23     caller: TGearStepProcedure;
       
    24 begin
       
    25     dX:= Gear^.dX;
       
    26     dY:= Gear^.dY;
       
    27     steps:= max(abs(hwRound(Gear^.X+dX)-hwRound(Gear^.X)), abs(hwRound(Gear^.Y+dY)-hwRound(Gear^.Y)));
       
    28 
       
    29     // Gear is still on the same Pixel it was before
       
    30     if steps < 1 then
       
    31     begin
       
    32         if onlyCheckIfChanged then
       
    33         begin
       
    34             Gear^.X := Gear^.X + dX;
       
    35             Gear^.Y := Gear^.Y + dY;
       
    36             EXIT;
       
    37         end
       
    38         else
       
    39             steps := 1;
       
    40     end;
       
    41 
       
    42     if steps > 1 then
       
    43     begin
       
    44         sX:= dX / steps;
       
    45         sY:= dY / steps;
       
    46     end
       
    47     else
       
    48     begin
       
    49         sX:= dX;
       
    50         sY:= dY;
       
    51     end;
       
    52 
       
    53     caller:= Gear^.doStep;
       
    54 
       
    55     for i:= 1 to steps do
       
    56     begin
       
    57         Gear^.X := Gear^.X + sX;
       
    58         Gear^.Y := Gear^.Y + sY;
       
    59         step(Gear);
       
    60         if (Gear^.doStep <> caller)
       
    61         or ((Gear^.State and gstCollision) <> 0)
       
    62         or ((Gear^.State and gstMoving) = 0) then
       
    63             break;
       
    64     end;
       
    65 end;
    18 
    66 
    19 procedure makeHogsWorry(x, y: hwFloat; r: LongInt);
    67 procedure makeHogsWorry(x, y: hwFloat; r: LongInt);
    20 var 
    68 var 
    21     gi: PGear;
    69     gi: PGear;
    22     d: LongInt;
    70     d: LongInt;
  3155 end;
  3203 end;
  3156 
  3204 
  3157 procedure doStepPortal(Gear: PGear);
  3205 procedure doStepPortal(Gear: PGear);
  3158 var 
  3206 var 
  3159     iterator, conPortal: PGear;
  3207     iterator, conPortal: PGear;
  3160     s, acptRadius, cdxy: hwFloat;
  3208     s, acptRadius, nx, ny, ox, oy, poffs, noffs, pspeed, nspeed: hwFloat;
  3161     noTrap, hasdxy: Boolean;
  3209     noTrap, hasdxy: Boolean;
  3162 begin
  3210 begin
  3163     doPortalColorSwitch();
  3211     doPortalColorSwitch();
  3164 
  3212 
  3165     // destroy portal if ground it was attached too is gone
  3213     // destroy portal if ground it was attached too is gone
  3190     // check all gears for stuff to port through
  3238     // check all gears for stuff to port through
  3191     iterator := nil;
  3239     iterator := nil;
  3192     while true do
  3240     while true do
  3193     begin
  3241     begin
  3194 
  3242 
       
  3243         // iterate through GearsList
  3195         if iterator = nil then
  3244         if iterator = nil then
  3196             iterator := GearsList // start
  3245             iterator := GearsList
  3197         else
  3246         else
  3198             iterator := iterator^.NextGear;
  3247             iterator := iterator^.NextGear;
  3199         // iterate through GearsList
  3248 
  3200 
  3249         // end of list?
  3201         if iterator = nil then
  3250         if iterator = nil then
  3202             break;
  3251             break;
  3203         // end of list
       
  3204 
  3252 
  3205         // don't port portals or other gear that wouldn't make sense
  3253         // don't port portals or other gear that wouldn't make sense
  3206         if (iterator^.Kind = gtPortal) or (iterator^.Kind = gtRope) or (iterator^.PortalCounter > 20) then
  3254         if (iterator^.Kind = gtPortal) or (iterator^.Kind = gtRope) or (iterator^.PortalCounter > 20) then
  3207             continue;
  3255             continue;
  3208 
  3256 
  3210         if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil)
  3258         if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil)
  3211            and (iterator = CurrentHedgehog^.Gear) and (CurAmmoGear <> nil) and (CurAmmoGear^.Kind =
  3259            and (iterator = CurrentHedgehog^.Gear) and (CurAmmoGear <> nil) and (CurAmmoGear^.Kind =
  3212            gtRope) then
  3260            gtRope) then
  3213             continue;
  3261             continue;
  3214 
  3262 
       
  3263         // check if gear fits through portal
  3215         if (iterator^.Radius > Gear^.Radius) then
  3264         if (iterator^.Radius > Gear^.Radius) then
  3216             continue;
  3265             continue;
  3217         // sorry, you're too fat!
  3266 
  3218 
  3267         // this is the max range we accept incoming gears in
  3219         // this is the range we accept incoming gears in
       
  3220         acptRadius := Int2hwFloat(iterator^.Radius+Gear^.Radius);
  3268         acptRadius := Int2hwFloat(iterator^.Radius+Gear^.Radius);
  3221 
  3269 
       
  3270         // too far away?
  3222         if (iterator^.X < Gear^.X - acptRadius)
  3271         if (iterator^.X < Gear^.X - acptRadius)
  3223            or (iterator^.X > Gear^.X + acptRadius)
  3272            or (iterator^.X > Gear^.X + acptRadius)
  3224            or (iterator^.Y < Gear^.Y - acptRadius)
  3273            or (iterator^.Y < Gear^.Y - acptRadius)
  3225            or (iterator^.Y > Gear^.Y + acptRadius) then
  3274            or (iterator^.Y > Gear^.Y + acptRadius) then
  3226             continue;
  3275             continue;
  3227         // too far away!
       
  3228 
  3276 
  3229         hasdxy := ((iterator^.dX.QWordValue <> 0) or (iterator^.dY.QWordValue <> 0));
  3277         hasdxy := ((iterator^.dX.QWordValue <> 0) or (iterator^.dY.QWordValue <> 0));
  3230 
  3278 
       
  3279         // won't port stuff that moves away from me!
  3231         if hasdxy and not (Gear^.dX*iterator^.dX + Gear^.dY*iterator^.dY).isNegative then
  3280         if hasdxy and not (Gear^.dX*iterator^.dX + Gear^.dY*iterator^.dY).isNegative then
  3232             continue;
  3281                 continue;
  3233         // won't port stuff that moves away from me!
  3282 
  3234 
  3283         if (iterator^.Kind <> gtCake) then
  3235         // wow! good candidate there, let's see if the distance really is small enough!
  3284         begin
  3236         if (Distance(Gear^.X-iterator^.X,Gear^.Y-iterator^.Y) > acptRadius) then
  3285             // wow! good candidate there, let's see if the distance and direction is okay!
  3237             continue;
  3286             if hasdxy then
       
  3287             begin
       
  3288                 s := int2hwFloat(iterator^.Radius) / Distance(iterator^.dX, iterator^.dY);
       
  3289                 ox:= iterator^.X + s * iterator^.dX;
       
  3290                 oy:= iterator^.Y + s * iterator^.dY;
       
  3291             end
       
  3292             else
       
  3293             begin
       
  3294                 ox:= iterator^.X;
       
  3295                 oy:= iterator^.Y + Int2hwFloat(iterator^.Radius);
       
  3296             end;
       
  3297 
       
  3298             if (hwRound(Distance(Gear^.X-ox,Gear^.Y-oy)) > Gear^.Radius) then
       
  3299                 continue;
       
  3300         end;
       
  3301 
  3238 (*
  3302 (*
  3239         noTrap := ((not Gear^.dY.isNegative or (Gear^.dY.QWordValue = 0))
  3303         noTrap := ((not Gear^.dY.isNegative or (Gear^.dY.QWordValue = 0))
  3240                   // can't be entered from above
  3304                   // can't be entered from above
  3241                   or ((conPortal^.dY.isNegative and not (conPortal^.dY.QWordValue = 0))));
  3305                   or ((conPortal^.dY.isNegative and not (conPortal^.dY.QWordValue = 0))));
  3242         // can't be left downwards; 
  3306         // can't be left downwards; 
  3250         DeleteCI(iterator);
  3314         DeleteCI(iterator);
  3251 
  3315 
  3252         // Until loops are reliably broken
  3316         // Until loops are reliably broken
  3253         inc(iterator^.PortalCounter);
  3317         inc(iterator^.PortalCounter);
  3254 
  3318 
  3255         // TODO: more accurate porting
  3319         // find out how much speed parallel to the portal vector
  3256         cdxy := Distance(conPortal^.dX, conPortal^.dY);
  3320         // the gear has, also get the vector offset
  3257         s := (Int2hwFloat(Gear^.Radius)) / cdxy;
  3321         pspeed:= (Gear^.dX * iterator^.dX + Gear^.dY * iterator^.dY);
  3258 
  3322         ox := (iterator^.X - Gear^.X);
       
  3323         oy := (iterator^.Y - Gear^.Y);
       
  3324         poffs:= (Gear^.dX * ox + Gear^.dY * oy);
       
  3325         // create a normal of the portal vector
       
  3326         nx := - Gear^.dY;
       
  3327         ny := Gear^.dX;
       
  3328         // pick the normal vector that's pointing skywards
       
  3329         if (not ny.isNegative) then
       
  3330             begin
       
  3331             nx.isNegative := not nx.isNegative;
       
  3332             ny.isNegative := not ny.isNegative;
       
  3333             end;
       
  3334         // now let's find out how much speed the gear has in the
       
  3335         // direction of that normal
       
  3336         nspeed:= (nx * iterator^.dX + ny * iterator^.dY);
       
  3337         noffs:= (nx * ox + ny * oy);
       
  3338 
       
  3339         // now let's project those back to the connected portal's vectors
       
  3340         nx := - conPortal^.dY;
       
  3341         ny := conPortal^.dX;
       
  3342         if ny.isNegative then
       
  3343             begin
       
  3344             nx.isNegative := not nx.isNegative;
       
  3345             ny.isNegative := not ny.isNegative;
       
  3346             end;
       
  3347 //AddFileLog('poffs:'+cstr(poffs)+' noffs:'+cstr(noffs)+' pspeed:'+cstr(pspeed)+' nspeed:'+cstr(nspeed));
       
  3348         iterator^.dX := -pspeed * conPortal^.dX - nspeed * nx;
       
  3349         iterator^.dY := -pspeed * conPortal^.dY - nspeed * ny;
  3259         if iterator^.Kind = gtCake then
  3350         if iterator^.Kind = gtCake then
  3260             begin
  3351             poffs := poffs * _0_5;
  3261             iterator^.X := conPortal^.X ;
  3352         iterator^.X := conPortal^.X + poffs * conPortal^.dX + noffs * nx;
  3262             iterator^.Y := conPortal^.Y ;
  3353         iterator^.Y := conPortal^.Y + poffs * conPortal^.dY + noffs * ny;
  3263             end
       
  3264         else
       
  3265             begin
       
  3266             iterator^.X := conPortal^.X + s * conPortal^.dX;
       
  3267             iterator^.Y := conPortal^.Y + s * conPortal^.dY;
       
  3268 
       
  3269             s := Distance(iterator^.dX, iterator^.dY) / cdxy;
       
  3270 
       
  3271             iterator^.dX := s * conPortal^.dX;
       
  3272             iterator^.dY := s * conPortal^.dY
       
  3273             end;
       
  3274 
  3354 
  3275         FollowGear := iterator;
  3355         FollowGear := iterator;
  3276 
  3356 //AddFileLog('portal''d');
       
  3357 
       
  3358 {
  3277         s := _0_2 + _0_008 * Gear^.Health;
  3359         s := _0_2 + _0_008 * Gear^.Health;
  3278         iterator^.dX := s * iterator^.dX;
  3360         iterator^.dX := s * iterator^.dX;
  3279         iterator^.dY := s * iterator^.dY;
  3361         iterator^.dY := s * iterator^.dY;
       
  3362 }
  3280 
  3363 
  3281         if Gear^.Health > 1 then dec(Gear^.Health);
  3364         if Gear^.Health > 1 then dec(Gear^.Health);
  3282             //dec(iterator^.Health);??
  3365 
  3283 
  3366 {        // breaks (some) loops
  3284         // breaks (some) loops
       
  3285         if Distance(iterator^.dX, iterator^.dY) > _0_96 then
  3367         if Distance(iterator^.dX, iterator^.dY) > _0_96 then
  3286         begin
  3368         begin
  3287             iterator^.dX := iterator^.dX + signAs(cGravity * getRandom(1000),iterator^.dX);
  3369             iterator^.dX := iterator^.dX + signAs(cGravity * getRandom(1000),iterator^.dX);
  3288             iterator^.dY := iterator^.dY + signAs(cGravity * getRandom(1000),iterator^.dY);
  3370             iterator^.dY := iterator^.dY + signAs(cGravity * getRandom(1000),iterator^.dY);
  3289             s := _0_96 / Distance(iterator^.dX, iterator^.dY);
  3371             s := _0_96 / Distance(iterator^.dX, iterator^.dY);
  3290             iterator^.dX := s * iterator^.dX;
  3372             iterator^.dX := s * iterator^.dX;
  3291             iterator^.dY := s * iterator^.dX;
  3373             iterator^.dY := s * iterator^.dX;
  3292         end;
  3374         end;
  3293     end;
  3375 }
  3294 end;
  3376     end;
  3295 
  3377 end;
  3296 procedure doStepMovingPortal(Gear: PGear);
  3378 
       
  3379 procedure doStepMovingPortal_real(Gear: PGear);
  3297 var 
  3380 var 
  3298     x, y, tx, ty: LongInt;
  3381     x, y, tx, ty: LongInt;
  3299     //, bx, by, tangle: LongInt;
       
  3300     s: hwFloat;
  3382     s: hwFloat;
  3301 
  3383 
  3302 procedure loadNewPortalBall(oldPortal: PGear; destroyGear: Boolean);
  3384 procedure loadNewPortalBall(oldPortal: PGear; destroyGear: Boolean);
  3303 var 
  3385 var 
  3304     flags: LongWord;
  3386     flags: LongWord;
  3320 
  3402 
  3321     if destroyGear then oldPortal^.Timer:= 0;
  3403     if destroyGear then oldPortal^.Timer:= 0;
  3322 end;
  3404 end;
  3323 
  3405 
  3324 begin
  3406 begin
  3325     if (Gear^.Timer < 1)
       
  3326        or (PHedgehog(Gear^.Hedgehog) <> CurrentHedgehog) then
       
  3327     begin
       
  3328         deleteGear(Gear);
       
  3329         EXIT;
       
  3330     end;
       
  3331     
       
  3332     doPortalColorSwitch();
       
  3333 
       
  3334     Gear^.X := Gear^.X + Gear^.dX;
       
  3335     Gear^.Y := Gear^.Y + Gear^.dY;
       
  3336     x := hwRound(Gear^.X);
  3407     x := hwRound(Gear^.X);
  3337     y := hwRound(Gear^.Y);
  3408     y := hwRound(Gear^.Y);
  3338     tx := 0;
  3409     tx := 0;
  3339     ty := 0;
  3410     ty := 0;
  3340     // avoid compiler hints
  3411     // avoid compiler hints
  3341 
  3412 
  3342     if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] > 255) then
  3413     if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] > 255) then
  3343     begin
  3414     begin
       
  3415         Gear^.State := Gear^.State or gstCollision;
       
  3416         Gear^.State := Gear^.State and not gstMoving;
  3344         if not calcSlopeTangent(Gear, x, y, tx, ty, 255)
  3417         if not calcSlopeTangent(Gear, x, y, tx, ty, 255)
  3345            or (DistanceI(tx,ty) < _12) then // reject shots at too irregular terrain
  3418            or (DistanceI(tx,ty) < _12) then // reject shots at too irregular terrain
  3346         begin
  3419         begin
  3347             loadNewPortalBall(Gear, true);
  3420             loadNewPortalBall(Gear, true);
  3348             EXIT;
  3421             EXIT;
  3369             loadNewPortalBall(Gear, true);
  3442             loadNewPortalBall(Gear, true);
  3370     end
  3443     end
  3371     else if (y > cWaterLine) or (y < -LAND_WIDTH)
  3444     else if (y > cWaterLine) or (y < -LAND_WIDTH)
  3372             or (x > 2*LAND_WIDTH) or (x < -LAND_WIDTH) then
  3445             or (x > 2*LAND_WIDTH) or (x < -LAND_WIDTH) then
  3373              loadNewPortalBall(Gear, true);
  3446              loadNewPortalBall(Gear, true);
       
  3447 end;
       
  3448 
       
  3449 procedure doStepMovingPortal(Gear: PGear);
       
  3450 begin
       
  3451     doPortalColorSwitch();
       
  3452     doStepPerPixel(Gear, @doStepMovingPortal_real, true);
       
  3453     if (Gear^.Timer < 1)
       
  3454        or (PHedgehog(Gear^.Hedgehog) <> CurrentHedgehog) then
       
  3455             deleteGear(Gear);
  3374 end;
  3456 end;
  3375 
  3457 
  3376 procedure doStepPortalShot(newPortal: PGear);
  3458 procedure doStepPortalShot(newPortal: PGear);
  3377 var 
  3459 var 
  3378     iterator: PGear;
  3460     iterator: PGear;
  3420                     end;
  3502                     end;
  3421                 iterator^.PortalCounter:= 0;
  3503                 iterator^.PortalCounter:= 0;
  3422                 iterator := iterator^.NextGear
  3504                 iterator := iterator^.NextGear
  3423             end;
  3505             end;
  3424         end;
  3506         end;
       
  3507     newPortal^.State := newPortal^.State and not gstCollision;
       
  3508     newPortal^.State := newPortal^.State or gstMoving;
  3425     newPortal^.doStep := @doStepMovingPortal;
  3509     newPortal^.doStep := @doStepMovingPortal;
  3426 end;
  3510 end;
  3427 
  3511 
  3428 procedure doStepPiano(Gear: PGear);
  3512 procedure doStepPiano(Gear: PGear);
  3429 var 
  3513 var