diff -r 475c0f2f9d17 -r 30f2d1037d5d hedgewars/uWorld.pas --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hedgewars/uWorld.pas Mon Aug 22 13:35:41 2005 +0000 @@ -0,0 +1,338 @@ +(* + * Hedgewars, a worms-like game + * Copyright (c) 2004, 2005 Andrey Korotaev + * + * Distributed under the terms of the BSD-modified licence: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * with the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *) + +unit uWorld; +interface +uses SDLh, uGears; +{$INCLUDE options.inc} +const WorldDx: integer = -512; + WorldDy: integer = -256; + +procedure InitWorld; +procedure DrawWorld(Lag: integer; Surface: PSDL_Surface); +procedure AddCaption(s: shortstring; Color, Group: LongWord); +procedure MoveWorld; +procedure AdjustMPoint; + +{$IFDEF COUNTTICKS} +var cntTicks: LongWord; +{$ENDIF} +var FollowGear: PGear = nil; + +implementation +uses uStore, uMisc, uConsts, uTeams, uIO; +const RealTicks: Longword = 0; + Frames: Longword = 0; + FPS: Longword = 0; + CountTicks: Longword = 0; + prevPoint: TPoint = (X: 0; Y: 0); + +type TCaptionStr = record + r: TSDL_Rect; + StorePos, + Group, + EndTime: LongWord; + end; + +var cWaterSprCount: integer; + Captions: array[0..Pred(cMaxCaptions)] of TCaptionStr; + +procedure InitWorld; +begin +cLandYShift:= cWaterLine + 64; +cWaterSprCount:= 1 + cScreenWidth div (SpritesData[sprWater].Width) +end; + +procedure DrawWorld(Lag: integer; Surface: PSDL_Surface); +var i, t: integer; + r: TSDL_Rect; + team: PTeam; +begin +// синее небо +inc(RealTicks, Lag); +r.h:= WorldDy; +if r.h > 0 then + begin + if r.h > cScreenHeight then r.h:= cScreenHeight; + r.x:= 0; + r.y:= 0; + r.w:= cScreenWidth; + SDL_FillRect(Surface, @r, cSkyColor) + end; +// задний фон +for i:= 0 to (cScreenWidth shr 6) do + DrawGear(sSky, i*64, WorldDy, Surface); + +for i:= -1 to 3 do // горизонт + DrawGear(sHorizont, i * 512 + (((WorldDx * 3) div 5) and $1FF), cWaterLine - 256 + WorldDy, Surface); + +// волны +{$WARNINGS OFF} +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); +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); +{$WARNINGS ON} + +// поле +DrawLand(WorldDx, WorldDy, Surface); +// вода +r.y:= WorldDy + cWaterLine + 32; +if r.y < cScreenHeight then + begin + r.h:= cScreenHeight - r.y; + r.x:= 0; + r.w:= cScreenWidth; + SDL_FillRect(Surface, @r, cWaterColor) + end; + +DrawGears(Surface); + +team:= TeamsList; +while team<>nil do + begin + for i:= 0 to 7 do + with team.Hedgehogs[i] do + if Gear<>nil then + if Gear.State = 0 then + begin // ёжик не находится под управлением + DrawCaption( round(Gear.X) + WorldDx, + round(Gear.Y) - cHHHalfHeight - 30 + WorldDy, + HealthRect, Surface, true); + DrawCaption( round(Gear.X) + WorldDx, + round(Gear.Y) - cHHHalfHeight - 54 + WorldDy, + NameRect, Surface); +// DrawCaption( round(Gear.X) + WorldDx, +// round(Gear.Y) - Gear.HalfHeight - 60 + WorldDy, +// Team.NameRect, Surface); + end else // ёжик, которым счас управляем + begin + if (Gear.State and (gstMoving or gstAttacked or gstDrowning or gstFalling))=0 then // рисуем прицел и, если бот думает, знак вопроса + if (Gear.State and gstHHThinking) <> 0 then + DrawGear(sQuestion, Round(Gear.X) - 10 + WorldDx, Round(Gear.Y) - cHHHalfHeight - 34 + WorldDy, Surface) + else + DrawCaption(Round(Gear.X + Sign(Gear.dX) * Sin(Gear.Angle*pi/cMaxAngle)*60) + WorldDx, + Round(Gear.Y - Cos(Gear.Angle*pi/cMaxAngle)*60) + WorldDy - 5, + Team.CrossHairRect, Surface) + end; + team:= team.Next + end; + +// волны +{$WARNINGS OFF} +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); +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); +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); +{$WARNINGS ON} + +if TurnTimeLeft <> 0 then + begin + i:= Succ(Pred(TurnTimeLeft) div 1000); + if i>99 then t:= 112 + else if i>9 then t:= 96 + else t:= 80; + DrawSprite(sprFrame, t, cScreenHeight - 48, 1, Surface); + while i > 0 do + begin + dec(t, 32); + DrawSprite(sprBigDigit, t, cScreenHeight - 48, i mod 10, Surface); + i:= i div 10 + end; + DrawSprite(sprFrame, t - 4, cScreenHeight - 48, 0, Surface); + end; +if CurrentTeam <> nil then + case AttackBar of + 1: begin + r:= StuffPoz[sPowerBar]; + {$WARNINGS OFF} + r.w:= (CurrentTeam.Hedgehogs[CurrentTeam.CurrHedgehog].Gear.Power * 256) div cPowerDivisor; + {$WARNINGS ON} + DrawSpriteFromRect(r, cScreenWidth - 272, cScreenHeight - 48, 16, 0, Surface); + end; + end; + +// Указатель на цель +if TargetPoint.X <> NoPointX then DrawSprite(sprTargetP, TargetPoint.X + WorldDx - 16, TargetPoint.Y + WorldDy - 16, 0, Surface); + +// Captions +i:= 0; +while (i < cMaxCaptions) do + begin + with Captions[i] do + if EndTime > 0 then DrawCaption(cScreenWidth div 2, 8 + i * 32 + cConsoleYAdd, r, Surface, true); + inc(i) + end; +while (Captions[0].EndTime > 0) and (Captions[0].EndTime <= RealTicks) do + begin + for i:= 1 to Pred(cMaxCaptions) do + Captions[Pred(i)]:= Captions[i]; + Captions[Pred(cMaxCaptions)].EndTime:= 0 + end; + +// Указание на лаг +if isInLag then DrawSprite(sprLag, 32, 32 + cConsoleYAdd, (RealTicks shr 7) mod 7, Surface); + +// Курсор +if isCursorVisible then DrawSprite(sprArrow, CursorPoint.X, CursorPoint.Y, (RealTicks shr 6) mod 8, Surface); + +{$IFDEF COUNTTICKS} +DXOutText(10, 10, fnt16, inttostr(cntTicks), Surface); +{$ENDIF} + +inc(Frames); +inc(CountTicks, Lag); +if CountTicks >= 1000 then + begin + FPS:= Frames; + Frames:= 0; + CountTicks:= 0; + end; +if cShowFPS then DXOutText(cScreenWidth - 50, 10, fnt16, inttostr(FPS) + ' fps', Surface) +end; + +procedure AddCaption(s: shortstring; Color, Group: LongWord); +var i, t, m, k: LongWord; +begin +i:= 0; +while (i < cMaxCaptions) and (Captions[i].Group <> Group)do inc(i); +if i < cMaxCaptions then + begin + while (i < Pred(cMaxCaptions)) do + begin + Captions[i]:= Captions[Succ(i)]; + inc(i) + end; + Captions[Pred(cMaxCaptions)].EndTime:= 0 + end; + +if Captions[Pred(cMaxCaptions)].EndTime > 0 then + begin + m:= Pred(cMaxCaptions); + for i:= 1 to m do + Captions[Pred(i)]:= Captions[i]; + Captions[m].EndTime:= 0 + end else + begin + m:= 0; + while (m < cMaxCaptions)and(Captions[m].EndTime > 0) do inc(m) + end; + +k:= 0; +for i:= 0 to Pred(cMaxCaptions) do + for t:= 0 to Pred(cMaxCaptions) do + if (Captions[t].EndTime > 0)and(Captions[t].StorePos = k) then inc(k); + +Captions[m].r:= RenderString(s, Color, k); +Captions[m].StorePos:= k; +Captions[m].Group:= Group; +Captions[m].EndTime:= RealTicks + 1200 +end; + +procedure MoveWorld; +const PrevSentPointTime: LongWord = 0; +var s: string[9]; +begin +if not (CurrentTeam.ExtDriven and isCursorVisible) then SDL_GetMouseState(@CursorPoint.X, @CursorPoint.Y); + +if (FollowGear <> nil) then + if abs(CursorPoint.X - prevPoint.X + CursorPoint.Y - prevpoint.Y) > 4 then + begin + FollowGear:= nil; + AdjustMPoint; + exit + end + else begin + CursorPoint.x:= (CursorPoint.x + (round(FollowGear.X + Sign(FollowGear.dX) * 100) + WorldDx)) div 2; + CursorPoint.y:= (CursorPoint.y + (round(FollowGear.Y) + WorldDy)) div 2 + end; + +if ((CursorPoint.X = prevPoint.X)and(CursorPoint.Y = prevpoint.Y)) then exit; + +if isCursorVisible then + begin + if (not CurrentTeam.ExtDriven)and(GameTicks >= PrevSentPointTime + cSendCursorPosTime) then + begin + s[0]:= #9; + s[1]:= 'P'; + PInteger(@s[2])^:= CursorPoint.X - WorldDx; + PInteger(@s[6])^:= CursorPoint.Y - WorldDy; + SendIPC(s); + PrevSentPointTime:= GameTicks + end; + end; +if isCursorVisible or (FollowGear <> nil) then + begin + if CursorPoint.X < cScreenEdgesDist then + begin + WorldDx:= WorldDx - CursorPoint.X + cScreenEdgesDist; + CursorPoint.X:= cScreenEdgesDist + end else + if CursorPoint.X > cScreenWidth - cScreenEdgesDist then + begin + WorldDx:= WorldDx - CursorPoint.X + cScreenWidth - cScreenEdgesDist; + CursorPoint.X:= cScreenWidth - cScreenEdgesDist + end; + if CursorPoint.Y < cScreenEdgesDist then + begin + WorldDy:= WorldDy - CursorPoint.Y + cScreenEdgesDist; + CursorPoint.Y:= cScreenEdgesDist + end else + if CursorPoint.Y > cScreenHeight - cScreenEdgesDist then + begin + WorldDy:= WorldDy - CursorPoint.Y + cScreenHeight - cScreenEdgesDist; + CursorPoint.Y:= cScreenHeight - cScreenEdgesDist + end; + end else + begin + WorldDx:= WorldDx - CursorPoint.X + (cScreenWidth shr 1); + WorldDy:= WorldDy - CursorPoint.Y + (cScreenHeight shr 1); + CursorPoint.X:= (cScreenWidth shr 1); + CursorPoint.Y:= (cScreenHeight shr 1); + end; +SDL_WarpMouse(CursorPoint.X, CursorPoint.Y); +prevPoint:= CursorPoint; +if WorldDy < cScreenHeight - cLandYShift - cVisibleWater then WorldDy:= cScreenHeight - cLandYShift - cVisibleWater; +if WorldDy > 2048 then WorldDy:= 2048; +if WorldDx < -2048 then WorldDx:= -2048; +if WorldDx > cScreenWidth then WorldDx:= cScreenWidth; +end; + +procedure AdjustMPoint; +begin +prevPoint.x:= cScreenWidth div 2; +prevPoint.y:= cScreenHeight div 2; +SDL_WarpMouse(prevPoint.X, prevPoint.Y); +end; + +initialization +FillChar(Captions, sizeof(Captions), 0) + +end.