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; // TODO: eliminate
38 DWArray
= array of DWORD
; // TODO: eliminate
40 function g_GetBuilderName (): AnsiString
;
41 function g_GetBuildHash (full
: Boolean = True): AnsiString
;
42 function g_GetBuildArch (): AnsiString
;
44 function g_CreateUID(UIDType
: Byte): Word;
45 function g_GetUIDType(UID
: Word): Byte;
46 function g_Collide(X1
, Y1
: Integer; Width1
, Height1
: Word;
47 X2
, Y2
: Integer; Width2
, Height2
: Word): Boolean; inline;
48 function g_CollideLine(x1
, y1
, x2
, y2
, rX
, rY
: Integer; rWidth
, rHeight
: Word): Boolean;
49 function g_CollidePoint(X
, Y
, X2
, Y2
: Integer; Width
, Height
: Word): Boolean; inline;
50 function g_CollideLevel(X
, Y
: Integer; Width
, Height
: Word): Boolean; inline;
51 function g_CollideAround(X1
, Y1
: Integer; Width1
, Height1
: Word;
52 X2
, Y2
: Integer; Width2
, Height2
: Word): Boolean; inline;
53 function g_CollidePlayer(X
, Y
: Integer; Width
, Height
: Word): Boolean; inline;
54 function g_PatchLength(X1
, Y1
, X2
, Y2
: Integer): Word;
55 function g_TraceVector(X1
, Y1
, X2
, Y2
: Integer): Boolean; // `true`: no wall hit
56 function g_GetAcidHit(X
, Y
: Integer; Width
, Height
: Word): Byte;
57 function g_Look(a
, b
: PObj
; d
: TDirection
): Boolean;
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 GetLines(Text: string; FontID
: DWORD
; MaxWidth
: Word): SSArray
;
80 function InDWArray(a
: DWORD
; arr
: DWArray
): Boolean; // TODO: eliminate
81 function InWArray(a
: Word; arr
: WArray
): Boolean; // TODO: eliminate
82 function InSArray(a
: string; arr
: SSArray
): Boolean; // TODO: eliminate
83 function GetPos(UID
: Word; o
: PObj
): Boolean;
84 function parse(s
: string): SSArray
;
85 function parse2(s
: string; delim
: Char): SSArray
;
86 function g_GetFileTime(fileName
: String): Integer;
87 function g_SetFileTime(fileName
: String; time
: Integer): Boolean;
88 function b_Text_Format(S
: string): string;
89 function b_Text_Unformat(S
: string): string;
90 function b_Text_Wrap(S
: string; LineLen
: Integer): string;
91 function b_Text_LineCount(S
: string): Integer;
94 gmon_dbg_los_enabled
: Boolean = True;
99 Math
, geom
, e_log
, g_map
, g_gfx
, g_player
, SysUtils
, MAPDEF
,
100 StrUtils
, e_graphics
, g_monsters
, g_items
, g_game
;
103 {$WARN 2054 OFF} // unknown env var
104 {$WARN 6018 OFF} // unreachable code
105 function g_GetBuilderName (): AnsiString
;
107 if {$I %D2DF_BUILD_USER%} <> '' then
108 result
:= {$I %D2DF_BUILD_USER%} // custom
109 else if {$I %USER%} <> '' then
110 result
:= {$I %USER%} // unix username
111 else if {$I %USERNAME%} <> '' then
112 result
:= {$I %USERNAME%} // windows username
117 function g_GetBuildHash (full
: Boolean): AnsiString
;
119 if {$I %D2DF_BUILD_HASH%} <> '' then
121 result
:= {$I %D2DF_BUILD_HASH%}
123 result
:= Copy({$I %D2DF_BUILD_HASH%}, 1, 7)
125 result
:= 'custom build'
129 function g_GetBuildArch (): AnsiString
;
131 cpu
, mode
, fpu
: AnsiString
;
133 cpu
:= {$IF DEFINED(CPUX86_64) OR DEFINED(CPUAMD64) OR DEFINED(CPUX64)}
134 'x86_64' {$ELSEIF DEFINED(CPUI386) OR DEFINED(CPU386)}
135 'x86' {$ELSEIF DEFINED(CPUI8086)}
136 'i8086' {$ELSEIF DEFINED(CPUI64)}
137 'Itanium64' {$ELSEIF DEFINED(CPUARM)}
138 'ARM' {$ELSEIF DEFINED(CPUAVR)}
139 'AVR' {$ELSEIF DEFINED(CPUPOWERPC32)}
140 'PowerPC_32' {$ELSEIF DEFINED(CPUPOWERPC64)}
141 'PowerPC_64' {$ELSEIF DEFINED(CPUALPHA)}}
142 'Alpha' {$ELSEIF DEFINED(CPUSPARC32)}
143 'Sparc32' {$ELSEIF DEFINED(CPUM68020)}
144 'M68020' {$ELSEIF DEFINED(CPU68K) OR DEFINED(CPUM68K)}
145 'm68k' {$ELSEIF DEFINED(CPUSPARC)}
146 'unknown-sparc' {$ELSEIF DEFINED(CPUPOWERPC)}
147 'unknown-ppc' {$ELSEIF DEFINED(CPU86) OR DEFINED(CPU87)}
148 'unknown-intel' {$ELSE}
149 'unknown-arch' {$ENDIF};
151 mode
:= {$IF DEFINED(CPU64)}
152 '64-bit' {$ELSEIF DEFINED(CPU32)}
153 '32-bit' {$ELSEIF DEFINED(CPU16)}
155 'unknown-mode' {$ENDIF};
157 fpu
:= {$IF DEFINED(FPUSOFT)}
158 'soft' {$ELSEIF DEFINED(FPUSSE3)}
159 'sse3' {$ELSEIF DEFINED(FPUSSE2)}
160 'sse2' {$ELSEIF DEFINED(FPUSSE)}
161 'sse' {$ELSEIF DEFINED(FPUSSE64)}
162 'sse64' {$ELSEIF DEFINED(FPULIBGCC)}
163 'libgcc' {$ELSEIF DEFINED(FPU68881)}
164 '68881' {$ELSEIF DEFINED(FPUVFP)}
165 'vfp' {$ELSEIF DEFINED(FPUFPA11)}
166 'fpa11' {$ELSEIF DEFINED(FPUFPA10)}
167 'fpa10' {$ELSEIF DEFINED(FPUFPA)}
168 'fpa' {$ELSEIF DEFINED(FPUX87)}
169 'x87' {$ELSEIF DEFINED(FPUITANIUM)}
170 'itanium' {$ELSEIF DEFINED(FPUSTANDARD)}
171 'standard' {$ELSEIF DEFINED(FPUHARD)}
173 'unknown-fpu' {$ENDIF};
175 Result
:= cpu
+ ' ' + mode
+ ' ' + fpu
;
178 function g_PatchLength(X1
, Y1
, X2
, Y2
: Integer): Word;
180 Result
:= Min(Round(Hypot(Abs(X2
-X1
), Abs(Y2
-Y1
))), 65535);
183 function g_CollideLevel(X
, Y
: Integer; Width
, Height
: Word): Boolean; inline;
185 result
:= g_Map_CollidePanel(X
, Y
, Width
, Height
, (PANEL_WALL
or PANEL_CLOSEDOOR
or PANEL_OPENDOOR
), False);
196 for a := 0 to High(gWalls) do
197 if gWalls[a].Enabled and
198 not ( ((Y + Height <= gWalls[a].Y) or
199 (Y >= gWalls[a].Y + gWalls[a].Height)) or
200 ((X + Width <= gWalls[a].X) or
201 (X >= gWalls[a].X + gWalls[a].Width)) ) then
209 function g_CollidePlayer(X
, Y
: Integer; Width
, Height
: Word): Boolean; inline;
214 for a
:= 0 to High(gPlayers
) do
215 if (gPlayers
[a
] <> nil) and gPlayers
[a
].alive
then
216 if gPlayers
[a
].Collide(X
, Y
, Width
, Height
) then
220 function g_TraceVector(X1
, Y1
, X2
, Y2
: Integer): Boolean;
222 wallHitX
: Integer = 0;
223 wallHitY
: Integer = 0;
227 Xerr, Yerr, d: LongWord;
235 Assert(gCollideMap <> nil, 'g_TraceVector: gCollideMap = nil');
242 if dx > 0 then incX := 1 else if dx < 0 then incX := -1 else incX := 0;
243 if dy > 0 then incY := 1 else if dy < 0 then incY := -1 else incY := 0;
248 if dx > dy then d := dx else d := dy;
268 if (y > gMapInfo.Height-1) or
269 (y < 0) or (x > gMapInfo.Width-1) or (x < 0) then
271 if ByteBool(gCollideMap[y, x] and MARK_BLOCKED) then
278 // `true` if no obstacles
279 if (g_profile_los
) then g_Mons_LOS_Start();
280 result
:= (g_Map_traceToNearestWall(x1
, y1
, x2
, y2
, @wallHitX
, @wallHitY
) = nil);
281 if (g_profile_los
) then g_Mons_LOS_End();
284 function g_CreateUID(UIDType
: Byte): Word;
295 Result
:= UID_MAX_GAME
+$1+Random(UID_MAX_PLAYER
-UID_MAX_GAME
+$1);
298 if gPlayers
<> nil then
299 for i
:= 0 to High(gPlayers
) do
300 if gPlayers
[i
] <> nil then
301 if Result
= gPlayers
[i
].UID
then
314 result
:= UID_MAX_PLAYER
+$1+Random(UID_MAX_MONSTER
-UID_MAX_GAME
-UID_MAX_PLAYER
+$1);
315 if (g_Monsters_ByUID(result
) = nil) then break
;
321 function g_GetUIDType(UID
: Word): Byte;
323 if UID
<= UID_MAX_GAME
then
325 else if UID
<= UID_MAX_PLAYER
then
328 Result
:= UID_MONSTER
;
331 function g_Collide(X1
, Y1
: Integer; Width1
, Height1
: Word;
332 X2
, Y2
: Integer; Width2
, Height2
: Word): Boolean; inline;
334 Result
:= not ( ((Y1
+ Height1
<= Y2
) or
335 (Y2
+ Height2
<= Y1
)) or
336 ((X1
+ Width1
<= X2
) or
337 (X2
+ Width2
<= X1
)) );
340 function g_CollideAround(X1
, Y1
: Integer; Width1
, Height1
: Word;
341 X2
, Y2
: Integer; Width2
, Height2
: Word): Boolean; inline;
343 Result
:= g_Collide(X1
, Y1
, Width1
, Height1
, X2
, Y2
, Width2
, Height2
) or
344 g_Collide(X1
+1, Y1
, Width1
, Height1
, X2
, Y2
, Width2
, Height2
) or
345 g_Collide(X1
-1, Y1
, Width1
, Height1
, X2
, Y2
, Width2
, Height2
) or
346 g_Collide(X1
, Y1
+1, Width1
, Height1
, X2
, Y2
, Width2
, Height2
) or
347 g_Collide(X1
, Y1
-1, Width1
, Height1
, X2
, Y2
, Width2
, Height2
);
350 function c(X1
, Y1
, Width1
, Height1
, X2
, Y2
, Width2
, Height2
: Integer): Boolean; inline;
352 Result
:= not (((Y1
+ Height1
<= Y2
) or
353 (Y1
>= Y2
+ Height2
)) or
354 ((X1
+ Width1
<= X2
) or
355 (X1
>= X2
+ Width2
)));
358 function g_Collide2(X1
, Y1
, X2
, Y2
, X3
, Y3
, X4
, Y4
: Integer): Boolean; inline;
360 //Result := not (((Y2 <= Y3) or (Y1 >= Y4)) or ((X2 <= X3) or (X1 >= X4)));
361 Result
:= c(X1
, Y1
, X2
-X1
, Y2
-Y1
, X3
, Y3
, X4
-X3
, Y4
-Y3
);
364 function g_CollidePoint(X
, Y
, X2
, Y2
: Integer; Width
, Height
: Word): Boolean; inline;
368 Result
:= (x
>= 0) and (x
<= Width
) and
369 (y
>= 0) and (y
<= Height
);
372 procedure IncMax(var A
: Integer; B
, Max
: Integer);
374 if A
+B
> Max
then A
:= Max
else A
:= A
+B
;
377 procedure IncMax(var A
: Single; B
, Max
: Single);
379 if A
+B
> Max
then A
:= Max
else A
:= A
+B
;
382 procedure DecMin(var A
: Integer; B
, Min
: Integer);
384 if A
-B
< Min
then A
:= Min
else A
:= A
-B
;
387 procedure DecMin(var A
: Word; B
, Min
: Word);
389 if A
-B
< Min
then A
:= Min
else A
:= A
-B
;
392 procedure DecMin(var A
: Single; B
, Min
: Single);
394 if A
-B
< Min
then A
:= Min
else A
:= A
-B
;
397 procedure IncMax(var A
: Integer; Max
: Integer);
399 if A
+1 > Max
then A
:= Max
else A
:= A
+1;
402 procedure IncMax(var A
: Single; Max
: Single);
404 if A
+1 > Max
then A
:= Max
else A
:= A
+1;
407 procedure IncMax(var A
: Word; B
, Max
: Word);
409 if A
+B
> Max
then A
:= Max
else A
:= A
+B
;
412 procedure IncMax(var A
: Word; Max
: Word);
414 if A
+1 > Max
then A
:= Max
else A
:= A
+1;
417 procedure IncMax(var A
: SmallInt
; B
, Max
: SmallInt
);
419 if A
+B
> Max
then A
:= Max
else A
:= A
+B
;
422 procedure IncMax(var A
: SmallInt
; Max
: SmallInt
);
424 if A
+1 > Max
then A
:= Max
else A
:= A
+1;
427 procedure DecMin(var A
: Integer; Min
: Integer);
429 if A
-1 < Min
then A
:= Min
else A
:= A
-1;
432 procedure DecMin(var A
: Single; Min
: Single);
434 if A
-1 < Min
then A
:= Min
else A
:= A
-1;
437 procedure DecMin(var A
: Word; Min
: Word);
439 if A
-1 < Min
then A
:= Min
else A
:= A
-1;
442 procedure DecMin(var A
: Byte; B
, Min
: Byte);
444 if A
-B
< Min
then A
:= Min
else A
:= A
-B
;
447 procedure DecMin(var A
: Byte; Min
: Byte); overload
;
449 if A
-1 < Min
then A
:= Min
else A
:= A
-1;
452 function Sign(A
: Integer): ShortInt
;
454 if A
< 0 then Result
:= -1
455 else if A
> 0 then Result
:= 1
459 function Sign(A
: Single): ShortInt
;
463 if Abs(A
) < Eps
then Result
:= 0
464 else if A
< 0 then Result
:= -1
468 function PointToRect(X
, Y
, X1
, Y1
: Integer; Width
, Height
: Word): Integer;
470 X
:= X
-X1
; // A(0;0) --- B(W;0)
475 if Y
< 0 then // Ñëåâà ñâåðõó: ðàññòîÿíèå äî A
476 Result
:= Round(Hypot(X
, Y
))
478 if Y
> Height
then // Ñëåâà ñíèçó: ðàññòîÿíèå äî D
479 Result
:= Round(Hypot(X
, Y
-Height
))
480 else // Ñëåâà ïîñåðåäèíå: ðàññòîÿíèå äî AD
487 if y
< 0 then // Ñïðàâà ñâåðõó: ðàññòîÿíèå äî B
488 Result
:= Round(Hypot(X
, Y
))
490 if Y
> Height
then // Ñïðàâà ñíèçó: ðàññòîÿíèå äî C
491 Result
:= Round(Hypot(X
, Y
-Height
))
492 else // Ñïðàâà ïîñåðåäèíå: ðàññòîÿíèå äî BC
497 if Y
< 0 then // Ïîñåðåäèíå ñâåðõó: ðàññòîÿíèå äî AB
500 if Y
> Height
then // Ïîñåðåäèíå ñíèçó: ðàññòîÿíèå äî DC
502 else // Âíóòðè ïðÿìîóãîëüíèêà: ðàññòîÿíèå 0
507 function g_GetAcidHit(X
, Y
: Integer; Width
, Height
: Word): Byte;
509 tab
: array[0..3] of Byte = (0, 5, 10, 20);
515 if g_Map_CollidePanel(X
, Y
, Width
, Height
, PANEL_ACID1
, False) then a
:= a
or 1;
516 if g_Map_CollidePanel(X
, Y
, Width
, Height
, PANEL_ACID2
, False) then a
:= a
or 2;
521 function g_Look(a
, b
: PObj
; d
: TDirection
): Boolean;
523 if not gmon_dbg_los_enabled
then
524 Exit(False); // always "wall hit"
526 if ((b
^.X
> a
^.X
) and (d
= TDirection
.D_LEFT
)) or
527 ((b
^.X
< a
^.X
) and (d
= TDirection
.D_RIGHT
)) then
530 Result
:= g_TraceVector(a
^.X
+a
^.Rect
.X
+(a
^.Rect
.Width
div 2),
531 a
^.Y
+a
^.Rect
.Y
+(a
^.Rect
.Height
div 2),
532 b
^.X
+b
^.Rect
.X
+(b
^.Rect
.Width
div 2),
533 b
^.Y
+b
^.Rect
.Y
+(b
^.Rect
.Height
div 2));
536 function GetAngle(baseX
, baseY
, pointX
, PointY
: Integer): SmallInt
;
541 a
:= abs(pointX
-baseX
);
542 b
:= abs(pointY
-baseY
);
544 if a
= 0 then c
:= 90
545 else c
:= RadToDeg(ArcTan(b
/a
));
547 if pointY
< baseY
then c
:= -c
;
548 if pointX
> baseX
then c
:= 180-c
;
553 function GetAngle2(vx
, vy
: Integer): SmallInt
;
563 else c
:= RadToDeg(ArcTan(b
/a
));
575 {function g_CollideLine(x1, y1, x2, y2, rX, rY: Integer; rWidth, rHeight: Word): Boolean;
577 table: array[0..8, 0..8] of Byte =
578 ((0, 0, 3, 3, 1, 2, 2, 0, 1),
579 (0, 0, 0, 0, 4, 7, 2, 0, 1),
580 (3, 0, 0, 0, 4, 4, 1, 3, 1),
581 (3, 0, 0, 0, 0, 0, 5, 6, 1),
582 (1, 4, 4, 0, 0, 0, 5, 5, 1),
583 (2, 7, 4, 0, 0, 0, 0, 0, 1),
584 (2, 2, 1, 5, 5, 0, 0, 0, 1),
585 (0, 0, 3, 6, 5, 0, 0, 0, 1),
586 (1, 1, 1, 1, 1, 1, 1, 1, 1));
588 function GetClass(x, y: Integer): Byte;
592 if x < rX then Result := 7
593 else if x < rX+rWidth then Result := 0
596 else if y < rY+rHeight then
598 if x < rX then Result := 6
599 else if x < rX+rWidth then Result := 8
604 if x < rX then Result := 5
605 else if x < rX+rWidth then Result := 4
611 case table[GetClass(x1, y1), GetClass(x2, y2)] of
614 2: Result := Abs((rY-y1))/Abs((rX-x1)) <= Abs((y2-y1))/Abs((x2-x1));
615 3: Result := Abs((rY-y1))/Abs((rX+rWidth-x1)) <= Abs((y2-y1))/Abs((x2-x1));
616 4: Result := Abs((rY+rHeight-y1))/Abs((rX+rWidth-x1)) >= Abs((y2-y1))/Abs((x2-x1));
617 5: Result := Abs((rY+rHeight-y1))/Abs((rX-x1)) >= Abs((y2-y1))/Abs((x2-x1));
618 6: Result := (Abs((rY-y1))/Abs((rX+rWidth-x1)) <= Abs((y2-y1))/Abs((x2-x1))) and
619 (Abs((rY+rHeight-y1))/Abs((rX-x1)) >= Abs((y2-y1))/Abs((x2-x1)));
620 7: Result := (Abs((rY+rHeight-y1))/Abs((rX+rWidth-x1)) >= Abs((y2-y1))/Abs((x2-x1))) and
621 (Abs((rY-y1))/Abs((rX-x1)) <= Abs((y2-y1))/Abs((x2-x1)));
622 else Result := False;
626 function g_CollideLine(x1
, y1
, x2
, y2
, rX
, rY
: Integer; rWidth
, rHeight
: Word): Boolean;
636 result
:= lineAABBIntersects(x1
, y1
, x2
, y2
, rX
, rY
, rWidth
, rHeight
);
645 if dx > 0 then incX := 1 else if dx < 0 then incX := -1 else incX := 0;
646 if dy > 0 then incY := 1 else if dy < 0 then incY := -1 else incY := 0;
651 if dx > dy then d := dx else d := dy;
671 if (x >= rX) and (x <= (rX + rWidth - 1)) and
672 (y >= rY) and (y <= (rY + rHeight - 1)) then Exit;
679 function GetStr(var Str
: string): string;
684 for a
:= 1 to Length(Str
) do
685 if (a
= Length(Str
)) or (Str
[a
+1] = ' ') then
687 Result
:= Copy(Str
, 1, a
);
694 function GetLines (text: string; FontID
: DWORD
; MaxWidth
: Word): SSArray
;
698 i
, len
, lastsep
: Integer;
700 function PrepareStep (): Boolean; inline;
702 // Skip leading spaces.
703 while PChar(text)[k
-1] = ' ' do k
+= 1;
708 function GetLine (j
: Integer; Strip
: Boolean): String; inline;
710 // Exclude trailing spaces from the line.
712 while text[j
] = ' ' do j
-= 1;
714 Result
:= Copy(text, k
, j
-k
+1);
717 function LineWidth (): Integer; inline;
720 e_CharFont_GetSize(FontID
, GetLine(i
, False), w
, h
);
727 //e_LogWritefln('GetLines @%s len=%s [%s]', [MaxWidth, len, text]);
729 while PrepareStep() do
731 // Get longest possible sequence (this is not constant because fonts are not monospaced).
734 if text[i
] in [' ', '.', ',', ':', ';']
737 until (i
> len
) or (LineWidth() > MaxWidth
);
739 // Do not include part of a word if possible.
740 if (lastsep
-k
> 3) and (i
<= len
) and (text[i
] <> ' ')
741 then i
:= lastsep
+ 1;
744 SetLength(Result
, lines
+ 1);
745 Result
[lines
] := GetLine(i
-1, True);
746 //e_LogWritefln(' -> (%s:%s::%s) [%s]', [k, i, LineWidth(), Result[lines]]);
753 function InDWArray(a
: DWORD
; arr
: DWArray
): Boolean;
759 if arr
= nil then Exit
;
761 for b
:= 0 to High(arr
) do
769 function InWArray(a
: Word; arr
: WArray
): Boolean;
775 if arr
= nil then Exit
;
777 for b
:= 0 to High(arr
) do
785 function InSArray(a
: string; arr
: SSArray
): Boolean;
791 if arr
= nil then Exit
;
793 a
:= AnsiLowerCase(a
);
795 for b
:= 0 to High(arr
) do
796 if AnsiLowerCase(arr
[b
]) = a
then
803 function GetPos(UID
: Word; o
: PObj
): Boolean;
810 case g_GetUIDType(UID
) of
813 p
:= g_Player_Get(UID
);
814 if p
= nil then Exit
;
815 if not p
.alive
then Exit
;
822 m
:= g_Monsters_ByUID(UID
);
823 if m
= nil then Exit
;
824 if not m
.alive
then Exit
;
834 function parse(s
: String): SSArray
;
844 for a
:= 1 to Length(s
) do
845 if (s
[a
] = ',') or (a
= Length(s
)) then
847 SetLength(Result
, Length(Result
)+1);
850 Result
[High(Result
)] := Copy(s
, 1, a
-1)
852 Result
[High(Result
)] := s
;
860 function parse2(s
: string; delim
: Char): SSArray
;
869 for a
:= 1 to Length(s
) do
870 if (s
[a
] = delim
) or (a
= Length(s
)) then
872 SetLength(Result
, Length(Result
)+1);
874 if s
[a
] = delim
then Result
[High(Result
)] := Copy(s
, 1, a
-1)
875 else Result
[High(Result
)] := s
;
883 function g_GetFileTime(fileName
: String): Integer;
887 if not FileExists(fileName
) then
893 AssignFile(F
, fileName
);
895 Result
:= FileGetDate(TFileRec(F
).Handle
);
899 function g_SetFileTime(fileName
: String; time
: Integer): Boolean;
903 if (not FileExists(fileName
)) or (time
< 0) then
909 AssignFile(F
, fileName
);
911 Result
:= (FileSetDate(TFileRec(F
).Handle
, time
) = 0);
915 function b_Text_Format(S
: string): string;
923 for I
:= 1 to Length(S
) do
925 if (not Spec
) and (S
[I
] = '\') and (I
+ 1 <= Length(S
)) then
935 Result
:= Result
+ #10;
937 Result
:= Result
+ #1;
939 Result
:= Result
+ #2;
941 Result
:= Result
+ #3;
943 Result
:= Result
+ #4;
945 Result
:= Result
+ #18;
947 Result
:= Result
+ #19;
949 Result
:= Result
+ #20;
951 Result
:= Result
+ #21;
953 Result
:= Result
+ '\';
955 Result
:= Result
+ '\' + S
[I
];
959 Result
:= Result
+ S
[I
];
961 // reset to white at end
962 if Rst
then Result
:= Result
+ #2;
965 function b_Text_Unformat(S
: string): string;
972 for I
:= 1 to Length(S
) do
974 if S
[I
] in [#1, #2, #3, #4, #10, #18, #19, #20, #21] then
979 if (not Spec
) and (S
[I
] = '\') and (I
+ 1 <= Length(S
)) then
998 Result
+= '\' + S
[I
];
1006 function b_Text_Wrap(S
: string; LineLen
: Integer): string;
1008 Result
:= WrapText(S
, ''#10, [#10, ' ', '-'], LineLen
);
1011 function b_Text_LineCount(S
: string): Integer;
1015 Result
:= IfThen(S
= '', 0, 1);
1016 for I
:= 1 to High(S
) do