DEADSOFTWARE

Player: Add sounds for CTF game
[d2df-sdl.git] / src / game / g_player.pas
index 355ecf323985108f69d23d047c3a34399fb77dcc..854d8119b44c4f0b4fe27b264e7dd273dece20bc 100644 (file)
@@ -95,6 +95,7 @@ const
   PLAYER_AP_SOFT  = 100;
   PLAYER_AP_LIMIT = 200;
   SUICIDE_DAMAGE  = 112;
+  WEAPON_DELAY    = 5;
 
   PLAYER1_DEF_COLOR: TRGB = (R:64; G:175; B:48);
   PLAYER2_DEF_COLOR: TRGB = (R:96; G:96; B:96);
@@ -231,6 +232,8 @@ type
 
     procedure doDamage (v: Integer);
 
+    function followCorpse(): Boolean;
+
   public
     FDamageBuffer:   Integer;
 
@@ -289,7 +292,7 @@ type
     procedure   BFGHit();
     function    GetFlag(Flag: Byte): Boolean;
     procedure   SetFlag(Flag: Byte);
-    function    DropFlag(): Boolean;
+    function    DropFlag(Silent: Boolean = True): Boolean;
     procedure   AllRulez(Health: Boolean);
     procedure   RestoreHealthArmor();
     procedure   FragCombo();
@@ -308,6 +311,7 @@ type
     procedure   DrawPickup();
     procedure   DrawRulez();
     procedure   DrawAim();
+    procedure   DrawIndicator();
     procedure   DrawBubble();
     procedure   DrawGUI();
     procedure   Update(); virtual;
@@ -463,7 +467,7 @@ type
 
   PGib = ^TGib;
   TGib = record
-    alive:     Boolean;
+    alive:    Boolean;
     ID:       DWORD;
     MaskID:   DWORD;
     RAngle:   Integer;
@@ -501,6 +505,7 @@ type
     FDamage:        Byte;
     FColor:         TRGB;
     FObj:           TObj;
+    FPlayerUID:     Word;
     FAnimation:     TAnimation;
     FAnimationMask: TAnimation;
 
@@ -539,6 +544,7 @@ var
   gFly: Boolean = False;
   gAimLine: Boolean = False;
   gChatBubble: Byte = 0;
+  gPlayerIndicator: Boolean = True;
   gNumBots: Word = 0;
   gLMSPID1: Word = 0;
   gLMSPID2: Word = 0;
@@ -1509,11 +1515,20 @@ end;
 
 procedure g_Player_CreateCorpse(Player: TPlayer);
 var
+  i: Integer;
   find_id: DWORD;
   ok: Boolean;
 begin
   if Player.alive then
     Exit;
+
+// Ðàçðûâàåì ñâÿçü ñ ïðåæíèì òðóïîì:
+  if gCorpses <> nil then
+    for i := 0 to High(gCorpses) do
+      if gCorpses[i] <> nil then
+        if gCorpses[i].FPlayerUID = Player.FUID then
+          gCorpses[i].FPlayerUID := 0;
+
   if Player.FObj.Y >= gMapInfo.Height+128 then
     Exit;
 
@@ -1539,6 +1554,7 @@ begin
         gCorpses[find_id].FColor := FModel.Color;
         gCorpses[find_id].FObj.Vel := FObj.Vel;
         gCorpses[find_id].FObj.Accel := FObj.Accel;
