hedgewars/GSHandlers.inc
changeset 3428 46a2694867bc
parent 3424 5543340db663
child 3431 e36dffdf7b82
equal deleted inserted replaced
3427:b49ed5673727 3428:46a2694867bc
  3042         exit
  3042         exit
  3043     end;
  3043     end;
  3044 end;
  3044 end;
  3045 
  3045 
  3046 ////////////////////////////////////////////////////////////////////////////////
  3046 ////////////////////////////////////////////////////////////////////////////////
       
  3047 procedure doPortalColorSwitch();
       
  3048 var flags: LongWord;
       
  3049 begin
       
  3050    if (CurrentHedgehog <> nil)
       
  3051         and (CurrentHedgehog^.Gear <> nil)
       
  3052             and ((CurrentHedgehog^.Gear^.Message and gm_Switch) <> 0) then
       
  3053             With CurrentHedgehog^ do
       
  3054                 if (Ammo^[CurSlot, CurAmmo].AmmoType = amPortalGun) then
       
  3055                     begin
       
  3056                     CurrentHedgehog^.Gear^.Message:= CurrentHedgehog^.Gear^.Message and not gm_Switch;
       
  3057 
       
  3058                     flags:= Ammo^[CurSlot, CurAmmo].Timer and not 2;
       
  3059                     if (flags and 1) = 0 then
       
  3060                         Ammo^[CurSlot, CurAmmo].Timer:= flags or 1
       
  3061                     else
       
  3062                         Ammo^[CurSlot, CurAmmo].Timer:= flags and not 1;
       
  3063                     end;
       
  3064 end;
       
  3065 
  3047 procedure doStepPortal(Gear: PGear);
  3066 procedure doStepPortal(Gear: PGear);
  3048 var iterator, conPortal: PGear;
  3067 var iterator, conPortal: PGear;
  3049     s, acptRadius: hwFloat;
  3068     s, acptRadius, cdxy: hwFloat;
  3050     noTrap, hasdxy: Boolean;
  3069     noTrap, hasdxy: Boolean;
  3051 begin
  3070 begin
       
  3071     doPortalColorSwitch();
       
  3072 
  3052     // destroy portal if ground it was attached too is gone
  3073     // destroy portal if ground it was attached too is gone
  3053     if (Land[hwRound(Gear^.Y), hwRound(Gear^.X)] and $FF00) = 0 then deleteGear(Gear);
  3074     if ((Land[hwRound(Gear^.Y), hwRound(Gear^.X)] and $FF00) = 0)
       
  3075     or (Gear^.Timer < 1)
       
  3076     or (hwRound(Gear^.Y) > cWaterLine) then
       
  3077         begin
       
  3078         deleteGear(Gear);
       
  3079         EXIT;
       
  3080         end;
       
  3081 
       
  3082     if (TurnTimeLeft < 1)
       
  3083     or (Gear^.Health < 1) then
       
  3084         dec(Gear^.Timer);
       
  3085 
       
  3086     if Gear^.Timer < 10000 then
       
  3087         gear^.RenderTimer:= true;
  3054 
  3088 
  3055     // abort if there is no other portal connected to this one
  3089     // abort if there is no other portal connected to this one
  3056     if Gear^.IntersectGear = nil then
  3090     if (Gear^.IntersectGear = nil) then 
       
  3091         exit;
       
  3092     if ((Gear^.IntersectGear^.Tag and 1) = 0) then // or if it's still moving;
  3057         exit;
  3093         exit;
  3058 
  3094 
  3059     conPortal:= Gear^.IntersectGear;
  3095     conPortal:= Gear^.IntersectGear;
  3060 
  3096 
  3061     // check all gears for stuff to port through
  3097     // check all gears for stuff to port through
  3071         if iterator = nil then
  3107         if iterator = nil then
  3072             break; // end of list
  3108             break; // end of list
  3073 
  3109 
  3074         // don't port portals or other gear that wouldn't make sense
  3110         // don't port portals or other gear that wouldn't make sense
  3075         if (iterator^.Kind = gtPortal)
  3111         if (iterator^.Kind = gtPortal)
       
  3112         or (iterator^.Kind = gtRope)
  3076         or (iterator^.Kind = gtHealthTag) then
  3113         or (iterator^.Kind = gtHealthTag) then
  3077             continue;
  3114             continue;
  3078 
  3115         
  3079 {
  3116         // don't port hogs on rope
  3080         if (((iterator^.State and gstMoving) = 0) // we don't port non-moving stuff IF the portal entry...
  3117         if (CurrentHedgehog <> nil) and (CurrentHedgehog^.Gear <> nil)
  3081             and (iterator^.Active = false)
  3118             and (iterator = CurrentHedgehog^.Gear) and (CurAmmoGear <> nil) and (CurAmmoGear^.Kind = gtRope) then
  3082             and ) then //...
       
  3083                 continue;
  3119                 continue;
  3084 }
       
  3085 
  3120 
  3086         if (iterator^.Radius > Gear^.Radius) then
  3121         if (iterator^.Radius > Gear^.Radius) then
  3087             continue; // sorry, you're too fat!
  3122             continue; // sorry, you're too fat!
  3088 
  3123 
  3089         // this is the range we accept incoming gears in
  3124         // this is the range we accept incoming gears in
  3103         // wow! good candidate there, let's see if the distance really is small enough!
  3138         // wow! good candidate there, let's see if the distance really is small enough!
  3104         if (Distance(Gear^.X-iterator^.X,Gear^.Y-iterator^.Y) > acptRadius) then
  3139         if (Distance(Gear^.X-iterator^.X,Gear^.Y-iterator^.Y) > acptRadius) then
  3105             continue;
  3140             continue;
  3106 
  3141 
  3107         noTrap:= ((not Gear^.dY.isNegative or (Gear^.dY.QWordValue = 0)) // can't be entered from above
  3142         noTrap:= ((not Gear^.dY.isNegative or (Gear^.dY.QWordValue = 0)) // can't be entered from above
  3108             or ((conPortal^.dY.isNegative or (conPortal^.dY.QWordValue = 0)))); // can't be left downwards;
  3143             or ((conPortal^.dY.isNegative and not (conPortal^.dY.QWordValue = 0)))); // can't be left downwards; 
  3109  
  3144  
  3110  
  3145         // prevent getting stuck in a ground portal loop       
  3111         // lets see if this one is just stuck in a stuck-loop       
  3146         if noTrap and (iterator^.dY.QWordValue < _0_08.QWordValue) then
  3112         if noTrap and (iterator^.dY.QWordValue < _0_1.QWordValue) then
       
  3113             continue;
  3147             continue;
  3114         
  3148 
  3115         iterator^.Active:= true;
  3149         iterator^.Active:= true;
  3116         iterator^.State:= iterator^.State or gstMoving;
  3150         iterator^.State:= iterator^.State or gstMoving;
  3117         DeleteCI(iterator);
  3151         DeleteCI(iterator);
  3118 
  3152 
  3119         s:= (_1+(Int2hwFloat(Gear^.Radius))) / Distance(conPortal^.dX, conPortal^.dY);
  3153 // TODO: more accurate porting
       
  3154         cdxy:= Distance(conPortal^.dX, conPortal^.dY);
       
  3155         s:= (Int2hwFloat(Gear^.Radius)) / cdxy;
       
  3156 
  3120         iterator^.X:= conPortal^.X + s * conPortal^.dX;
  3157         iterator^.X:= conPortal^.X + s * conPortal^.dX;
  3121         iterator^.Y:= conPortal^.Y + s * conPortal^.dY;
  3158         iterator^.Y:= conPortal^.Y + s * conPortal^.dY;
  3122         s:= Distance(iterator^.dX, iterator^.dY) / Distance(conPortal^.dX, conPortal^.dY);
  3159 
       
  3160         s:= Distance(iterator^.dX, iterator^.dY) / cdxy;
       
  3161 
  3123         iterator^.dX:= s * conPortal^.dX;
  3162         iterator^.dX:= s * conPortal^.dX;
  3124         iterator^.dY:= s * conPortal^.dY;
  3163         iterator^.dY:= s * conPortal^.dY;
       
  3164 
       
  3165         FollowGear:= iterator;
       
  3166 
       
  3167         s:= _0_2 + _0_008 * Gear^.Health;
       
  3168         iterator^.dX:= s * iterator^.dX;
       
  3169         iterator^.dY:= s * iterator^.dY;
  3125         
  3170         
  3126         if iterator^.dY.isNegative and (iterator^.dY.QWordValue <> 0) then
  3171         if Gear^.Health > 1 then
  3127             iterator^.dY:= iterator^.dY + hwAbs(Int2hwFloat(iterator^.Radius) / iterator^.dY) * cGravity;
  3172             begin
       
  3173             dec(Gear^.Health);
       
  3174             dec(iterator^.Health);
       
  3175             end;
  3128 
  3176 
  3129         // breaks (some) loops
  3177         // breaks (some) loops
  3130         if Distance(iterator^.dX, iterator^.dY) > _0_96 then
  3178         if Distance(iterator^.dX, iterator^.dY) > _0_96 then
  3131             begin
  3179             begin
  3132             iterator^.dX:= iterator^.dX + signAs(cGravity * getRandom(1000),iterator^.dX);
  3180             iterator^.dX:= iterator^.dX + signAs(cGravity * getRandom(1000),iterator^.dX);
  3133             iterator^.dY:= iterator^.dY + signAs(cGravity * getRandom(1000),iterator^.dY);
  3181             iterator^.dY:= iterator^.dY + signAs(cGravity * getRandom(1000),iterator^.dY);
  3134             s:= _0_995 / Distance(iterator^.dX, iterator^.dY);
  3182             s:= _0_96 / Distance(iterator^.dX, iterator^.dY);
  3135             iterator^.dX:= s * iterator^.dX;
  3183             iterator^.dX:= s * iterator^.dX;
  3136             iterator^.dY:= s * iterator^.dX;
  3184             iterator^.dY:= s * iterator^.dX;
  3137             end;
  3185             end;
  3138 
       
  3139         iterator:= iterator^.NextGear;
       
  3140         end;
  3186         end;
  3141 end;
  3187 end;
  3142 
  3188 
  3143 procedure doStepMovingPortal(Gear: PGear);
  3189 procedure doStepMovingPortal(Gear: PGear);
  3144 var x, y, tx, ty: LongInt;//, bx, by, tangle: LongInt;
  3190 var x, y, tx, ty: LongInt;//, bx, by, tangle: LongInt;
  3145     s, dx, dy: hwFloat;
  3191     s, dx, dy: hwFloat;
  3146 begin
  3192 
       
  3193 procedure loadNewPortalBall(oldPortal: PGear; destroyGear: Boolean);
       
  3194 var flags: LongWord;
       
  3195 begin
       
  3196 if CurrentHedgehog <> nil then
       
  3197     With CurrentHedgehog^ do
       
  3198         if (Ammo^[CurSlot, CurAmmo].AmmoType = amPortalGun) then
       
  3199             begin
       
  3200             flags:= Ammo^[CurSlot, CurAmmo].Timer;
       
  3201 
       
  3202             if destroyGear xor ((oldPortal^.Tag and 2) = 0) then
       
  3203                 flags:= flags or 1
       
  3204             else
       
  3205                 flags:= flags and not 1;
       
  3206 
       
  3207             Ammo^[CurSlot, CurAmmo].Timer:= flags and not 2; // make the ball visible
       
  3208             end;
       
  3209 
       
  3210 if destroyGear then deleteGear(oldPortal);
       
  3211 end;
       
  3212 
       
  3213 begin
       
  3214 doPortalColorSwitch();
       
  3215 
  3147 Gear^.X:= Gear^.X + Gear^.dX;
  3216 Gear^.X:= Gear^.X + Gear^.dX;
  3148 Gear^.Y:= Gear^.Y + Gear^.dY;
  3217 Gear^.Y:= Gear^.Y + Gear^.dY;
  3149 x:= hwRound(Gear^.X);
  3218 x:= hwRound(Gear^.X);
  3150 y:= hwRound(Gear^.Y);
  3219 y:= hwRound(Gear^.Y);
  3151 tx:= 0; ty:= 0; // avoid compiler hints
  3220 tx:= 0; ty:= 0; // avoid compiler hints
  3152 
  3221 
  3153 if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] > 255) then
  3222 if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] > 255) then
  3154     begin
  3223     begin
  3155     if not calcSlopeTangent(Gear, x, y, tx, ty, 255) then
  3224     if not calcSlopeTangent(Gear, x, y, tx, ty, 255)
  3156         begin
  3225         or (DistanceI(tx,ty) < _12) then // reject shots at too irregular terrain
  3157         deleteGear(Gear);
  3226             begin
  3158         EXIT;
  3227             loadNewPortalBall(Gear, true);
  3159         end;
  3228             EXIT;
  3160 
  3229             end;
  3161     // reject shots at too irregular terrain
       
  3162     if DistanceI(tx,ty) < _12 then
       
  3163         begin
       
  3164         deleteGear(Gear);
       
  3165         EXIT;
       
  3166     end;
       
  3167     
  3230     
  3168     // making a normal, normalized vector
  3231     // making a normalized normal vector
  3169     s:= _1/DistanceI(tx,ty);
  3232     s:= _1/DistanceI(tx,ty);
  3170     dx:= -s * ty;
  3233     dx:= -s * ty;
  3171     dy:=  s * tx;
  3234     dy:=  s * tx;
  3172 
  3235 
  3173     // make sure the vector is pointing outwards
  3236     // make sure the vector is pointing outwards
  3174     if not (Gear^.dX*dx + Gear^.dY*dy).isNegative then
  3237     if not (Gear^.dX*dx + Gear^.dY*dy).isNegative then
  3175     begin
  3238         begin
  3176         dx:= -dx;
  3239         dx:= -dx;
  3177         dy:= -dy;
  3240         dy:= -dy;
  3178     end;
  3241         end;
  3179 
  3242 
  3180     Gear^.dX:= dx;
  3243     Gear^.dX:= dx;
  3181     Gear^.dY:= dy;
  3244     Gear^.dY:= dy;
  3182 
  3245 
  3183     Gear^.DirAngle:= DxDy2Angle(-dy,dx);
  3246     Gear^.DirAngle:= DxDy2Angle(-dy,dx);
  3184     if not Gear^.dX.isNegative then Gear^.DirAngle:= 180-Gear^.DirAngle;
  3247     if not Gear^.dX.isNegative then Gear^.DirAngle:= 180-Gear^.DirAngle;
  3185 
  3248 
  3186     if ((Gear^.IntersectGear <> nil) and (hwRound(Distance(Gear^.X - Gear^.IntersectGear^.X,Gear^.Y-Gear^.IntersectGear^.Y)) < Gear^.Radius*2)) 
  3249     if ((Gear^.IntersectGear = nil)
       
  3250     or (hwRound(Distance(Gear^.X - Gear^.IntersectGear^.X,Gear^.Y-Gear^.IntersectGear^.Y)) >= Gear^.Radius*2)) 
  3187     then
  3251     then
  3188         begin
  3252         begin
  3189         if CurrentHedgehog <> nil then
  3253         loadNewPortalBall(Gear, false);
  3190             if Gear^.IntersectGear = nil then CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 1
  3254         inc(Gear^.Tag);
  3191             else if Gear^.Tag = 2 then CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 2
  3255         Gear^.doStep:= @doStepPortal;
  3192             else CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 1;
       
  3193         deleteGear(Gear)
       
  3194         end
  3256         end
  3195     else
  3257     else
  3196         begin
  3258         loadNewPortalBall(Gear, true);
  3197         if CurrentHedgehog <> nil then
  3259     end
  3198             if Gear^.Tag = 2 then CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 1
  3260 else if (y > cWaterLine) or (y < -LAND_WIDTH)
  3199             else CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 2;
  3261      or (x > 2*LAND_WIDTH) or (x < -LAND_WIDTH) then
  3200         inc(Gear^.Tag);
  3262         loadNewPortalBall(Gear, true);
  3201         Gear^.doStep:= @doStepPortal;
  3263 end;
  3202         if Gear^.IntersectGear <> nil then Gear^.IntersectGear^.IntersectGear:= Gear;
  3264 
  3203         end
  3265 procedure doStepPortalShot(newPortal: PGear);
  3204     end
  3266 var iterator: PGear;
  3205 else if (y > cWaterLine + cVisibleWater + Gear^.Radius) or (y < -LAND_WIDTH) or (x > LAND_WIDTH + LAND_WIDTH) or (x < -LAND_WIDTH) then
  3267 begin
  3206     begin
  3268 newPortal^.IntersectGear:= nil;
  3207     if CurrentHedgehog <> nil then
  3269 
  3208         if Gear^.IntersectGear = nil then CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 1
  3270 if CurrentHedgehog <> nil then
  3209         else if Gear^.Tag = 2 then CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 2
  3271     With CurrentHedgehog^ do
  3210         else CurrentHedgehog^.Ammo^[CurrentHedgehog^.CurSlot, CurrentHedgehog^.CurAmmo].Timer:= 1;
  3272     begin
  3211     deleteGear(Gear);
  3273     // make portal gun look unloaded
  3212     end;
  3274     Ammo^[CurSlot, CurAmmo].Timer:= Ammo^[CurSlot, CurAmmo].Timer or 2;
       
  3275 
       
  3276     // set portal to the currently chosen color
       
  3277     if ((Ammo^[CurSlot, CurAmmo].Timer and 1) <> 0) then
       
  3278         newPortal^.Tag:= newPortal^.Tag or 2;
       
  3279 
       
  3280     iterator:= GearsList;
       
  3281     while iterator <> nil do
       
  3282         begin
       
  3283         if (iterator^.Kind = gtPortal) then
       
  3284             if (iterator <> newPortal) then
       
  3285                 begin
       
  3286                 if (iterator^.Tag and 2) = (newPortal^.Tag and 2) then
       
  3287                     begin
       
  3288                     iterator:= iterator^.PrevGear;
       
  3289                     deleteGear(iterator^.NextGear);
       
  3290                     continue;
       
  3291                     end
       
  3292                 else
       
  3293                     begin // link portals with each other
       
  3294                     newPortal^.IntersectGear:= iterator;
       
  3295                     iterator^.IntersectGear:= newPortal;
       
  3296                     iterator^.Health:= newPortal^.Health;
       
  3297                     end;
       
  3298                 end;
       
  3299         iterator:= iterator^.NextGear
       
  3300         end;
       
  3301     end;
       
  3302 newPortal^.doStep:= @doStepMovingPortal;
  3213 end;
  3303 end;
  3214 
  3304 
  3215 procedure doStepPiano(Gear: PGear);
  3305 procedure doStepPiano(Gear: PGear);
  3216 var r0, r1: LongInt;
  3306 var r0, r1: LongInt;
  3217 begin
  3307 begin