hedgewars/uWorld.pas
changeset 1 30f2d1037d5d
child 4 bcbd7adb4e4b
equal deleted inserted replaced
0:475c0f2f9d17 1:30f2d1037d5d
       
     1 (*
       
     2  * Hedgewars, a worms-like game
       
     3  * Copyright (c) 2004, 2005 Andrey Korotaev <unC0Rr@gmail.com>
       
     4  *
       
     5  * Distributed under the terms of the BSD-modified licence:
       
     6  *
       
     7  * Permission is hereby granted, free of charge, to any person obtaining a copy
       
     8  * of this software and associated documentation files (the "Software"), to deal
       
     9  * with the Software without restriction, including without limitation the
       
    10  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
       
    11  * sell copies of the Software, and to permit persons to whom the Software is
       
    12  * furnished to do so, subject to the following conditions:
       
    13  *
       
    14  * 1. Redistributions of source code must retain the above copyright notice,
       
    15  *    this list of conditions and the following disclaimer.
       
    16  * 2. Redistributions in binary form must reproduce the above copyright notice,
       
    17  *    this list of conditions and the following disclaimer in the documentation
       
    18  *    and/or other materials provided with the distribution.
       
    19  * 3. The name of the author may not be used to endorse or promote products
       
    20  *    derived from this software without specific prior written permission.
       
    21  *
       
    22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
       
    23  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
       
    24  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
       
    25  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
       
    26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
       
    27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
       
    28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
       
    29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
       
    30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
       
    31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    32  *)
       
    33 
       
    34 unit uWorld;
       
    35 interface
       
    36 uses SDLh, uGears;
       
    37 {$INCLUDE options.inc}
       
    38 const WorldDx: integer = -512;
       
    39       WorldDy: integer = -256;
       
    40 
       
    41 procedure InitWorld;
       
    42 procedure DrawWorld(Lag: integer; Surface: PSDL_Surface);
       
    43 procedure AddCaption(s: shortstring; Color, Group: LongWord);
       
    44 procedure MoveWorld;
       
    45 procedure AdjustMPoint;
       
    46 
       
    47 {$IFDEF COUNTTICKS}
       
    48 var cntTicks: LongWord;
       
    49 {$ENDIF}
       
    50 var FollowGear: PGear = nil;
       
    51 
       
    52 implementation
       
    53 uses uStore, uMisc, uConsts, uTeams, uIO;
       
    54 const RealTicks: Longword = 0;
       
    55       Frames: Longword = 0;
       
    56       FPS: Longword = 0;
       
    57       CountTicks: Longword = 0;
       
    58       prevPoint: TPoint = (X: 0; Y: 0);
       
    59       
       
    60 type TCaptionStr = record
       
    61                    r: TSDL_Rect;
       
    62                    StorePos,
       
    63                    Group,
       
    64                    EndTime: LongWord;
       
    65                    end;
       
    66 
       
    67 var cWaterSprCount: integer;
       
    68     Captions: array[0..Pred(cMaxCaptions)] of TCaptionStr;
       
    69 
       
    70 procedure InitWorld;
       
    71 begin
       
    72 cLandYShift:= cWaterLine + 64;
       
    73 cWaterSprCount:= 1 + cScreenWidth div (SpritesData[sprWater].Width)
       
    74 end;
       
    75 
       
    76 procedure DrawWorld(Lag: integer; Surface: PSDL_Surface);
       
    77 var i, t: integer;
       
    78     r: TSDL_Rect;
       
    79     team: PTeam;
       
    80 begin
       
    81 // синее небо
       
    82 inc(RealTicks, Lag);
       
    83 r.h:= WorldDy;
       
    84 if r.h > 0 then
       
    85    begin
       
    86    if r.h > cScreenHeight then r.h:= cScreenHeight;
       
    87    r.x:= 0;
       
    88    r.y:= 0;
       
    89    r.w:= cScreenWidth;
       
    90    SDL_FillRect(Surface, @r, cSkyColor)
       
    91    end;
       
    92 // задний фон
       
    93 for i:= 0 to (cScreenWidth shr 6) do
       
    94     DrawGear(sSky, i*64, WorldDy, Surface);
       
    95 
       
    96 for i:= -1 to 3 do // горизонт
       
    97     DrawGear(sHorizont, i * 512 + (((WorldDx * 3) div 5) and $1FF), cWaterLine - 256 + WorldDy, Surface);
       
    98 
       
    99 // волны
       
   100 {$WARNINGS OFF}
       
   101 for i:= -1 to cWaterSprCount do DrawSprite(sprWater,  i * 256  + ((WorldDx + (RealTicks shr 6)      ) and $FF), cWaterLine + WorldDy - 40, (((GameTicks shr 7) + 2) mod 12), Surface);
       
   102 for i:= -1 to cWaterSprCount do DrawSprite(sprWater,  i * 256  + ((WorldDx - (RealTicks shr 6) + 192) and $FF), cWaterLine + WorldDy - 30, (((GameTicks shr 7) + 8) mod 12), Surface);
       
   103 {$WARNINGS ON}
       
   104 
       
   105 // поле
       
   106 DrawLand(WorldDx, WorldDy, Surface);
       
   107 // вода
       
   108 r.y:= WorldDy + cWaterLine + 32;
       
   109 if r.y < cScreenHeight then
       
   110    begin
       
   111    r.h:= cScreenHeight - r.y;
       
   112    r.x:= 0;
       
   113    r.w:= cScreenWidth;
       
   114    SDL_FillRect(Surface, @r, cWaterColor)
       
   115    end;
       
   116 
       
   117 DrawGears(Surface);
       
   118 
       
   119 team:= TeamsList;
       
   120 while team<>nil do
       
   121       begin
       
   122       for i:= 0 to 7 do
       
   123           with team.Hedgehogs[i] do
       
   124                if Gear<>nil then
       
   125                   if Gear.State = 0 then
       
   126                      begin // ёжик не находится под управлением
       
   127                      DrawCaption( round(Gear.X) + WorldDx,
       
   128                                   round(Gear.Y) - cHHHalfHeight - 30 + WorldDy,
       
   129                                   HealthRect, Surface, true);
       
   130                      DrawCaption( round(Gear.X) + WorldDx,
       
   131                                   round(Gear.Y) - cHHHalfHeight - 54 + WorldDy,
       
   132                                   NameRect, Surface);
       
   133 //                     DrawCaption( round(Gear.X) + WorldDx,
       
   134 //                                  round(Gear.Y) - Gear.HalfHeight - 60 + WorldDy,
       
   135 //                                  Team.NameRect, Surface);
       
   136                      end else // ёжик, которым счас управляем
       
   137                      begin
       
   138                      if (Gear.State and (gstMoving or gstAttacked or gstDrowning or gstFalling))=0 then // рисуем прицел и, если бот думает, знак вопроса
       
   139                         if (Gear.State and gstHHThinking) <> 0 then
       
   140                            DrawGear(sQuestion, Round(Gear.X)  - 10 + WorldDx, Round(Gear.Y) - cHHHalfHeight - 34 + WorldDy, Surface)
       
   141                         else
       
   142                            DrawCaption(Round(Gear.X + Sign(Gear.dX) * Sin(Gear.Angle*pi/cMaxAngle)*60) + WorldDx,
       
   143                                        Round(Gear.Y - Cos(Gear.Angle*pi/cMaxAngle)*60) + WorldDy - 5,
       
   144                                        Team.CrossHairRect, Surface)
       
   145                      end;
       
   146       team:= team.Next
       
   147       end;
       
   148 
       
   149 // волны
       
   150 {$WARNINGS OFF}
       
   151 for i:= -1 to cWaterSprCount do DrawSprite(sprWater,  i * 256  + ((WorldDx + (RealTicks shr 6) +  64) and $FF), cWaterLine + WorldDy - 20, (((GameTicks shr 7) + 4 ) mod 12), Surface);
       
   152 for i:= -1 to cWaterSprCount do DrawSprite(sprWater,  i * 256  + ((WorldDx - (RealTicks shr 6) + 128) and $FF), cWaterLine + WorldDy - 10, (((GameTicks shr 7) + 10) mod 12), Surface);
       
   153 for i:= -1 to cWaterSprCount do DrawSprite(sprWater,  i * 256  + ((WorldDx + (RealTicks shr 6)      ) and $FF), cWaterLine + WorldDy     , (((GameTicks shr 7) + 6 ) mod 12), Surface);
       
   154 {$WARNINGS ON}
       
   155 
       
   156 if TurnTimeLeft <> 0 then
       
   157    begin
       
   158    i:= Succ(Pred(TurnTimeLeft) div 1000);
       
   159    if i>99 then t:= 112
       
   160       else if i>9 then t:= 96
       
   161                   else t:= 80;
       
   162    DrawSprite(sprFrame, t, cScreenHeight - 48, 1, Surface);
       
   163    while i > 0 do
       
   164          begin
       
   165          dec(t, 32);
       
   166          DrawSprite(sprBigDigit, t, cScreenHeight - 48, i mod 10, Surface);
       
   167          i:= i div 10
       
   168          end;
       
   169    DrawSprite(sprFrame, t - 4, cScreenHeight - 48, 0, Surface);
       
   170    end;
       
   171 if CurrentTeam <> nil then
       
   172    case AttackBar of
       
   173         1: begin
       
   174            r:= StuffPoz[sPowerBar];
       
   175            {$WARNINGS OFF}
       
   176            r.w:= (CurrentTeam.Hedgehogs[CurrentTeam.CurrHedgehog].Gear.Power * 256) div cPowerDivisor;
       
   177            {$WARNINGS ON}
       
   178            DrawSpriteFromRect(r, cScreenWidth - 272, cScreenHeight - 48, 16, 0, Surface);
       
   179            end;
       
   180         end;
       
   181 
       
   182 // Указатель на цель
       
   183 if TargetPoint.X <> NoPointX then DrawSprite(sprTargetP, TargetPoint.X + WorldDx - 16, TargetPoint.Y + WorldDy - 16, 0, Surface);
       
   184 
       
   185 // Captions
       
   186 i:= 0;
       
   187 while (i < cMaxCaptions) do
       
   188     begin
       
   189     with Captions[i] do
       
   190          if EndTime > 0 then DrawCaption(cScreenWidth div 2, 8 + i * 32 + cConsoleYAdd, r, Surface, true);
       
   191     inc(i)
       
   192     end;
       
   193 while (Captions[0].EndTime > 0) and (Captions[0].EndTime <= RealTicks) do
       
   194     begin
       
   195     for i:= 1 to Pred(cMaxCaptions) do
       
   196         Captions[Pred(i)]:= Captions[i];
       
   197     Captions[Pred(cMaxCaptions)].EndTime:= 0
       
   198     end;
       
   199 
       
   200 // Указание на лаг
       
   201 if isInLag then DrawSprite(sprLag, 32, 32  + cConsoleYAdd, (RealTicks shr 7) mod 7, Surface);
       
   202 
       
   203 // Курсор
       
   204 if isCursorVisible then DrawSprite(sprArrow, CursorPoint.X, CursorPoint.Y, (RealTicks shr 6) mod 8, Surface);
       
   205 
       
   206 {$IFDEF COUNTTICKS}
       
   207 DXOutText(10, 10, fnt16, inttostr(cntTicks), Surface);
       
   208 {$ENDIF}
       
   209 
       
   210 inc(Frames);
       
   211 inc(CountTicks, Lag);
       
   212 if CountTicks >= 1000 then
       
   213    begin
       
   214    FPS:= Frames;
       
   215    Frames:= 0;
       
   216    CountTicks:= 0;
       
   217    end;
       
   218 if cShowFPS then DXOutText(cScreenWidth - 50, 10, fnt16, inttostr(FPS) + ' fps', Surface)
       
   219 end;
       
   220 
       
   221 procedure AddCaption(s: shortstring; Color, Group: LongWord);
       
   222 var i, t, m, k: LongWord;
       
   223 begin
       
   224 i:= 0;
       
   225 while (i < cMaxCaptions) and (Captions[i].Group <> Group)do inc(i);
       
   226 if i < cMaxCaptions then
       
   227    begin
       
   228    while (i < Pred(cMaxCaptions)) do
       
   229          begin
       
   230          Captions[i]:= Captions[Succ(i)];
       
   231          inc(i)
       
   232          end;
       
   233    Captions[Pred(cMaxCaptions)].EndTime:= 0
       
   234    end;
       
   235    
       
   236 if Captions[Pred(cMaxCaptions)].EndTime > 0 then
       
   237    begin
       
   238    m:= Pred(cMaxCaptions);
       
   239    for i:= 1 to m do
       
   240        Captions[Pred(i)]:= Captions[i];
       
   241    Captions[m].EndTime:= 0
       
   242    end else
       
   243    begin
       
   244    m:= 0;
       
   245    while (m < cMaxCaptions)and(Captions[m].EndTime > 0) do inc(m)
       
   246    end;
       
   247 
       
   248 k:= 0;
       
   249 for i:= 0 to Pred(cMaxCaptions) do
       
   250     for t:= 0 to Pred(cMaxCaptions) do
       
   251         if (Captions[t].EndTime > 0)and(Captions[t].StorePos = k) then inc(k);
       
   252 
       
   253 Captions[m].r:= RenderString(s, Color, k);
       
   254 Captions[m].StorePos:= k;
       
   255 Captions[m].Group:= Group;
       
   256 Captions[m].EndTime:= RealTicks + 1200
       
   257 end;
       
   258 
       
   259 procedure MoveWorld;
       
   260 const PrevSentPointTime: LongWord = 0;
       
   261 var s: string[9];
       
   262 begin
       
   263 if not (CurrentTeam.ExtDriven and isCursorVisible) then SDL_GetMouseState(@CursorPoint.X, @CursorPoint.Y);
       
   264 
       
   265 if (FollowGear <> nil) then
       
   266    if abs(CursorPoint.X - prevPoint.X + CursorPoint.Y - prevpoint.Y) > 4 then
       
   267       begin
       
   268       FollowGear:= nil;
       
   269       AdjustMPoint;
       
   270       exit
       
   271       end
       
   272       else begin
       
   273       CursorPoint.x:= (CursorPoint.x + (round(FollowGear.X + Sign(FollowGear.dX) * 100) + WorldDx)) div 2;
       
   274       CursorPoint.y:= (CursorPoint.y + (round(FollowGear.Y) + WorldDy)) div 2
       
   275       end;
       
   276 
       
   277 if ((CursorPoint.X = prevPoint.X)and(CursorPoint.Y = prevpoint.Y)) then exit;
       
   278 
       
   279 if isCursorVisible then
       
   280    begin
       
   281    if (not CurrentTeam.ExtDriven)and(GameTicks >= PrevSentPointTime + cSendCursorPosTime) then
       
   282       begin
       
   283       s[0]:= #9;
       
   284       s[1]:= 'P';
       
   285       PInteger(@s[2])^:= CursorPoint.X - WorldDx;
       
   286       PInteger(@s[6])^:= CursorPoint.Y - WorldDy;
       
   287       SendIPC(s);
       
   288       PrevSentPointTime:= GameTicks
       
   289       end;
       
   290    end;
       
   291 if isCursorVisible or (FollowGear <> nil) then
       
   292    begin
       
   293    if CursorPoint.X < cScreenEdgesDist then
       
   294          begin
       
   295          WorldDx:= WorldDx - CursorPoint.X + cScreenEdgesDist;
       
   296          CursorPoint.X:= cScreenEdgesDist
       
   297          end else
       
   298       if CursorPoint.X > cScreenWidth - cScreenEdgesDist then
       
   299          begin
       
   300          WorldDx:= WorldDx - CursorPoint.X + cScreenWidth - cScreenEdgesDist;
       
   301          CursorPoint.X:= cScreenWidth - cScreenEdgesDist
       
   302          end;
       
   303       if CursorPoint.Y < cScreenEdgesDist then
       
   304          begin
       
   305          WorldDy:= WorldDy - CursorPoint.Y + cScreenEdgesDist;
       
   306          CursorPoint.Y:= cScreenEdgesDist
       
   307          end else
       
   308       if CursorPoint.Y > cScreenHeight - cScreenEdgesDist then
       
   309          begin
       
   310          WorldDy:= WorldDy - CursorPoint.Y + cScreenHeight - cScreenEdgesDist;
       
   311          CursorPoint.Y:= cScreenHeight - cScreenEdgesDist
       
   312          end;
       
   313    end else
       
   314    begin
       
   315       WorldDx:= WorldDx - CursorPoint.X + (cScreenWidth  shr 1);
       
   316       WorldDy:= WorldDy - CursorPoint.Y + (cScreenHeight shr 1);
       
   317       CursorPoint.X:= (cScreenWidth  shr 1);
       
   318       CursorPoint.Y:= (cScreenHeight shr 1);
       
   319    end;
       
   320 SDL_WarpMouse(CursorPoint.X, CursorPoint.Y);
       
   321 prevPoint:= CursorPoint;
       
   322 if WorldDy < cScreenHeight - cLandYShift - cVisibleWater then WorldDy:= cScreenHeight - cLandYShift - cVisibleWater;
       
   323 if WorldDy >  2048 then WorldDy:=  2048;
       
   324 if WorldDx < -2048 then WorldDx:= -2048;
       
   325 if WorldDx > cScreenWidth then WorldDx:=  cScreenWidth;
       
   326 end;
       
   327 
       
   328 procedure AdjustMPoint;
       
   329 begin
       
   330 prevPoint.x:= cScreenWidth div 2;
       
   331 prevPoint.y:= cScreenHeight div 2;
       
   332 SDL_WarpMouse(prevPoint.X, prevPoint.Y);
       
   333 end;
       
   334 
       
   335 initialization
       
   336 FillChar(Captions, sizeof(Captions), 0)
       
   337 
       
   338 end.