1 (* Copyright (C) Doom 2D: Forever Developers
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, version 3 of the License ONLY.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 {$INCLUDE ../shared/a_modes.inc}
24 GAME_VERSION
= '0.667';
25 GAME_BUILDDATE
= {$I %DATE%};
26 GAME_BUILDTIME
= {$I %TIME%};
32 UID_MAX_PLAYER
= $7FFF;
33 UID_MAX_MONSTER
= $FFFF;
36 TDirection
= (D_LEFT
, D_RIGHT
);
37 WArray
= array of Word;
38 DWArray
= array of DWORD
;
39 String20
= String[20];
41 function g_GetBuilderName (): AnsiString;
42 function g_GetBuildHash (full
: Boolean = True): AnsiString;
43 function g_GetBuildArch (): AnsiString;
45 function g_CreateUID(UIDType
: Byte): Word;
46 function g_GetUIDType(UID
: Word): Byte;
47 function g_Collide(X1
, Y1
: Integer; Width1
, Height1
: Word;
48 X2
, Y2
: Integer; Width2
, Height2
: Word): Boolean; inline;
49 function g_CollideLine(x1
, y1
, x2
, y2
, rX
, rY
: Integer; rWidth
, rHeight
: Word): Boolean;
50 function g_CollidePoint(X
, Y
, X2
, Y2
: Integer; Width
, Height
: Word): Boolean; inline;
51 function g_CollideLevel(X
, Y
: Integer; Width
, Height
: Word): Boolean; inline;
52 function g_CollideAround(X1
, Y1
: Integer; Width1
, Height1
: Word;
53 X2
, Y2
: Integer; Width2
, Height2
: Word): Boolean; inline;
54 function g_CollidePlayer(X
, Y
: Integer; Width
, Height
: Word): Boolean; inline;
55 function g_PatchLength(X1
, Y1
, X2
, Y2
: Integer): Word;
56 function g_TraceVector(X1
, Y1
, X2
, Y2
: Integer): Boolean; // `true`: no wall hit
57 function g_GetAcidHit(X
, Y
: Integer; Width
, Height
: Word): Byte;
58 procedure IncMax(var A
: Integer; B
, Max
: Integer); overload
;
59 procedure IncMax(var A
: Single; B
, Max
: Single); overload
;
60 procedure IncMax(var A
: Integer; Max
: Integer); overload
;
61 procedure IncMax(var A
: Single; Max
: Single); overload
;
62 procedure IncMax(var A
: Word; B
, Max
: Word); overload
;
63 procedure IncMax(var A
: Word; Max
: Word); overload
;
64 procedure IncMax(var A
: SmallInt; B
, Max
: SmallInt); overload
;
65 procedure IncMax(var A
: SmallInt; Max
: SmallInt); overload
;
66 procedure DecMin(var A
: Integer; B
, Min
: Integer); overload
;
67 procedure DecMin(var A
: Single; B
, Min
: Single); overload
;
68 procedure DecMin(var A
: Integer; Min
: Integer); overload
;
69 procedure DecMin(var A
: Single; Min
: Single); overload
;
70 procedure DecMin(var A
: Word; B
, Min
: Word); overload
;
71 procedure DecMin(var A
: Word; Min
: Word); overload
;
72 procedure DecMin(var A
: Byte; B
, Min
: Byte); overload
;
73 procedure DecMin(var A
: Byte; Min
: Byte); overload
;
74 function Sign(A
: Integer): ShortInt; overload
;
75 function Sign(A
: Single): ShortInt; overload
;
76 function PointToRect(X
, Y
, X1
, Y1
: Integer; Width
, Height
: Word): Integer;
77 function GetAngle(baseX
, baseY
, pointX
, PointY
: Integer): SmallInt;
78 function GetAngle2(vx
, vy
: Integer): SmallInt;
79 function Sscanf(const s
: string; const fmt
: string;
80 const Pointers
: array of Pointer): Integer;
81 function InDWArray(a
: DWORD
; arr
: DWArray
): Boolean;
82 function InWArray(a
: Word; arr
: WArray
): Boolean;
83 function InSArray(a
: string; arr
: SSArray
): Boolean;
84 function GetPos(UID
: Word; o
: PObj
): Boolean;
85 function parse(s
: string): SSArray
;
86 function parse2(s
: string; delim
: Char): SSArray
;
87 function g_GetFileTime(fileName
: String): Integer;
88 function g_SetFileTime(fileName
: String; time
: Integer): Boolean;
89 procedure SortSArray(var S
: SSArray
);
90 function b_Text_Format(S
: string): string;
91 function b_Text_Unformat(S
: string): string;
92 function b_Text_Wrap(S
: string; LineLen
: Integer): string;
93 function b_Text_LineCount(S
: string): Integer;
96 gmon_dbg_los_enabled
: Boolean = true;
101 Math
, geom
, e_log
, g_map
, g_player
, SysUtils
, MAPDEF
,
102 StrUtils
, g_monsters
, g_items
, g_game
;
105 {$WARN 2054 OFF} // unknwon env var
106 {$WARN 6018 OFF} // unreachable code
107 function g_GetBuilderName (): AnsiString;
109 if {$I %D2DF_BUILD_USER%} <> '' then
110 result
:= {$I %D2DF_BUILD_USER%} // custom
111 else if {$I %USER%} <> '' then
112 result
:= {$I %USER%} // unix username
113 else if {$I %USERNAME%} <> '' then
114 result
:= {$I %USERNAME%} // windows username
119 function g_GetBuildHash (full
: Boolean = True): AnsiString;
121 if {$I %D2DF_BUILD_HASH%} <> '' then
123 result
:= {$I %D2DF_BUILD_HASH%}
125 result
:= Copy({$I %D2DF_BUILD_HASH%}, 1, 7)
127 result
:= 'custom build'
131 function g_GetBuildArch (): AnsiString;
132 var cpu
, mode
, fpu
: AnsiString;
134 {$IF DEFINED(CPUX86_64) OR DEFINED(CPUAMD64) OR DEFINED(CPUX64)}
136 {$ELSEIF DEFINED(CPUI386) OR DEFINED(CPU386)}
138 {$ELSEIF DEFINED(CPUI8086)}
140 {$ELSEIF DEFINED(CPUI64)}
142 {$ELSEIF DEFINED(CPUARM)}
144 {$ELSEIF DEFINED(CPUAVR)}
146 {$ELSEIF DEFINED(CPUPOWERPC32)}
148 {$ELSEIF DEFINED(CPUPOWERPC64)}
150 {$ELSEIF DEFINED(CPUALPHA)}}
152 {$ELSEIF DEFINED(CPUSPARC32)}
154 {$ELSEIF DEFINED(CPUM68020)}
156 {$ELSEIF DEFINED(CPU68K) OR DEFINED(CPUM68K)}
158 {$ELSEIF DEFINED(CPUSPARC)}
159 cpu
:= 'unknown-sparc';
160 {$ELSEIF DEFINED(CPUPOWERPC)}
161 cpu
:= 'unknown-ppc';
162 {$ELSEIF DEFINED(CPU86) OR DEFINED(CPU87)}
163 cpu
:= 'unknown-intel';
165 cpu
:= 'unknown-arch';
170 {$ELSEIF DEFINED(CPU32)}
172 {$ELSEIF DEFINED(CPU16)}
175 mode
:= 'unknown-mode';
178 {$IF DEFINED(FPUSOFT)}
180 {$ELSEIF DEFINED(FPUSSE3)}
182 {$ELSEIF DEFINED(FPUSSE2)}
184 {$ELSEIF DEFINED(FPUSSE)}
186 {$ELSEIF DEFINED(FPUSSE64)}
188 {$ELSEIF DEFINED(FPULIBGCC)}
190 {$ELSEIF DEFINED(FPU68881)}
192 {$ELSEIF DEFINED(FPUVFP)}
194 {$ELSEIF DEFINED(FPUFPA11)}
196 {$ELSEIF DEFINED(FPUFPA10)}
198 {$ELSEIF DEFINED(FPUFPA)}
200 {$ELSEIF DEFINED(FPUX87)}
202 {$ELSEIF DEFINED(FPUITANIUM)}
204 {$ELSEIF DEFINED(FPUSTANDARD)}
206 {$ELSEIF DEFINED(FPUHARD)}
209 fpu
:= 'unknown-fpu';
212 result
:= cpu
+ ' ' + mode
+ ' ' + fpu
;
215 function g_PatchLength(X1
, Y1
, X2
, Y2
: Integer): Word;
217 Result
:= Min(Round(Hypot(Abs(X2
-X1
), Abs(Y2
-Y1
))), 65535);
220 function g_CollideLevel(X
, Y
: Integer; Width
, Height
: Word): Boolean; inline;
222 result
:= g_Map_CollidePanel(X
, Y
, Width
, Height
, (PANEL_WALL
or PANEL_CLOSEDOOR
or PANEL_OPENDOOR
), false);
233 for a := 0 to High(gWalls) do
234 if gWalls[a].Enabled and
235 not ( ((Y + Height <= gWalls[a].Y) or
236 (Y >= gWalls[a].Y + gWalls[a].Height)) or
237 ((X + Width <= gWalls[a].X) or
238 (X >= gWalls[a].X + gWalls[a].Width)) ) then
246 function g_CollidePlayer(X
, Y
: Integer; Width
, Height
: Word): Boolean; inline;
252 if gPlayers
= nil then Exit
;
254 for a
:= 0 to High(gPlayers
) do
255 if (gPlayers
[a
] <> nil) and gPlayers
[a
].alive
then
256 if gPlayers
[a
].Collide(X
, Y
, Width
, Height
) then
264 function g_TraceVector(X1
, Y1
, X2
, Y2
: Integer): Boolean;
266 wallHitX
: Integer = 0;
267 wallHitY
: Integer = 0;
271 Xerr, Yerr, d: LongWord;
279 Assert(gCollideMap <> nil, 'g_TraceVector: gCollideMap = nil');
286 if dx > 0 then incX := 1 else if dx < 0 then incX := -1 else incX := 0;
287 if dy > 0 then incY := 1 else if dy < 0 then incY := -1 else incY := 0;
292 if dx > dy then d := dx else d := dy;
312 if (y > gMapInfo.Height-1) or
313 (y < 0) or (x > gMapInfo.Width-1) or (x < 0) then
315 if ByteBool(gCollideMap[y, x] and MARK_BLOCKED) then
322 // `true` if no obstacles
323 if (g_profile_los
) then g_Mons_LOS_Start();
324 result
:= (g_Map_traceToNearestWall(x1
, y1
, x2
, y2
, @wallHitX
, @wallHitY
) = nil);
325 if (g_profile_los
) then g_Mons_LOS_End();
329 function g_CreateUID(UIDType
: Byte): Word;
340 Result
:= UID_MAX_GAME
+$1+Random(UID_MAX_PLAYER
-UID_MAX_GAME
+$1);
343 if gPlayers
<> nil then
344 for i
:= 0 to High(gPlayers
) do
345 if gPlayers
[i
] <> nil then
346 if Result
= gPlayers
[i
].UID
then
359 result
:= UID_MAX_PLAYER
+$1+Random(UID_MAX_MONSTER
-UID_MAX_GAME
-UID_MAX_PLAYER
+$1);
360 if (g_Monsters_ByUID(result
) = nil) then break
;
366 function g_GetUIDType(UID
: Word): Byte;
368 if UID
<= UID_MAX_GAME
then
371 if UID
<= UID_MAX_PLAYER
then
374 Result
:= UID_MONSTER
;
377 function g_Collide(X1
, Y1
: Integer; Width1
, Height1
: Word;
378 X2
, Y2
: Integer; Width2
, Height2
: Word): Boolean; inline;
380 Result
:= not ( ((Y1
+ Height1
<= Y2
) or
381 (Y2
+ Height2
<= Y1
)) or
382 ((X1
+ Width1
<= X2
) or
383 (X2
+ Width2
<= X1
)) );
386 function g_CollideAround(X1
, Y1
: Integer; Width1
, Height1
: Word;
387 X2
, Y2
: Integer; Width2
, Height2
: Word): Boolean; inline;
389 Result
:= g_Collide(X1
, Y1
, Width1
, Height1
, X2
, Y2
, Width2
, Height2
) or
390 g_Collide(X1
+1, Y1
, Width1
, Height1
, X2
, Y2
, Width2
, Height2
) or
391 g_Collide(X1
-1, Y1
, Width1
, Height1
, X2
, Y2
, Width2
, Height2
) or
392 g_Collide(X1
, Y1
+1, Width1
, Height1
, X2
, Y2
, Width2
, Height2
) or
393 g_Collide(X1
, Y1
-1, Width1
, Height1
, X2
, Y2
, Width2
, Height2
);
396 function c(X1
, Y1
, Width1
, Height1
, X2
, Y2
, Width2
, Height2
: Integer): Boolean; inline;
398 Result
:= not (((Y1
+ Height1
<= Y2
) or
399 (Y1
>= Y2
+ Height2
)) or
400 ((X1
+ Width1
<= X2
) or
401 (X1
>= X2
+ Width2
)));
404 function g_Collide2(X1
, Y1
, X2
, Y2
, X3
, Y3
, X4
, Y4
: Integer): Boolean; inline;
406 //Result := not (((Y2 <= Y3) or (Y1 >= Y4)) or ((X2 <= X3) or (X1 >= X4)));
407 Result
:= c(X1
, Y1
, X2
-X1
, Y2
-Y1
, X3
, Y3
, X4
-X3
, Y4
-Y3
);
410 function g_CollidePoint(X
, Y
, X2
, Y2
: Integer; Width
, Height
: Word): Boolean; inline;
414 Result
:= (x
>= 0) and (x
<= Width
) and
415 (y
>= 0) and (y
<= Height
);
418 procedure IncMax(var A
: Integer; B
, Max
: Integer);
420 if A
+B
> Max
then A
:= Max
else A
:= A
+B
;
423 procedure IncMax(var A
: Single; B
, Max
: Single);
425 if A
+B
> Max
then A
:= Max
else A
:= A
+B
;
428 procedure DecMin(var A
: Integer; B
, Min
: Integer);
430 if A
-B
< Min
then A
:= Min
else A
:= A
-B
;
433 procedure DecMin(var A
: Word; B
, Min
: Word);
435 if A
-B
< Min
then A
:= Min
else A
:= A
-B
;
438 procedure DecMin(var A
: Single; B
, Min
: Single);
440 if A
-B
< Min
then A
:= Min
else A
:= A
-B
;
443 procedure IncMax(var A
: Integer; Max
: Integer);
445 if A
+1 > Max
then A
:= Max
else A
:= A
+1;
448 procedure IncMax(var A
: Single; Max
: Single);
450 if A
+1 > Max
then A
:= Max
else A
:= A
+1;
453 procedure IncMax(var A
: Word; B
, Max
: Word);
455 if A
+B
> Max
then A
:= Max
else A
:= A
+B
;
458 procedure IncMax(var A
: Word; Max
: Word);
460 if A
+1 > Max
then A
:= Max
else A
:= A
+1;
463 procedure IncMax(var A
: SmallInt; B
, Max
: SmallInt);
465 if A
+B
> Max
then A
:= Max
else A
:= A
+B
;
468 procedure IncMax(var A
: SmallInt; Max
: SmallInt);
470 if A
+1 > Max
then A
:= Max
else A
:= A
+1;
473 procedure DecMin(var A
: Integer; Min
: Integer);
475 if A
-1 < Min
then A
:= Min
else A
:= A
-1;
478 procedure DecMin(var A
: Single; Min
: Single);
480 if A
-1 < Min
then A
:= Min
else A
:= A
-1;
483 procedure DecMin(var A
: Word; Min
: Word);
485 if A
-1 < Min
then A
:= Min
else A
:= A
-1;
488 procedure DecMin(var A
: Byte; B
, Min
: Byte);
490 if A
-B
< Min
then A
:= Min
else A
:= A
-B
;
493 procedure DecMin(var A
: Byte; Min
: Byte); overload
;
495 if A
-1 < Min
then A
:= Min
else A
:= A
-1;
498 function Sign(A
: Integer): ShortInt;
500 if A
< 0 then Result
:= -1
501 else if A
> 0 then Result
:= 1
505 function Sign(A
: Single): ShortInt;
509 if Abs(A
) < Eps
then Result
:= 0
510 else if A
< 0 then Result
:= -1
514 function PointToRect(X
, Y
, X1
, Y1
: Integer; Width
, Height
: Word): Integer;
516 X
:= X
-X1
; // A(0;0) --- B(W;0)
521 if Y
< 0 then // Ñëåâà ñâåðõó: ðàññòîÿíèå äî A
522 Result
:= Round(Hypot(X
, Y
))
524 if Y
> Height
then // Ñëåâà ñíèçó: ðàññòîÿíèå äî D
525 Result
:= Round(Hypot(X
, Y
-Height
))
526 else // Ñëåâà ïîñåðåäèíå: ðàññòîÿíèå äî AD
533 if y
< 0 then // Ñïðàâà ñâåðõó: ðàññòîÿíèå äî B
534 Result
:= Round(Hypot(X
, Y
))
536 if Y
> Height
then // Ñïðàâà ñíèçó: ðàññòîÿíèå äî C
537 Result
:= Round(Hypot(X
, Y
-Height
))
538 else // Ñïðàâà ïîñåðåäèíå: ðàññòîÿíèå äî BC
543 if Y
< 0 then // Ïîñåðåäèíå ñâåðõó: ðàññòîÿíèå äî AB
546 if Y
> Height
then // Ïîñåðåäèíå ñíèçó: ðàññòîÿíèå äî DC
548 else // Âíóòðè ïðÿìîóãîëüíèêà: ðàññòîÿíèå 0
553 function g_GetAcidHit(X
, Y
: Integer; Width
, Height
: Word): Byte;
555 tab
: array[0..3] of Byte = (0, 5, 10, 20);
561 if g_Map_CollidePanel(X
, Y
, Width
, Height
, PANEL_ACID1
, False) then a
:= a
or 1;
562 if g_Map_CollidePanel(X
, Y
, Width
, Height
, PANEL_ACID2
, False) then a
:= a
or 2;
567 function GetAngle(baseX
, baseY
, pointX
, PointY
: Integer): SmallInt;
572 a
:= abs(pointX
-baseX
);
573 b
:= abs(pointY
-baseY
);
575 if a
= 0 then c
:= 90
576 else c
:= RadToDeg(ArcTan(b
/a
));
578 if pointY
< baseY
then c
:= -c
;
579 if pointX
> baseX
then c
:= 180-c
;
584 function GetAngle2(vx
, vy
: Integer): SmallInt;
595 c
:= RadToDeg(ArcTan(b
/a
));
607 {function g_CollideLine(x1, y1, x2, y2, rX, rY: Integer; rWidth, rHeight: Word): Boolean;
609 table: array[0..8, 0..8] of Byte =
610 ((0, 0, 3, 3, 1, 2, 2, 0, 1),
611 (0, 0, 0, 0, 4, 7, 2, 0, 1),
612 (3, 0, 0, 0, 4, 4, 1, 3, 1),
613 (3, 0, 0, 0, 0, 0, 5, 6, 1),
614 (1, 4, 4, 0, 0, 0, 5, 5, 1),
615 (2, 7, 4, 0, 0, 0, 0, 0, 1),
616 (2, 2, 1, 5, 5, 0, 0, 0, 1),
617 (0, 0, 3, 6, 5, 0, 0, 0, 1),
618 (1, 1, 1, 1, 1, 1, 1, 1, 1));
620 function GetClass(x, y: Integer): Byte;
624 if x < rX then Result := 7
625 else if x < rX+rWidth then Result := 0
628 else if y < rY+rHeight then
630 if x < rX then Result := 6
631 else if x < rX+rWidth then Result := 8
636 if x < rX then Result := 5
637 else if x < rX+rWidth then Result := 4
643 case table[GetClass(x1, y1), GetClass(x2, y2)] of
646 2: Result := Abs((rY-y1))/Abs((rX-x1)) <= Abs((y2-y1))/Abs((x2-x1));
647 3: Result := Abs((rY-y1))/Abs((rX+rWidth-x1)) <= Abs((y2-y1))/Abs((x2-x1));
648 4: Result := Abs((rY+rHeight-y1))/Abs((rX+rWidth-x1)) >= Abs((y2-y1))/Abs((x2-x1));
649 5: Result := Abs((rY+rHeight-y1))/Abs((rX-x1)) >= Abs((y2-y1))/Abs((x2-x1));
650 6: Result := (Abs((rY-y1))/Abs((rX+rWidth-x1)) <= Abs((y2-y1))/Abs((x2-x1))) and
651 (Abs((rY+rHeight-y1))/Abs((rX-x1)) >= Abs((y2-y1))/Abs((x2-x1)));
652 7: Result := (Abs((rY+rHeight-y1))/Abs((rX+rWidth-x1)) >= Abs((y2-y1))/Abs((x2-x1))) and
653 (Abs((rY-y1))/Abs((rX-x1)) <= Abs((y2-y1))/Abs((x2-x1)));
654 else Result := False;
658 function g_CollideLine(x1
, y1
, x2
, y2
, rX
, rY
: Integer; rWidth
, rHeight
: Word): Boolean;
668 result
:= lineAABBIntersects(x1
, y1
, x2
, y2
, rX
, rY
, rWidth
, rHeight
);
677 if dx > 0 then incX := 1 else if dx < 0 then incX := -1 else incX := 0;
678 if dy > 0 then incY := 1 else if dy < 0 then incY := -1 else incY := 0;
683 if dx > dy then d := dx else d := dy;
703 if (x >= rX) and (x <= (rX + rWidth - 1)) and
704 (y >= rY) and (y <= (rY + rHeight - 1)) then Exit;
711 function GetStr(var Str
: string): string;
716 for a
:= 1 to Length(Str
) do
717 if (a
= Length(Str
)) or (Str
[a
+1] = ' ') then
719 Result
:= Copy(Str
, 1, a
);
726 function Sscanf(const s
: String; const fmt
: String;
727 const Pointers
: array of Pointer): Integer;
734 function GetInt(): Integer;
737 while (n
<= Length(s
)) and (s
[n
] = ' ') do
740 while (n
<= Length(s
)) and (s
[n
] in ['0'..'9', '+', '-']) do
746 Result
:= Length(s1
);
749 function GetFloat(): Integer;
752 while (n
<= Length(s
)) and (s
[n
] = ' ') do
755 while (n
<= Length(s
)) and //jd >= rather than >
756 (s
[n
] in ['0'..'9', '+', '-', '.', 'e', 'E']) do
762 Result
:= Length(s1
);
765 function GetString(): Integer;
768 while (n
<= Length(s
)) and (s
[n
] = ' ') do
771 while (n
<= Length(s
)) and (s
[n
] <> ' ') do
777 Result
:= Length(s1
);
780 function ScanStr(c
: Char): Boolean;
782 while (n
<= Length(s
)) and (s
[n
] <> c
) do
786 Result
:= (n
<= Length(s
));
789 function GetFmt(): Integer;
795 while (fmt
[m
] = ' ') and (m
< Length(fmt
)) do
797 if (m
>= Length(fmt
)) then
800 if (fmt
[m
] = '%') then
804 'd': Result
:= vtInteger
;
805 'f': Result
:= vtExtended
;
806 's': Result
:= vtString
;
812 if (not ScanStr(fmt
[m
])) then
824 for i
:= 0 to High(Pointers
) do
833 L
:= StrToIntDef(s1
, 0);
834 Move(L
, Pointers
[i
]^, SizeOf(LongInt));
843 if GetFloat() > 0 then
845 X
:= StrToFloatDef(s1
, 0.0);
846 Move(X
, Pointers
[i
]^, SizeOf(Extended
));
855 if GetString() > 0 then
857 Move(s1
, Pointers
[i
]^, Length(s1
)+1);
870 function InDWArray(a
: DWORD
; arr
: DWArray
): Boolean;
876 if arr
= nil then Exit
;
878 for b
:= 0 to High(arr
) do
886 function InWArray(a
: Word; arr
: WArray
): Boolean;
892 if arr
= nil then Exit
;
894 for b
:= 0 to High(arr
) do
902 function InSArray(a
: string; arr
: SSArray
): Boolean;
908 if arr
= nil then Exit
;
910 a
:= AnsiLowerCase(a
);
912 for b
:= 0 to High(arr
) do
913 if AnsiLowerCase(arr
[b
]) = a
then
920 function GetPos(UID
: Word; o
: PObj
): Boolean;
927 case g_GetUIDType(UID
) of
930 p
:= g_Player_Get(UID
);
931 if p
= nil then Exit
;
932 if not p
.alive
then Exit
;
939 m
:= g_Monsters_ByUID(UID
);
940 if m
= nil then Exit
;
941 if not m
.alive
then Exit
;
951 function parse(s
: String): SSArray
;
961 for a
:= 1 to Length(s
) do
962 if (s
[a
] = ',') or (a
= Length(s
)) then
964 SetLength(Result
, Length(Result
)+1);
967 Result
[High(Result
)] := Copy(s
, 1, a
-1)
969 Result
[High(Result
)] := s
;
977 function parse2(s
: string; delim
: Char): SSArray
;
986 for a
:= 1 to Length(s
) do
987 if (s
[a
] = delim
) or (a
= Length(s
)) then
989 SetLength(Result
, Length(Result
)+1);
991 if s
[a
] = delim
then Result
[High(Result
)] := Copy(s
, 1, a
-1)
992 else Result
[High(Result
)] := s
;
1000 function g_GetFileTime(fileName
: String): Integer;
1004 if not FileExists(fileName
) then
1010 AssignFile(F
, fileName
);
1012 Result
:= FileGetDate(TFileRec(F
).Handle
);
1016 function g_SetFileTime(fileName
: String; time
: Integer): Boolean;
1020 if (not FileExists(fileName
)) or (time
< 0) then
1026 AssignFile(F
, fileName
);
1028 Result
:= (FileSetDate(TFileRec(F
).Handle
, time
) = 0);
1032 procedure SortSArray(var S
: SSArray
);
1040 for i
:= Low(S
) to High(S
) - 1 do
1041 if S
[i
] > S
[i
+ 1] then begin
1050 function b_Text_Format(S
: string): string;
1058 for I
:= 1 to Length(S
) do
1060 if (not Spec
) and (S
[I
] = '\') and (I
+ 1 <= Length(S
)) then
1070 Result
:= Result
+ #10;
1072 Result
:= Result
+ #1;
1074 Result
:= Result
+ #2;
1076 Result
:= Result
+ #3;
1078 Result
:= Result
+ #4;
1080 Result
:= Result
+ #18;
1082 Result
:= Result
+ #19;
1084 Result
:= Result
+ #20;
1086 Result
:= Result
+ #21;
1088 Result
:= Result
+ '\';
1090 Result
:= Result
+ '\' + S
[I
];
1094 Result
:= Result
+ S
[I
];
1096 // reset to white at end
1097 if Rst
then Result
:= Result
+ #2;
1100 function b_Text_Unformat(S
: string): string;
1107 for I
:= 1 to Length(S
) do
1109 if S
[I
] in [#1, #2, #3, #4, #10, #18, #19, #20, #21] then
1114 if (not Spec
) and (S
[I
] = '\') and (I
+ 1 <= Length(S
)) then
1131 '\': Result
:= Result
+ '\';
1133 Result
:= Result
+ '\' + S
[I
];
1137 Result
:= Result
+ S
[I
];
1141 function b_Text_Wrap(S
: string; LineLen
: Integer): string;
1143 Result
:= WrapText(S
, ''#10, [#10, ' ', '-'], LineLen
);
1146 function b_Text_LineCount(S
: string): Integer;
1150 Result
:= IfThen(S
= '', 0, 1);
1151 for I
:= 1 to High(S
) do