+        gCorpses[find_id].FPlayerUID := FUID;
       end
     else
       g_Player_CreateGibs(FObj.X + PLAYER_RECT_CX,
@@ -1598,11 +1614,13 @@ procedure g_Player_CreateGibs(fX, fY: Integer; ModelName: string; fColor: TRGB);
 var
   a: Integer;
   GibsArray: TGibsArray;
+  Blood: TModelBlood;
 begin
   if (gGibs = nil) or (Length(gGibs) = 0) then
     Exit;
   if not g_PlayerModel_GetGibs(ModelName, GibsArray) then
     Exit;
+  Blood := g_PlayerModel_GetBlood(ModelName);
 
   for a := 0 to High(GibsArray) do
     with gGibs[CurrentGib] do
@@ -1621,7 +1639,7 @@ begin
 
       if gBloodCount > 0 then
         g_GFX_Blood(fX, fY, 16*gBloodCount+Random(5*gBloodCount), -16+Random(33), -16+Random(33),
-                    Random(48), Random(48), 150, 0, 0);
+                    Random(48), Random(48), Blood.R, Blood.G, Blood.B, Blood.Kind);
 
       if CurrentGib >= High(gGibs) then
         CurrentGib := 0
@@ -2258,6 +2276,25 @@ begin
   inherited;
 end;
 
+procedure TPlayer.DrawIndicator();
+var
+  indX, indY: Integer;
+  indW, indH: Word;
+  ID: DWORD;
+begin
+  if FAlive then
+    begin
+      indX := FObj.X+FObj.Rect.X;
+      indY := FObj.Y;
+      if g_Texture_Get('TEXTURE_PLAYER_INDICATOR', ID) then
+        begin
+          e_GetTextureSize(ID, @indW, @indH);
+          e_Draw(ID, indX + indW div 2, indY - indH, 0, True, False);
+        end;
+    end;
+  //e_TextureFontPrint(indX, indY, FName, gStdFont); // Shows player name overhead
+end;
+
 procedure TPlayer.DrawBubble();
 var
   bubX, bubY: Integer;
@@ -2354,8 +2391,15 @@ begin
       Mirror := TMirrorType.Horizontal;
 
     if FPunchAnim <> nil then
+    begin
       FPunchAnim.Draw(FObj.X+IfThen(Direction = TDirection.D_LEFT, 15-FObj.Rect.X, FObj.Rect.X-15),
                       FObj.Y+FObj.Rect.Y-11, Mirror);
+      if FPunchAnim.played then
+      begin
+        FPunchAnim.Free;
+        FPunchAnim := nil;
+      end;
+    end;
 
     if (FMegaRulez[MR_INVUL] > gTime) and (gPlayerDrawn <> Self) then
       if g_Texture_Get('TEXTURE_PLAYER_INVULPENTA', ID) then
@@ -2400,7 +2444,9 @@ begin
   end;
 
   if (gChatBubble > 0) and (FKeys[KEY_CHAT].Pressed) and not FGhost then
-    DrawBubble();
+    if (FMegaRulez[MR_INVIS] <= gTime) or ((gPlayerDrawn <> nil) and ((Self = gPlayerDrawn) or
+       ((FTeam = gPlayerDrawn.Team) and (gGameSettings.GameMode <> GM_DM)))) then
+      DrawBubble();
  // e_DrawPoint(5, 335, 288, 255, 0, 0); // DL, UR, DL, UR
   if gAimLine and alive and
   ((Self = gPlayer1) or (Self = gPlayer2)) then
@@ -2797,12 +2843,22 @@ end;
 procedure TPlayer.DoPunch();
 var
   id: DWORD;
+  st: String;
 begin
-  if FPunchAnim = nil then begin
-    g_Frames_Get(id, 'FRAMES_PUNCH');
-    FPunchAnim := TAnimation.Create(id, False, 1);
-  end else
+  if FPunchAnim <> nil then begin
     FPunchAnim.reset();
+    FPunchAnim.Free;
+    FPunchAnim := nil;
+  end;
+  st := 'FRAMES_PUNCH';
+  if R_BERSERK in FRulez then
+    st := st + '_BERSERK';
+  if FKeys[KEY_UP].Pressed then
+    st := st + '_UP'
+  else if FKeys[KEY_DOWN].Pressed then
+    st := st + '_DN';
+  g_Frames_Get(id, st);
+  FPunchAnim := TAnimation.Create(id, False, 1);
 end;
 
 procedure TPlayer.Fire();
@@ -2834,6 +2890,7 @@ begin
   case FCurrWeap of
     WEAPON_KASTET:
     begin
