|
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. |