DEADSOFTWARE

no more public `gMonsters`
[d2df-sdl.git] / src / game / g_basic.pas
1 (* Copyright (C) DooM 2D:Forever Developers
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *)
16 {$INCLUDE ../shared/a_modes.inc}
17 unit g_basic;
19 interface
21 uses
22 wadreader, g_phys;
24 const
25 GAME_VERSION = '0.667';
26 UID_GAME = 1;
27 UID_PLAYER = 2;
28 UID_MONSTER = 3;
29 UID_ITEM = 10;
30 UID_MAX_GAME = $10;
31 UID_MAX_PLAYER = $7FFF;
32 UID_MAX_MONSTER = $FFFF;
34 type
35 TDirection = (D_LEFT, D_RIGHT);
36 WArray = array of Word;
37 DWArray = array of DWORD;
38 String20 = String[20];
40 function g_CreateUID(UIDType: Byte): Word;
41 function g_GetUIDType(UID: Word): Byte;
42 function g_Collide(X1, Y1: Integer; Width1, Height1: Word;
43 X2, Y2: Integer; Width2, Height2: Word): Boolean;
44 function g_CollideLine(x1, y1, x2, y2, rX, rY: Integer; rWidth, rHeight: Word): Boolean;
45 function g_CollidePoint(X, Y, X2, Y2: Integer; Width, Height: Word): Boolean;
46 function g_CollideLevel(X, Y: Integer; Width, Height: Word): Boolean;
47 function g_CollideAround(X1, Y1: Integer; Width1, Height1: Word;
48 X2, Y2: Integer; Width2, Height2: Word): Boolean;
49 function g_CollidePlayer(X, Y: Integer; Width, Height: Word): Boolean;
50 function g_CollideMonster(X, Y: Integer; Width, Height: Word): Boolean;
51 function g_PatchLength(X1, Y1, X2, Y2: Integer): Word;
52 function g_TraceVector(X1, Y1, X2, Y2: Integer): Boolean;
53 function g_GetAcidHit(X, Y: Integer; Width, Height: Word): Byte;
54 function g_Look(a, b: PObj; d: TDirection): Boolean;
55 procedure IncMax(var A: Integer; B, Max: Integer); overload;
56 procedure IncMax(var A: Single; B, Max: Single); overload;
57 procedure IncMax(var A: Integer; Max: Integer); overload;
58 procedure IncMax(var A: Single; Max: Single); overload;
59 procedure IncMax(var A: Word; B, Max: Word); overload;
60 procedure IncMax(var A: Word; Max: Word); overload;
61 procedure IncMax(var A: SmallInt; B, Max: SmallInt); overload;
62 procedure IncMax(var A: SmallInt; Max: SmallInt); overload;
63 procedure DecMin(var A: Integer; B, Min: Integer); overload;
64 procedure DecMin(var A: Single; B, Min: Single); overload;
65 procedure DecMin(var A: Integer; Min: Integer); overload;
66 procedure DecMin(var A: Single; Min: Single); overload;
67 procedure DecMin(var A: Word; B, Min: Word); overload;
68 procedure DecMin(var A: Word; Min: Word); overload;
69 procedure DecMin(var A: Byte; B, Min: Byte); overload;
70 procedure DecMin(var A: Byte; Min: Byte); overload;
71 function Sign(A: Integer): ShortInt; overload;
72 function Sign(A: Single): ShortInt; overload;
73 function PointToRect(X, Y, X1, Y1: Integer; Width, Height: Word): Integer;
74 function GetAngle(baseX, baseY, pointX, PointY: Integer): SmallInt;
75 function GetAngle2(vx, vy: Integer): SmallInt;
76 function GetLines(Text: string; FontID: DWORD; MaxWidth: Word): SArray;
77 procedure Sort(var a: SArray);
78 function Sscanf(const s: string; const fmt: string;
79 const Pointers: array of Pointer): Integer;
80 function InDWArray(a: DWORD; arr: DWArray): Boolean;
81 function InWArray(a: Word; arr: WArray): Boolean;
82 function InSArray(a: string; arr: SArray): Boolean;
83 function GetPos(UID: Word; o: PObj): Boolean;
84 function parse(s: string): SArray;
85 function parse2(s: string; delim: Char): SArray;
86 function g_GetFileTime(fileName: String): Integer;
87 function g_SetFileTime(fileName: String; time: Integer): Boolean;
88 procedure SortSArray(var S: SArray);
89 function b_Text_Format(S: string): string;
90 function b_Text_Unformat(S: string): string;
92 implementation
94 uses
95 Math, g_map, g_gfx, g_player, SysUtils, MAPDEF,
96 StrUtils, e_graphics, g_monsters, g_items;
98 function g_PatchLength(X1, Y1, X2, Y2: Integer): Word;
99 begin
100 Result := Min(Round(Hypot(Abs(X2-X1), Abs(Y2-Y1))), 65535);
101 end;
103 function g_CollideLevel(X, Y: Integer; Width, Height: Word): Boolean;
104 begin
105 result := g_Map_CollidePanel(X, Y, Width, Height, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_OPENDOOR), false);
106 end;
107 (*
108 var
109 a: Integer;
110 begin
111 Result := False;
113 if gWalls = nil then
114 Exit;
116 for a := 0 to High(gWalls) do
117 if gWalls[a].Enabled and
118 not ( ((Y + Height <= gWalls[a].Y) or
119 (Y >= gWalls[a].Y + gWalls[a].Height)) or
120 ((X + Width <= gWalls[a].X) or
121 (X >= gWalls[a].X + gWalls[a].Width)) ) then
122 begin
123 Result := True;
124 Exit;
125 end;
126 end;
127 *)
129 function g_CollidePlayer(X, Y: Integer; Width, Height: Word): Boolean;
130 var
131 a: Integer;
132 begin
133 Result := False;
135 if gPlayers = nil then Exit;
137 for a := 0 to High(gPlayers) do
138 if (gPlayers[a] <> nil) and gPlayers[a].Live then
139 if gPlayers[a].Collide(X, Y, Width, Height) then
140 begin
141 Result := True;
142 Exit;
143 end;
144 end;
146 function g_CollideMonster(X, Y: Integer; Width, Height: Word): Boolean;
147 begin
148 result := g_Mons_AnyAt(X, Y, Width, Height);
149 end;
151 function g_TraceVector(X1, Y1, X2, Y2: Integer): Boolean;
152 var
153 i: Integer;
154 dx, dy: Integer;
155 Xerr, Yerr, d: LongWord;
156 incX, incY: Integer;
157 x, y: Integer;
158 begin
159 Result := False;
161 Assert(gCollideMap <> nil, 'g_TraceVector: gCollideMap = nil');
163 Xerr := 0;
164 Yerr := 0;
165 dx := X2-X1;
166 dy := Y2-Y1;
168 if dx > 0 then incX := 1 else if dx < 0 then incX := -1 else incX := 0;
169 if dy > 0 then incY := 1 else if dy < 0 then incY := -1 else incY := 0;
171 dx := abs(dx);
172 dy := abs(dy);
174 if dx > dy then d := dx else d := dy;
176 x := X1;
177 y := Y1;
179 for i := 1 to d do
180 begin
181 Inc(Xerr, dx);
182 Inc(Yerr, dy);
183 if Xerr>d then
184 begin
185 Dec(Xerr, d);
186 Inc(x, incX);
187 end;
188 if Yerr > d then
189 begin
190 Dec(Yerr, d);
191 Inc(y, incY);
192 end;
194 if (y > gMapInfo.Height-1) or
195 (y < 0) or (x > gMapInfo.Width-1) or (x < 0) then
196 Exit;
197 if ByteBool(gCollideMap[y, x] and MARK_BLOCKED) then
198 Exit;
199 end;
201 Result := True;
202 end;
204 function g_CreateUID(UIDType: Byte): Word;
205 var
206 ok: Boolean;
207 i: Integer;
208 begin
209 Result := $0;
211 case UIDType of
212 UID_PLAYER:
213 begin
214 repeat
215 Result := UID_MAX_GAME+$1+Random(UID_MAX_PLAYER-UID_MAX_GAME+$1);
217 ok := True;
218 if gPlayers <> nil then
219 for i := 0 to High(gPlayers) do
220 if gPlayers[i] <> nil then
221 if Result = gPlayers[i].UID then
222 begin
223 ok := False;
224 Break;
225 end;
226 until ok;
227 end;
229 UID_MONSTER:
230 begin
231 //FIXME!!!
232 while true do
233 begin
234 result := UID_MAX_PLAYER+$1+Random(UID_MAX_MONSTER-UID_MAX_GAME-UID_MAX_PLAYER+$1);
235 if (g_Monsters_Get(result) = nil) then break;
236 end;
237 end;
238 end;
239 end;
241 function g_GetUIDType(UID: Word): Byte;
242 begin
243 if UID <= UID_MAX_GAME then
244 Result := UID_GAME
245 else
246 if UID <= UID_MAX_PLAYER then
247 Result := UID_PLAYER
248 else
249 Result := UID_MONSTER;
250 end;
252 function g_Collide(X1, Y1: Integer; Width1, Height1: Word;
253 X2, Y2: Integer; Width2, Height2: Word): Boolean;
254 begin
255 Result := not ( ((Y1 + Height1 <= Y2) or
256 (Y2 + Height2 <= Y1)) or
257 ((X1 + Width1 <= X2) or
258 (X2 + Width2 <= X1)) );
259 end;
261 function g_CollideAround(X1, Y1: Integer; Width1, Height1: Word;
262 X2, Y2: Integer; Width2, Height2: Word): Boolean;
263 begin
264 Result := g_Collide(X1, Y1, Width1, Height1, X2, Y2, Width2, Height2) or
265 g_Collide(X1+1, Y1, Width1, Height1, X2, Y2, Width2, Height2) or
266 g_Collide(X1-1, Y1, Width1, Height1, X2, Y2, Width2, Height2) or
267 g_Collide(X1, Y1+1, Width1, Height1, X2, Y2, Width2, Height2) or
268 g_Collide(X1, Y1-1, Width1, Height1, X2, Y2, Width2, Height2);
269 end;
271 function c(X1, Y1, Width1, Height1, X2, Y2, Width2, Height2: Integer): Boolean;
272 begin
273 Result := not (((Y1 + Height1 <= Y2) or
274 (Y1 >= Y2 + Height2)) or
275 ((X1 + Width1 <= X2) or
276 (X1 >= X2 + Width2)));
277 end;
279 function g_Collide2(X1, Y1, X2, Y2, X3, Y3, X4, Y4: Integer): Boolean;
280 begin
281 //Result := not (((Y2 <= Y3) or (Y1 >= Y4)) or ((X2 <= X3) or (X1 >= X4)));
282 Result := c(X1, Y1, X2-X1, Y2-Y1, X3, Y3, X4-X3, Y4-Y3);
283 end;
285 function g_CollidePoint(X, Y, X2, Y2: Integer; Width, Height: Word): Boolean;
286 begin
287 X := X-X2;
288 Y := Y-Y2;
289 Result := (x >= 0) and (x <= Width) and
290 (y >= 0) and (y <= Height);
291 end;
293 procedure IncMax(var A: Integer; B, Max: Integer);
294 begin
295 if A+B > Max then A := Max else A := A+B;
296 end;
298 procedure IncMax(var A: Single; B, Max: Single);
299 begin
300 if A+B > Max then A := Max else A := A+B;
301 end;
303 procedure DecMin(var A: Integer; B, Min: Integer);
304 begin
305 if A-B < Min then A := Min else A := A-B;
306 end;
308 procedure DecMin(var A: Word; B, Min: Word);
309 begin
310 if A-B < Min then A := Min else A := A-B;
311 end;
313 procedure DecMin(var A: Single; B, Min: Single);
314 begin
315 if A-B < Min then A := Min else A := A-B;
316 end;
318 procedure IncMax(var A: Integer; Max: Integer);
319 begin
320 if A+1 > Max then A := Max else A := A+1;
321 end;
323 procedure IncMax(var A: Single; Max: Single);
324 begin
325 if A+1 > Max then A := Max else A := A+1;
326 end;
328 procedure IncMax(var A: Word; B, Max: Word);
329 begin
330 if A+B > Max then A := Max else A := A+B;
331 end;
333 procedure IncMax(var A: Word; Max: Word);
334 begin
335 if A+1 > Max then A := Max else A := A+1;
336 end;
338 procedure IncMax(var A: SmallInt; B, Max: SmallInt);
339 begin
340 if A+B > Max then A := Max else A := A+B;
341 end;
343 procedure IncMax(var A: SmallInt; Max: SmallInt);
344 begin
345 if A+1 > Max then A := Max else A := A+1;
346 end;
348 procedure DecMin(var A: Integer; Min: Integer);
349 begin
350 if A-1 < Min then A := Min else A := A-1;
351 end;
353 procedure DecMin(var A: Single; Min: Single);
354 begin
355 if A-1 < Min then A := Min else A := A-1;
356 end;
358 procedure DecMin(var A: Word; Min: Word);
359 begin
360 if A-1 < Min then A := Min else A := A-1;
361 end;
363 procedure DecMin(var A: Byte; B, Min: Byte);
364 begin
365 if A-B < Min then A := Min else A := A-B;
366 end;
368 procedure DecMin(var A: Byte; Min: Byte); overload;
369 begin
370 if A-1 < Min then A := Min else A := A-1;
371 end;
373 function Sign(A: Integer): ShortInt;
374 begin
375 if A < 0 then Result := -1
376 else if A > 0 then Result := 1
377 else Result := 0;
378 end;
380 function Sign(A: Single): ShortInt;
381 const
382 Eps = 1.0E-5;
383 begin
384 if Abs(A) < Eps then Result := 0
385 else if A < 0 then Result := -1
386 else Result := 1;
387 end;
389 function PointToRect(X, Y, X1, Y1: Integer; Width, Height: Word): Integer;
390 begin
391 X := X-X1; // A(0;0) --- B(W;0)
392 Y := Y-Y1; // | |
393 // D(0;H) --- C(W;H)
394 if X < 0 then
395 begin // Ñëåâà
396 if Y < 0 then // Ñëåâà ñâåðõó: ðàññòîÿíèå äî A
397 Result := Round(Hypot(X, Y))
398 else
399 if Y > Height then // Ñëåâà ñíèçó: ðàññòîÿíèå äî D
400 Result := Round(Hypot(X, Y-Height))
401 else // Ñëåâà ïîñåðåäèíå: ðàññòîÿíèå äî AD
402 Result := -X;
403 end
404 else
405 if X > Width then
406 begin // Ñïðàâà
407 X := X-Width;
408 if y < 0 then // Ñïðàâà ñâåðõó: ðàññòîÿíèå äî B
409 Result := Round(Hypot(X, Y))
410 else
411 if Y > Height then // Ñïðàâà ñíèçó: ðàññòîÿíèå äî C
412 Result := Round(Hypot(X, Y-Height))
413 else // Ñïðàâà ïîñåðåäèíå: ðàññòîÿíèå äî BC
414 Result := X;
415 end
416 else // Ïîñåðåäèíå
417 begin
418 if Y < 0 then // Ïîñåðåäèíå ñâåðõó: ðàññòîÿíèå äî AB
419 Result := -Y
420 else
421 if Y > Height then // Ïîñåðåäèíå ñíèçó: ðàññòîÿíèå äî DC
422 Result := Y-Height
423 else // Âíóòðè ïðÿìîóãîëüíèêà: ðàññòîÿíèå 0
424 Result := 0;
425 end;
426 end;
428 function g_GetAcidHit(X, Y: Integer; Width, Height: Word): Byte;
429 const
430 tab: array[0..3] of Byte = (0, 5, 10, 20);
431 var
432 a: Byte;
433 begin
434 a := 0;
436 if g_Map_CollidePanel(X, Y, Width, Height, PANEL_ACID1, False) then a := a or 1;
437 if g_Map_CollidePanel(X, Y, Width, Height, PANEL_ACID2, False) then a := a or 2;
439 Result := tab[a];
440 end;
442 function g_Look(a, b: PObj; d: TDirection): Boolean;
443 begin
444 if ((b^.X > a^.X) and (d = D_LEFT)) or
445 ((b^.X < a^.X) and (d = D_RIGHT)) then
446 begin
447 Result := False;
448 Exit;
449 end;
451 Result := g_TraceVector(a^.X+a^.Rect.X+(a^.Rect.Width div 2),
452 a^.Y+a^.Rect.Y+(a^.Rect.Height div 2),
453 b^.X+b^.Rect.X+(b^.Rect.Width div 2),
454 b^.Y+b^.Rect.Y+(b^.Rect.Height div 2));
455 end;
457 function GetAngle(baseX, baseY, pointX, PointY: Integer): SmallInt;
458 var
459 c: Single;
460 a, b: Integer;
461 begin
462 a := abs(pointX-baseX);
463 b := abs(pointY-baseY);
465 if a = 0 then c := 90
466 else c := RadToDeg(ArcTan(b/a));
468 if pointY < baseY then c := -c;
469 if pointX > baseX then c := 180-c;
471 Result := Round(c);
472 end;
474 function GetAngle2(vx, vy: Integer): SmallInt;
475 var
476 c: Single;
477 a, b: Integer;
478 begin
479 a := abs(vx);
480 b := abs(vy);
482 if a = 0 then
483 c := 90
484 else
485 c := RadToDeg(ArcTan(b/a));
487 if vy < 0 then
488 c := -c;
489 if vx > 0 then
490 c := 180 - c;
492 c := c + 180;
494 Result := Round(c);
495 end;
497 {function g_CollideLine(x1, y1, x2, y2, rX, rY: Integer; rWidth, rHeight: Word): Boolean;
498 const
499 table: array[0..8, 0..8] of Byte =
500 ((0, 0, 3, 3, 1, 2, 2, 0, 1),
501 (0, 0, 0, 0, 4, 7, 2, 0, 1),
502 (3, 0, 0, 0, 4, 4, 1, 3, 1),
503 (3, 0, 0, 0, 0, 0, 5, 6, 1),
504 (1, 4, 4, 0, 0, 0, 5, 5, 1),
505 (2, 7, 4, 0, 0, 0, 0, 0, 1),
506 (2, 2, 1, 5, 5, 0, 0, 0, 1),
507 (0, 0, 3, 6, 5, 0, 0, 0, 1),
508 (1, 1, 1, 1, 1, 1, 1, 1, 1));
510 function GetClass(x, y: Integer): Byte;
511 begin
512 if y < rY then
513 begin
514 if x < rX then Result := 7
515 else if x < rX+rWidth then Result := 0
516 else Result := 1;
517 end
518 else if y < rY+rHeight then
519 begin
520 if x < rX then Result := 6
521 else if x < rX+rWidth then Result := 8
522 else Result := 2;
523 end
524 else
525 begin
526 if x < rX then Result := 5
527 else if x < rX+rWidth then Result := 4
528 else Result := 3;
529 end;
530 end;
532 begin
533 case table[GetClass(x1, y1), GetClass(x2, y2)] of
534 0: Result := False;
535 1: Result := True;
536 2: Result := Abs((rY-y1))/Abs((rX-x1)) <= Abs((y2-y1))/Abs((x2-x1));
537 3: Result := Abs((rY-y1))/Abs((rX+rWidth-x1)) <= Abs((y2-y1))/Abs((x2-x1));
538 4: Result := Abs((rY+rHeight-y1))/Abs((rX+rWidth-x1)) >= Abs((y2-y1))/Abs((x2-x1));
539 5: Result := Abs((rY+rHeight-y1))/Abs((rX-x1)) >= Abs((y2-y1))/Abs((x2-x1));
540 6: Result := (Abs((rY-y1))/Abs((rX+rWidth-x1)) <= Abs((y2-y1))/Abs((x2-x1))) and
541 (Abs((rY+rHeight-y1))/Abs((rX-x1)) >= Abs((y2-y1))/Abs((x2-x1)));
542 7: Result := (Abs((rY+rHeight-y1))/Abs((rX+rWidth-x1)) >= Abs((y2-y1))/Abs((x2-x1))) and
543 (Abs((rY-y1))/Abs((rX-x1)) <= Abs((y2-y1))/Abs((x2-x1)));
544 else Result := False;
545 end;
546 end;}
548 function g_CollideLine(x1, y1, x2, y2, rX, rY: Integer; rWidth, rHeight: Word): Boolean;
549 var
550 i: Integer;
551 dx, dy: Integer;
552 Xerr, Yerr: Integer;
553 incX, incY: Integer;
554 x, y, d: Integer;
555 begin
556 Result := True;
558 Xerr := 0;
559 Yerr := 0;
560 dx := X2-X1;
561 dy := Y2-Y1;
563 if dx > 0 then incX := 1 else if dx < 0 then incX := -1 else incX := 0;
564 if dy > 0 then incY := 1 else if dy < 0 then incY := -1 else incY := 0;
566 dx := abs(dx);
567 dy := abs(dy);
569 if dx > dy then d := dx else d := dy;
571 x := X1;
572 y := Y1;
574 for i := 1 to d+1 do
575 begin
576 Inc(Xerr, dx);
577 Inc(Yerr, dy);
578 if Xerr > d then
579 begin
580 Dec(Xerr, d);
581 Inc(x, incX);
582 end;
583 if Yerr > d then
584 begin
585 Dec(Yerr, d);
586 Inc(y, incY);
587 end;
589 if (x >= rX) and (x <= (rX + rWidth - 1)) and
590 (y >= rY) and (y <= (rY + rHeight - 1)) then Exit;
591 end;
593 Result := False;
594 end;
596 function GetStr(var Str: string): string;
597 var
598 a: Integer;
599 begin
600 Result := '';
601 for a := 1 to Length(Str) do
602 if (a = Length(Str)) or (Str[a+1] = ' ') then
603 begin
604 Result := Copy(Str, 1, a);
605 Delete(Str, 1, a+1);
606 Str := Trim(Str);
607 Exit;
608 end;
609 end;
611 {function GetLines(Text: string; MaxChars: Word): SArray;
612 var
613 a: Integer;
614 b: array of string;
615 str: string;
616 begin
617 Text := Trim(Text);
619 while Pos(' ', Text) <> 0 do Text := AnsiReplaceStr(Text, ' ', ' ');
621 while Text <> '' do
622 begin
623 SetLength(b, Length(b)+1);
624 b[High(b)] := GetStr(Text);
625 end;
627 a := 0;
628 while True do
629 begin
630 if a > High(b) then Break;
632 str := b[a];
633 a := a+1;
635 if Length(str) >= MaxChars then
636 begin
637 while str <> '' do
638 begin
639 SetLength(Result, Length(Result)+1);
640 Result[High(Result)] := Copy(str, 1, MaxChars);
641 Delete(str, 1, MaxChars);
642 end;
644 Continue;
645 end;
647 while (a <= High(b)) and (Length(str+' '+b[a]) <= MaxChars) do
648 begin
649 str := str+' '+b[a];
650 a := a+1;
651 end;
653 SetLength(Result, Length(Result)+1);
654 Result[High(Result)] := str;
655 end;
656 end;}
658 function GetLines(Text: string; FontID: DWORD; MaxWidth: Word): SArray;
660 function TextLen(Text: string): Word;
661 var
662 h: Word;
663 begin
664 e_CharFont_GetSize(FontID, Text, Result, h);
665 end;
667 var
668 a, c: Integer;
669 b: array of string;
670 str: string;
671 begin
672 SetLength(Result, 0);
673 SetLength(b, 0);
675 Text := Trim(Text);
677 // Óäàëÿåì ìíîæåñòâåííûå ïðîáåëû:
678 while Pos(' ', Text) <> 0 do
679 Text := AnsiReplaceStr(Text, ' ', ' ');
681 while Text <> '' do
682 begin
683 SetLength(b, Length(b)+1);
684 b[High(b)] := GetStr(Text);
685 end;
687 a := 0;
688 while True do
689 begin
690 if a > High(b) then
691 Break;
693 str := b[a];
694 a := a+1;
696 if TextLen(str) > MaxWidth then
697 begin // Òåêóùàÿ ñòðîêà ñëèøêîì äëèííàÿ => ðàçáèâàåì
698 while str <> '' do
699 begin
700 SetLength(Result, Length(Result)+1);
702 c := 0;
703 while (c < Length(str)) and
704 (TextLen(Copy(str, 1, c+1)) < MaxWidth) do
705 c := c+1;
707 Result[High(Result)] := Copy(str, 1, c);
708 Delete(str, 1, c);
709 end;
710 end
711 else // Ñòðîêà íîðìàëüíîé äëèíû => ñîåäèíÿåì ñî ñëåäóþùèìè
712 begin
713 while (a <= High(b)) and
714 (TextLen(str+' '+b[a]) < MaxWidth) do
715 begin
716 str := str+' '+b[a];
717 a := a + 1;
718 end;
720 SetLength(Result, Length(Result)+1);
721 Result[High(Result)] := str;
722 end;
723 end;
724 end;
726 procedure Sort(var a: SArray);
727 var
728 i, j: Integer;
729 s: string;
730 begin
731 if a = nil then Exit;
733 for i := High(a) downto Low(a) do
734 for j := Low(a) to High(a)-1 do
735 if LowerCase(a[j]) > LowerCase(a[j+1]) then
736 begin
737 s := a[j];
738 a[j] := a[j+1];
739 a[j+1] := s;
740 end;
741 end;
743 function Sscanf(const s: String; const fmt: String;
744 const Pointers: array of Pointer): Integer;
745 var
746 i, j, n, m: Integer;
747 s1: ShortString;
748 L: LongInt;
749 X: Extended;
751 function GetInt(): Integer;
752 begin
753 s1 := '';
754 while (n <= Length(s)) and (s[n] = ' ') do
755 Inc(n);
757 while (n <= Length(s)) and (s[n] in ['0'..'9', '+', '-']) do
758 begin
759 s1 := s1 + s[n];
760 Inc(n);
761 end;
763 Result := Length(s1);
764 end;
766 function GetFloat(): Integer;
767 begin
768 s1 := '';
769 while (n <= Length(s)) and (s[n] = ' ') do
770 Inc(n);
772 while (n <= Length(s)) and //jd >= rather than >
773 (s[n] in ['0'..'9', '+', '-', '.', 'e', 'E']) do
774 begin
775 s1 := s1 + s[n];
776 Inc(n);
777 end;
779 Result := Length(s1);
780 end;
782 function GetString(): Integer;
783 begin
784 s1 := '';
785 while (n <= Length(s)) and (s[n] = ' ') do
786 Inc(n);
788 while (n <= Length(s)) and (s[n] <> ' ') do
789 begin
790 s1 := s1 + s[n];
791 Inc(n);
792 end;
794 Result := Length(s1);
795 end;
797 function ScanStr(c: Char): Boolean;
798 begin
799 while (n <= Length(s)) and (s[n] <> c) do
800 Inc(n);
801 Inc(n);
803 Result := (n <= Length(s));
804 end;
806 function GetFmt(): Integer;
807 begin
808 Result := -1;
810 while (True) do
811 begin
812 while (fmt[m] = ' ') and (m < Length(fmt)) do
813 Inc(m);
814 if (m >= Length(fmt)) then
815 Break;
817 if (fmt[m] = '%') then
818 begin
819 Inc(m);
820 case fmt[m] of
821 'd': Result := vtInteger;
822 'f': Result := vtExtended;
823 's': Result := vtString;
824 end;
825 Inc(m);
826 Break;
827 end;
829 if (not ScanStr(fmt[m])) then
830 Break;
831 Inc(m);
832 end;
833 end;
835 begin
836 n := 1;
837 m := 1;
838 Result := 0;
839 s1 := '';
841 for i := 0 to High(Pointers) do
842 begin
843 j := GetFmt();
845 case j of
846 vtInteger :
847 begin
848 if GetInt() > 0 then
849 begin
850 L := StrToIntDef(s1, 0);
851 Move(L, Pointers[i]^, SizeOf(LongInt));
852 Inc(Result);
853 end
854 else
855 Break;
856 end;
858 vtExtended :
859 begin
860 if GetFloat() > 0 then
861 begin
862 X := StrToFloatDef(s1, 0.0);
863 Move(X, Pointers[i]^, SizeOf(Extended));
864 Inc(Result);
865 end
866 else
867 Break;
868 end;
870 vtString :
871 begin
872 if GetString() > 0 then
873 begin
874 Move(s1, Pointers[i]^, Length(s1)+1);
875 Inc(Result);
876 end
877 else
878 Break;
879 end;
881 else {case}
882 Break;
883 end; {case}
884 end;
885 end;
887 function InDWArray(a: DWORD; arr: DWArray): Boolean;
888 var
889 b: Integer;
890 begin
891 Result := False;
893 if arr = nil then Exit;
895 for b := 0 to High(arr) do
896 if arr[b] = a then
897 begin
898 Result := True;
899 Exit;
900 end;
901 end;
903 function InWArray(a: Word; arr: WArray): Boolean;
904 var
905 b: Integer;
906 begin
907 Result := False;
909 if arr = nil then Exit;
911 for b := 0 to High(arr) do
912 if arr[b] = a then
913 begin
914 Result := True;
915 Exit;
916 end;
917 end;
919 function InSArray(a: string; arr: SArray): Boolean;
920 var
921 b: Integer;
922 begin
923 Result := False;
925 if arr = nil then Exit;
927 a := AnsiLowerCase(a);
929 for b := 0 to High(arr) do
930 if AnsiLowerCase(arr[b]) = a then
931 begin
932 Result := True;
933 Exit;
934 end;
935 end;
937 function GetPos(UID: Word; o: PObj): Boolean;
938 var
939 p: TPlayer;
940 m: TMonster;
941 begin
942 Result := False;
944 case g_GetUIDType(UID) of
945 UID_PLAYER:
946 begin
947 p := g_Player_Get(UID);
948 if p = nil then Exit;
949 if not p.Live then Exit;
951 o^ := p.Obj;
952 end;
954 UID_MONSTER:
955 begin
956 m := g_Monsters_Get(UID);
957 if m = nil then Exit;
958 if not m.Live then Exit;
960 o^ := m.Obj;
961 end;
962 else Exit;
963 end;
965 Result := True;
966 end;
968 function parse(s: String): SArray;
969 var
970 a: Integer;
971 begin
972 Result := nil;
973 if s = '' then
974 Exit;
976 while s <> '' do
977 begin
978 for a := 1 to Length(s) do
979 if (s[a] = ',') or (a = Length(s)) then
980 begin
981 SetLength(Result, Length(Result)+1);
983 if s[a] = ',' then
984 Result[High(Result)] := Copy(s, 1, a-1)
985 else // Êîíåö ñòðîêè
986 Result[High(Result)] := s;
988 Delete(s, 1, a);
989 Break;
990 end;
991 end;
992 end;
994 function parse2(s: string; delim: Char): SArray;
995 var
996 a: Integer;
997 begin
998 Result := nil;
999 if s = '' then Exit;
1001 while s <> '' do
1002 begin
1003 for a := 1 to Length(s) do
1004 if (s[a] = delim) or (a = Length(s)) then
1005 begin
1006 SetLength(Result, Length(Result)+1);
1008 if s[a] = delim then Result[High(Result)] := Copy(s, 1, a-1)
1009 else Result[High(Result)] := s;
1011 Delete(s, 1, a);
1012 Break;
1013 end;
1014 end;
1015 end;
1017 function g_GetFileTime(fileName: String): Integer;
1018 var
1019 F: File;
1020 begin
1021 if not FileExists(fileName) then
1022 begin
1023 Result := -1;
1024 Exit;
1025 end;
1027 AssignFile(F, fileName);
1028 Reset(F);
1029 Result := FileGetDate(TFileRec(F).Handle);
1030 CloseFile(F);
1031 end;
1033 function g_SetFileTime(fileName: String; time: Integer): Boolean;
1034 var
1035 F: File;
1036 begin
1037 if (not FileExists(fileName)) or (time < 0) then
1038 begin
1039 Result := False;
1040 Exit;
1041 end;
1043 AssignFile(F, fileName);
1044 Reset(F);
1045 Result := (FileSetDate(TFileRec(F).Handle, time) = 0);
1046 CloseFile(F);
1047 end;
1049 procedure SortSArray(var S: SArray);
1050 var
1051 b: Boolean;
1052 i: Integer;
1053 sw: ShortString;
1054 begin
1055 repeat
1056 b := False;
1057 for i := Low(S) to High(S) - 1 do
1058 if S[i] > S[i + 1] then begin
1059 sw := S[i];
1060 S[i] := S[i + 1];
1061 S[i + 1] := sw;
1062 b := True;
1063 end;
1064 until not b;
1065 end;
1067 function b_Text_Format(S: string): string;
1068 var
1069 Spec, Rst: Boolean;
1070 I: Integer;
1071 begin
1072 Result := '';
1073 Spec := False;
1074 Rst := False;
1075 for I := 1 to Length(S) do
1076 begin
1077 if (not Spec) and (S[I] = '\') and (I + 1 <= Length(S)) then
1078 begin
1079 Spec := True;
1080 Rst := True;
1081 continue;
1082 end;
1083 if Spec then
1084 begin
1085 case S[I] of
1086 'n': // line feed
1087 Result := Result + #10;
1088 '0': // black
1089 Result := Result + #1;
1090 '1': // white
1091 Result := Result + #2;
1092 'd': // darker
1093 Result := Result + #3;
1094 'l': // lighter
1095 Result := Result + #4;
1096 'r': // red
1097 Result := Result + #18;
1098 'g': // green
1099 Result := Result + #19;
1100 'b': // blue
1101 Result := Result + #20;
1102 'y': // yellow
1103 Result := Result + #21;
1104 '\': // escape
1105 Result := Result + '\';
1106 else
1107 Result := Result + '\' + S[I];
1108 end;
1109 Spec := False;
1110 end else
1111 Result := Result + S[I];
1112 end;
1113 // reset to white at end
1114 if Rst then Result := Result + #2;
1115 end;
1117 function b_Text_Unformat(S: string): string;
1118 var
1119 Spec: Boolean;
1120 I: Integer;
1121 begin
1122 Result := '';
1123 Spec := False;
1124 for I := 1 to Length(S) do
1125 begin
1126 if S[I] in [#1, #2, #3, #4, #10, #18, #19, #20, #21] then
1127 begin
1128 Spec := False;
1129 continue;
1130 end;
1131 if (not Spec) and (S[I] = '\') and (I + 1 <= Length(S)) then
1132 begin
1133 Spec := True;
1134 continue;
1135 end;
1136 if Spec then
1137 begin
1138 case S[I] of
1139 'n': ;
1140 '0': ;
1141 '1': ;
1142 'd': ;
1143 'l': ;
1144 'r': ;
1145 'g': ;
1146 'b': ;
1147 'y': ;
1148 '\': Result := Result + '\';
1149 else
1150 Result := Result + '\' + S[I];
1151 end;
1152 Spec := False;
1153 end else
1154 Result := Result + S[I];
1155 end;
1156 end;
1158 end.