+      DoPunch();
       if R_BERSERK in FRulez then
       begin
         //g_Weapon_punch(FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y, 75, FUID);
@@ -2848,8 +2905,6 @@ begin
         locobj.Accel.X := xd-wx;
         locobj.Accel.y := yd-wy;
 
-        DoPunch();
-
         if g_Weapon_Hit(@locobj, 50, FUID, HIT_SOME) <> 0 then
           g_Sound_PlayExAt('SOUND_WEAPON_HITBERSERK', FObj.X, FObj.Y)
         else
@@ -3348,7 +3403,7 @@ begin
     end;
 
 // Âûáðîñ ôëàãà:
-    DropFlag();
+    DropFlag(KillType = K_FALLKILL);
   end;
 
   g_Player_CreateCorpse(Self);
@@ -3489,11 +3544,11 @@ begin
   g_GFX_Blood(FObj.X+PLAYER_RECT.X+(PLAYER_RECT.Width div 2)+8,
               FObj.Y+PLAYER_RECT.Y+(PLAYER_RECT.Height div 2),
               Count div 2, 3, -1, 16, (PLAYER_RECT.Height*2 div 3),
-              150, 0, 0);
+              FModel.Blood.R, FModel.Blood.G, FModel.Blood.B, FModel.Blood.Kind);
   g_GFX_Blood(FObj.X+PLAYER_RECT.X+(PLAYER_RECT.Width div 2)-8,
               FObj.Y+PLAYER_RECT.Y+(PLAYER_RECT.Height div 2),
               Count div 2, -3, -1, 16, (PLAYER_RECT.Height*2) div 3,
-              150, 0, 0);
+              FModel.Blood.R, FModel.Blood.G, FModel.Blood.B, FModel.Blood.Kind);
 end;
 
 procedure TPlayer.MakeBloodVector(Count: Word; VelX, VelY: Integer);
@@ -3501,7 +3556,7 @@ begin
   g_GFX_Blood(FObj.X+PLAYER_RECT.X+(PLAYER_RECT.Width div 2),
               FObj.Y+PLAYER_RECT.Y+(PLAYER_RECT.Height div 2),
               Count, VelX, VelY, 16, (PLAYER_RECT.Height*2) div 3,
-              150, 0, 0);
+              FModel.Blood.R, FModel.Blood.G, FModel.Blood.B, FModel.Blood.Kind);
 end;
 
 procedure TPlayer.QueueWeaponSwitch(Weapon: Byte);
@@ -3564,7 +3619,7 @@ begin
       begin
         //e_WriteLog(Format(' SWITCH: cur=%d; new=%d', [FCurrWeap, cwi]), MSG_WARNING);
         result := Byte(cwi);
-        FNextWeapDelay := 10;
+        FNextWeapDelay := WEAPON_DELAY;
         exit;
       end;
     end;
@@ -3609,7 +3664,7 @@ begin
       // i found her!
       result := Byte(i);
       resetWeaponQueue();
-      FNextWeapDelay := 10; // anyway, 'cause why not
+      FNextWeapDelay := WEAPON_DELAY; // anyway, 'cause why not
       exit;
     end;
   end;
@@ -3643,7 +3698,7 @@ begin
   if not switchAllowed then
   begin
     //HACK for weapon cycling
-    if (FNextWeap and $7000) <> 0 then FNextWeap := 0;
+    if (FNextWeap and $E000) <> 0 then FNextWeap := 0;
     exit;
   end;
 
@@ -4750,6 +4805,30 @@ begin
     Result := 1;
 end;
 
+function TPlayer.followCorpse(): Boolean;
+var
+  i: Integer;
+begin
+  Result := False;
+  if FAlive or FSpectator then
+    Exit;
+  if (gCorpses = nil) or (Length(gCorpses) = 0) then
+    Exit;
+  for i := 0 to High(gCorpses) do
+    if gCorpses[i] <> nil then
+      if gCorpses[i].FPlayerUID = FUID then
+      begin
+        Result := True;
+        FObj.X := gCorpses[i].FObj.X;
+        FObj.Y := gCorpses[i].FObj.Y;
+        FObj.Vel.X := gCorpses[i].FObj.Vel.X;
+        FObj.Vel.Y := gCorpses[i].FObj.Vel.Y;
+        FObj.Accel.X := gCorpses[i].FObj.Accel.X;
+        FObj.Accel.Y := gCorpses[i].FObj.Accel.Y;
+        break;
+      end;
+end;
+
 procedure TPlayer.Update();
 var
   b: Byte;
@@ -4826,7 +4905,8 @@ begin
 
     if FPhysics then
     begin
-      g_Obj_Move(@FObj, True, True, True);
+      if not followCorpse() then
+        g_Obj_Move(@FObj, True, True, True);
       positionChanged(); // this updates spatial accelerators
     end;
 
@@ -4952,7 +5032,8 @@ begin
 
   if FPhysics then
   begin
-    g_Obj_Move(@FObj, True, True, True);
+    if not followCorpse() then
+      g_Obj_Move(@FObj, True, True, True);
     positionChanged(); // this updates spatial accelerators
   end
   else
@@ -5296,6 +5377,7 @@ begin
   case FCurrWeap of
     WEAPON_KASTET:
     begin
+      DoPunch();
       if R_BERSERK in FRulez then
       begin
         //g_Weapon_punch(FObj.X+FObj.Rect.X, FObj.Y+FObj.Rect.Y, 75, FUID);
@@ -5310,8 +5392,6 @@ begin
         locobj.Accel.X := xd-wx;
         locobj.Accel.y := yd-wy;
 
-        DoPunch();
-
         if g_Weapon_Hit(@locobj, 50, FUID, HIT_SOME) <> 0 then
           g_Sound_PlayExAt('SOUND_WEAPON_HITBERSERK', FObj.X, FObj.Y)
         else
@@ -5466,7 +5546,7 @@ end;
 function TPlayer.GetFlag(Flag: Byte): Boolean;
 var
   s, ts: String;
-  evtype: Byte;
+  evtype, a: Byte;
 begin
   Result := False;
 
@@ -5494,6 +5574,16 @@ begin
     g_Map_ResetFlag(FFlag);
     g_Game_Message(Format(_lc[I_MESSAGE_FLAG_CAPTURE], [AnsiUpperCase(s)]), 144);
 
+    if ((Self = gPlayer1) or (Self = gPlayer2)
+    or ((gPlayer1 <> nil) and (gPlayer1.Team = FTeam))
+    or ((gPlayer2 <> nil) and (gPlayer2.Team = FTeam))) then
+      a := 0
+    else
+      a := 1;
+
+    if not sound_cap_flag[a].IsPlaying() then
+      sound_cap_flag[a].Play();
+
     gTeamStat[FTeam].Goals := gTeamStat[FTeam].Goals + 1;
 
     Result := True;
@@ -5525,6 +5615,16 @@ begin
     g_Map_ResetFlag(Flag);
     g_Game_Message(Format(_lc[I_MESSAGE_FLAG_RETURN], [AnsiUpperCase(s)]), 144);
 
+    if ((Self = gPlayer1) or (Self = gPlayer2)
+    or ((gPlayer1 <> nil) and (gPlayer1.Team = FTeam))
+    or ((gPlayer2 <> nil) and (gPlayer2.Team = FTeam))) then
+      a := 0
+    else
+      a := 1;
+
+    if not sound_ret_flag[a].IsPlaying() then
+      sound_ret_flag[a].Play();
+
     Result := True;
     if g_Game_IsNet then
     begin
@@ -5552,6 +5652,16 @@ begin
 
     gFlags[Flag].State := FLAG_STATE_CAPTURED;
 
+    if ((Self = gPlayer1) or (Self = gPlayer2)
+    or ((gPlayer1 <> nil) and (gPlayer1.Team = FTeam))
+    or ((gPlayer2 <> nil) and (gPlayer2.Team = FTeam))) then
+      a := 0
+    else
+      a := 1;
+
+    if not sound_get_flag[a].IsPlaying() then
+      sound_get_flag[a].Play();
+
     Result := True;
     if g_Game_IsNet then
     begin
@@ -5568,9 +5678,10 @@ begin
     FModel.SetFlag(FFlag);
 end;
 
-function TPlayer.DropFlag(): Boolean;
+function TPlayer.DropFlag(Silent: Boolean = True): Boolean;
 var
   s: String;
+  a: Byte;
 begin
   Result := False;
   if (not g_Game_IsServer) or (FFlag = FLAG_NONE) then
@@ -5595,6 +5706,16 @@ begin
     g_Console_Add(Format(_lc[I_PLAYER_FLAG_DROP], [FName, s]), True);
     g_Game_Message(Format(_lc[I_MESSAGE_FLAG_DROP], [AnsiUpperCase(s)]), 144);
 
+    if ((Self = gPlayer1) or (Self = gPlayer2)
+    or ((gPlayer1 <> nil) and (gPlayer1.Team = FTeam))
+    or ((gPlayer2 <> nil) and (gPlayer2.Team = FTeam))) then
+      a := 0
+    else
+      a := 1;
+
+    if (not Silent) and (not sound_lost_flag[a].IsPlaying()) then
+      sound_lost_flag[a].Play();
+
     if g_Game_IsNet then
       MH_SEND_FlagEvent(FLAG_STATE_DROPPED, Flag, FUID, False);
   end;
@@ -6198,6 +6319,7 @@ end;
 procedure TCorpse.Damage(Value: Word; vx, vy: Integer);
 var
   pm: TPlayerModel;
+  Blood: TModelBlood;
 begin
   if FState = CORPSE_STATE_REMOVEME then
     Exit;
@@ -6220,16 +6342,23 @@ begin
         pm := g_PlayerModel_Get(FModelName);
         pm.PlaySound(MODELSOUND_DIE, 5, FObj.X, FObj.Y);
         pm.Free;
+
+        // Çëîâåùèé ñìåõ:
+        if (gBodyKillEvent <> -1)
+        and gDelayedEvents[gBodyKillEvent].Pending then
+          gDelayedEvents[gBodyKillEvent].Pending := False;
+        gBodyKillEvent := g_Game_DelayEvent(DE_BODYKILL, 1050, 0);
       end;
     end
   else
     begin
+      Blood := g_PlayerModel_GetBlood(FModelName);
       FObj.Vel.X := FObj.Vel.X + vx;
       FObj.Vel.Y := FObj.Vel.Y + vy;
       g_GFX_Blood(FObj.X+PLAYER_CORPSERECT.X+(PLAYER_CORPSERECT.Width div 2),
                   FObj.Y+PLAYER_CORPSERECT.Y+(PLAYER_CORPSERECT.Height div 2),
                   Value, vx, vy, 16, (PLAYER_CORPSERECT.Height*2) div 3,
-                  150, 0, 0);
+                  Blood.R, Blood.G, Blood.B, Blood.Kind);
     end;
 end;
 
@@ -6303,6 +6432,7 @@ begin
   utils.writeInt(st, Byte(FColor.B));
   // Îáúåêò òðóïà
   Obj_SaveState(st, @FObj);
+  utils.writeInt(st, Word(FPlayerUID));
   // Åñòü ëè àíèìàöèÿ
   anim := (FAnimation <> nil);
   utils.writeBool(st, anim);
@@ -6335,6 +6465,7 @@ begin
   FColor.B := utils.readByte(st);
   // Îáúåêò òðóïà
   Obj_LoadState(@FObj, st);
+  FPlayerUID := utils.readWord(st);
   // Åñòü ëè àíèìàöèÿ
   anim := utils.readBool(st);
   // Åñëè åñòü - çàãðóæàåì