1 (* |
1 (* |
2 * Hedgewars, a free turn based strategy game |
2 * Hedgewars, a free turn based strategy game |
3 * Copyright (c) 2004-2013 Andrey Korotaev <unC0Rr@gmail.com> |
3 * Copyright (c) 2004-2015 Andrey Korotaev <unC0Rr@gmail.com> |
4 * |
4 * |
5 * This program is free software; you can redistribute it and/or modify |
5 * This program is free software; you can redistribute it and/or modify |
6 * it under the terms of the GNU General Public License as published by |
6 * it under the terms of the GNU General Public License as published by |
7 * the Free Software Foundation; version 2 of the License |
7 * the Free Software Foundation; version 2 of the License |
8 * |
8 * |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 * GNU General Public License for more details. |
12 * GNU General Public License for more details. |
13 * |
13 * |
14 * You should have received a copy of the GNU General Public License |
14 * You should have received a copy of the GNU General Public License |
15 * along with this program; if not, write to the Free Software |
15 * along with this program; if not, write to the Free Software |
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
17 *) |
17 *) |
18 |
18 |
19 {$INCLUDE "options.inc"} |
19 {$INCLUDE "options.inc"} |
20 |
20 |
21 unit uUtils; |
21 unit uUtils; |
23 interface |
23 interface |
24 uses uTypes, uFloat; |
24 uses uTypes, uFloat; |
25 |
25 |
26 procedure SplitBySpace(var a, b: shortstring); |
26 procedure SplitBySpace(var a, b: shortstring); |
27 procedure SplitByChar(var a, b: shortstring; c: char); |
27 procedure SplitByChar(var a, b: shortstring; c: char); |
28 procedure SplitByChar(var a, b: ansistring; c: char); |
28 procedure SplitByCharA(var a, b: ansistring; c: char); |
29 |
29 |
30 function EnumToStr(const en : TGearType) : shortstring; overload; |
30 function EnumToStr(const en : TGearType) : shortstring; overload; |
31 function EnumToStr(const en : TVisualGearType) : shortstring; overload; |
31 function EnumToStr(const en : TVisualGearType) : shortstring; overload; |
32 function EnumToStr(const en : TSound) : shortstring; overload; |
32 function EnumToStr(const en : TSound) : shortstring; overload; |
33 function EnumToStr(const en : TAmmoType) : shortstring; overload; |
33 function EnumToStr(const en : TAmmoType) : shortstring; overload; |
34 function EnumToStr(const en : TStatInfoType) : shortstring; overload; |
34 function EnumToStr(const en : TStatInfoType) : shortstring; overload; |
35 function EnumToStr(const en : THogEffect) : shortstring; overload; |
35 function EnumToStr(const en : THogEffect) : shortstring; overload; |
36 function EnumToStr(const en : TCapGroup) : shortstring; overload; |
36 function EnumToStr(const en : TCapGroup) : shortstring; overload; |
|
37 function EnumToStr(const en : TSprite) : shortstring; overload; |
|
38 function EnumToStr(const en : TMapGen) : shortstring; overload; |
37 |
39 |
38 function Min(a, b: LongInt): LongInt; inline; |
40 function Min(a, b: LongInt): LongInt; inline; |
|
41 function MinD(a, b: double) : double; inline; |
39 function Max(a, b: LongInt): LongInt; inline; |
42 function Max(a, b: LongInt): LongInt; inline; |
40 |
43 |
41 function IntToStr(n: LongInt): shortstring; |
44 function IntToStr(n: LongInt): shortstring; |
42 function StrToInt(s: shortstring): LongInt; |
45 function StrToInt(s: shortstring): LongInt; |
43 function FloatToStr(n: hwFloat): shortstring; |
46 function FloatToStr(n: hwFloat): shortstring; |
65 function CheckNoTeamOrHH: boolean; inline; |
68 function CheckNoTeamOrHH: boolean; inline; |
66 |
69 |
67 function GetLaunchX(at: TAmmoType; dir: LongInt; angle: LongInt): LongInt; |
70 function GetLaunchX(at: TAmmoType; dir: LongInt; angle: LongInt): LongInt; |
68 function GetLaunchY(at: TAmmoType; angle: LongInt): LongInt; |
71 function GetLaunchY(at: TAmmoType; angle: LongInt): LongInt; |
69 |
72 |
|
73 {$IFNDEF PAS2C} |
70 procedure Write(var f: textfile; s: shortstring); |
74 procedure Write(var f: textfile; s: shortstring); |
71 procedure WriteLn(var f: textfile; s: shortstring); |
75 procedure WriteLn(var f: textfile; s: shortstring); |
|
76 function StrLength(s: PChar): Longword; |
|
77 procedure SetLengthA(var s: ansistring; len: Longword); |
|
78 {$ENDIF} |
72 |
79 |
73 function isPhone: Boolean; inline; |
80 function isPhone: Boolean; inline; |
74 |
81 |
75 {$IFDEF IPHONEOS} |
82 {$IFDEF IPHONEOS} |
76 procedure startLoadingIndicator; cdecl; external; |
83 procedure startLoadingIndicator; cdecl; external; |
86 procedure initModule(isNotPreview: boolean); |
93 procedure initModule(isNotPreview: boolean); |
87 procedure freeModule; |
94 procedure freeModule; |
88 |
95 |
89 |
96 |
90 implementation |
97 implementation |
91 uses typinfo, Math, uConsts, uVariables, SysUtils; |
98 uses {$IFNDEF PAS2C}typinfo, {$ENDIF}Math, uConsts, uVariables, SysUtils; |
92 |
99 |
93 {$IFDEF DEBUGFILE} |
100 {$IFDEF DEBUGFILE} |
94 var f: textfile; |
101 var logFile: textfile; |
95 {$IFDEF USE_VIDEO_RECORDING} |
102 {$IFDEF USE_VIDEO_RECORDING} |
96 logMutex: TRTLCriticalSection; // mutex for debug file |
103 logMutex: TRTLCriticalSection; // mutex for debug file |
97 {$ENDIF} |
104 {$ENDIF} |
98 {$ENDIF} |
105 {$ENDIF} |
99 var CharArray: array[byte] of Char; |
106 var CharArray: array[0..255] of Char; |
100 |
107 |
101 procedure SplitBySpace(var a,b: shortstring); |
108 procedure SplitBySpace(var a,b: shortstring); |
102 begin |
109 begin |
103 SplitByChar(a,b,' '); |
110 SplitByChar(a,b,' '); |
104 end; |
111 end; |
113 for t:= 1 to Pred(i) do |
120 for t:= 1 to Pred(i) do |
114 if (a[t] >= 'A')and(a[t] <= 'Z') then |
121 if (a[t] >= 'A')and(a[t] <= 'Z') then |
115 Inc(a[t], 32); |
122 Inc(a[t], 32); |
116 b:= copy(a, i + 1, Length(a) - i); |
123 b:= copy(a, i + 1, Length(a) - i); |
117 a[0]:= char(Pred(i)) |
124 a[0]:= char(Pred(i)) |
|
125 {$IFDEF PAS2C} |
|
126 a[i] := 0; |
|
127 {$ENDIF} |
118 end |
128 end |
119 else |
129 else |
120 b:= ''; |
130 b:= ''; |
121 end; |
131 end; |
122 |
132 |
123 procedure SplitByChar(var a, b: ansistring; c: char); |
133 {$IFNDEF PAS2C} |
|
134 procedure SetLengthA(var s: ansistring; len: Longword); |
|
135 begin |
|
136 SetLength(s, len) |
|
137 end; |
|
138 {$ENDIF} |
|
139 |
|
140 procedure SplitByCharA(var a, b: ansistring; c: char); |
124 var i: LongInt; |
141 var i: LongInt; |
125 begin |
142 begin |
126 i:= Pos(c, a); |
143 i:= Pos(c, a); |
127 if i > 0 then |
144 if i > 0 then |
128 begin |
145 begin |
129 b:= copy(a, i + 1, Length(a) - i); |
146 b:= copy(a, i + 1, Length(a) - i); |
130 setlength(a, Pred(i)); |
147 SetLengthA(a, Pred(i)); |
131 end else b:= ''; |
148 end else b:= ''; |
132 end; |
149 end; { SplitByCharA } |
133 |
150 |
134 function EnumToStr(const en : TGearType) : shortstring; overload; |
151 function EnumToStr(const en : TGearType) : shortstring; overload; |
135 begin |
152 begin |
136 EnumToStr:= GetEnumName(TypeInfo(TGearType), ord(en)) |
153 EnumToStr:= GetEnumName(TypeInfo(TGearType), ord(en)) |
137 end; |
154 end; |
162 end; |
179 end; |
163 |
180 |
164 function EnumToStr(const en: TCapGroup) : shortstring; overload; |
181 function EnumToStr(const en: TCapGroup) : shortstring; overload; |
165 begin |
182 begin |
166 EnumToStr := GetEnumName(TypeInfo(TCapGroup), ord(en)) |
183 EnumToStr := GetEnumName(TypeInfo(TCapGroup), ord(en)) |
|
184 end; |
|
185 |
|
186 function EnumToStr(const en: TSprite) : shortstring; overload; |
|
187 begin |
|
188 EnumToStr := GetEnumName(TypeInfo(TSprite), ord(en)) |
|
189 end; |
|
190 |
|
191 function EnumToStr(const en: TMapGen) : shortstring; overload; |
|
192 begin |
|
193 EnumToStr := GetEnumName(TypeInfo(TMapGen), ord(en)) |
167 end; |
194 end; |
168 |
195 |
169 |
196 |
170 function Min(a, b: LongInt): LongInt; |
197 function Min(a, b: LongInt): LongInt; |
171 begin |
198 begin |
255 end; |
294 end; |
256 |
295 |
257 |
296 |
258 function DecodeBase64(s: shortstring): shortstring; |
297 function DecodeBase64(s: shortstring): shortstring; |
259 const table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; |
298 const table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; |
260 var i, t, c: Longword; |
299 var i, t, c: LongInt; |
261 begin |
300 begin |
262 c:= 0; |
301 c:= 0; |
263 for i:= 1 to Length(s) do |
302 for i:= 1 to Length(s) do |
264 begin |
303 begin |
265 t:= Pos(s[i], table); |
304 t:= Pos(s[i], table); |
288 DecodeBase64[0]:= char(t - 1) |
327 DecodeBase64[0]:= char(t - 1) |
289 end; |
328 end; |
290 |
329 |
291 |
330 |
292 function Str2PChar(const s: shortstring): PChar; |
331 function Str2PChar(const s: shortstring): PChar; |
293 begin |
332 var i :Integer ; |
294 CharArray:= s; |
333 begin |
295 CharArray[Length(s)]:= #0; |
334 for i:= 1 to Length(s) do |
296 Str2PChar:= @CharArray |
335 begin |
|
336 CharArray[i - 1] := s[i]; |
|
337 end; |
|
338 CharArray[Length(s)]:= #0; |
|
339 Str2PChar:= @(CharArray[0]); |
297 end; |
340 end; |
298 |
341 |
299 |
342 |
300 function endian(independent: LongWord): LongWord; inline; |
343 function endian(independent: LongWord): LongWord; inline; |
301 begin |
344 begin |
310 end; |
353 end; |
311 |
354 |
312 |
355 |
313 procedure AddFileLog(s: shortstring); |
356 procedure AddFileLog(s: shortstring); |
314 begin |
357 begin |
|
358 // s:= s; |
|
359 {$IFDEF DEBUGFILE} |
|
360 |
|
361 {$IFDEF USE_VIDEO_RECORDING} |
|
362 EnterCriticalSection(logMutex); |
|
363 {$ENDIF} |
|
364 writeln(logFile, inttostr(GameTicks) + ': ' + s); |
|
365 flush(logFile); |
|
366 |
|
367 {$IFDEF USE_VIDEO_RECORDING} |
|
368 LeaveCriticalSection(logMutex); |
|
369 {$ENDIF} |
|
370 |
|
371 {$ENDIF} |
|
372 end; |
|
373 |
|
374 procedure AddFileLogRaw(s: pchar); cdecl; |
|
375 begin |
315 s:= s; |
376 s:= s; |
|
377 {$IFNDEF PAS2C} |
316 {$IFDEF DEBUGFILE} |
378 {$IFDEF DEBUGFILE} |
317 {$IFDEF USE_VIDEO_RECORDING} |
379 {$IFDEF USE_VIDEO_RECORDING} |
318 EnterCriticalSection(logMutex); |
380 EnterCriticalSection(logMutex); |
319 {$ENDIF} |
381 {$ENDIF} |
320 writeln(f, inttostr(GameTicks) + ': ' + s); |
382 write(logFile, s); |
321 flush(f); |
383 flush(logFile); |
322 {$IFDEF USE_VIDEO_RECORDING} |
384 {$IFDEF USE_VIDEO_RECORDING} |
323 LeaveCriticalSection(logMutex); |
385 LeaveCriticalSection(logMutex); |
324 {$ENDIF} |
386 {$ENDIF} |
325 {$ENDIF} |
|
326 end; |
|
327 |
|
328 procedure AddFileLogRaw(s: pchar); cdecl; |
|
329 begin |
|
330 s:= s; |
|
331 {$IFDEF DEBUGFILE} |
|
332 {$IFDEF USE_VIDEO_RECORDING} |
|
333 EnterCriticalSection(logMutex); |
|
334 {$ENDIF} |
|
335 write(f, s); |
|
336 flush(f); |
|
337 {$IFDEF USE_VIDEO_RECORDING} |
|
338 LeaveCriticalSection(logMutex); |
|
339 {$ENDIF} |
387 {$ENDIF} |
340 {$ENDIF} |
388 {$ENDIF} |
341 end; |
389 end; |
342 |
390 |
343 function CheckCJKFont(s: ansistring; font: THWFont): THWFont; |
391 function CheckCJKFont(s: ansistring; font: THWFont): THWFont; |
368 ((#$4E00 <= u) and (u <= #$9FFF)) or // CJK Unified Ideographs |
416 ((#$4E00 <= u) and (u <= #$9FFF)) or // CJK Unified Ideographs |
369 ((#$AC00 <= u) and (u <= #$D7AF)) or // Hangul Syllables |
417 ((#$AC00 <= u) and (u <= #$D7AF)) or // Hangul Syllables |
370 ((#$F900 <= u) and (u <= #$FAFF)) or // CJK Compatibility Ideographs |
418 ((#$F900 <= u) and (u <= #$FAFF)) or // CJK Compatibility Ideographs |
371 ((#$FE30 <= u) and (u <= #$FE4F)) or // CJK Compatibility Forms |
419 ((#$FE30 <= u) and (u <= #$FE4F)) or // CJK Compatibility Forms |
372 ((#$FF66 <= u) and (u <= #$FF9D))) // halfwidth katakana |
420 ((#$FF66 <= u) and (u <= #$FF9D))) // halfwidth katakana |
373 then |
421 then |
374 begin |
422 begin |
375 CheckCJKFont:= THWFont( ord(font) + ((ord(High(THWFont))+1) div 2) ); |
423 CheckCJKFont:= THWFont( ord(font) + ((ord(High(THWFont))+1) div 2) ); |
376 exit; |
424 exit; |
377 end; |
425 end; |
378 inc(i) |
426 inc(i) |
406 function CheckNoTeamOrHH: boolean; |
454 function CheckNoTeamOrHH: boolean; |
407 begin |
455 begin |
408 CheckNoTeamOrHH:= (CurrentTeam = nil) or (CurrentHedgehog^.Gear = nil); |
456 CheckNoTeamOrHH:= (CurrentTeam = nil) or (CurrentHedgehog^.Gear = nil); |
409 end; |
457 end; |
410 |
458 |
|
459 {$IFNDEF PAS2C} |
411 procedure Write(var f: textfile; s: shortstring); |
460 procedure Write(var f: textfile; s: shortstring); |
412 begin |
461 begin |
413 system.write(f, s) |
462 system.write(f, s) |
414 end; |
463 end; |
415 |
464 |
416 procedure WriteLn(var f: textfile; s: shortstring); |
465 procedure WriteLn(var f: textfile; s: shortstring); |
417 begin |
466 begin |
418 system.writeln(f, s) |
467 system.writeln(f, s) |
419 end; |
468 end; |
420 |
469 |
|
470 function StrLength(s: PChar): Longword; |
|
471 begin |
|
472 StrLength:= length(s) |
|
473 end; |
|
474 {$ENDIF} |
421 |
475 |
422 // this function is just to determine whether we are running on a limited screen device |
476 // this function is just to determine whether we are running on a limited screen device |
423 function isPhone: Boolean; inline; |
477 function isPhone: Boolean; inline; |
424 begin |
478 begin |
425 isPhone:= false; |
479 isPhone:= false; |
442 for i:= 1 to length(s) do |
496 for i:= 1 to length(s) do |
443 if (s[i] < #32) or (s[i] > #127) then |
497 if (s[i] < #32) or (s[i] > #127) then |
444 r[i]:= '?' |
498 r[i]:= '?' |
445 else |
499 else |
446 r[i]:= s[i]; |
500 r[i]:= s[i]; |
447 |
501 |
448 sanitizeForLog:= r |
502 sanitizeForLog:= r |
449 end; |
503 end; |
450 |
504 |
451 function sanitizeCharForLog(c: char): shortstring; |
505 function sanitizeCharForLog(c: char): shortstring; |
452 var r: shortstring; |
506 var r: shortstring; |
453 begin |
507 begin |
454 if (c < #32) or (c > #127) then |
508 if (c < #32) or (c > #127) then |
455 r:= '#' + inttostr(byte(c)) |
509 r:= '#' + inttostr(byte(c)) |
456 else |
510 else |
457 r:= c; |
511 begin |
458 |
512 // some magic for pas2c |
|
513 r[0]:= #1; |
|
514 r[1]:= c; |
|
515 end; |
|
516 |
459 sanitizeCharForLog:= r |
517 sanitizeCharForLog:= r |
460 end; |
518 end; |
461 |
519 |
462 procedure initModule(isNotPreview: boolean); |
520 procedure initModule(isNotPreview: boolean); |
463 {$IFDEF DEBUGFILE} |
521 {$IFDEF DEBUGFILE} |
464 var logfileBase: shortstring; |
522 var logfileBase: shortstring; |
465 i: LongInt; |
523 i: LongInt; |
|
524 rwfailed: boolean; |
466 {$ENDIF} |
525 {$ENDIF} |
467 begin |
526 begin |
468 {$IFDEF DEBUGFILE} |
527 {$IFDEF DEBUGFILE} |
469 if isNotPreview then |
528 if isNotPreview then |
470 begin |
529 begin |
471 if GameType = gmtRecord then |
530 if GameType = gmtRecord then |
472 logfileBase:= 'rec' |
531 logfileBase:= 'rec' |
473 else |
532 else |
474 logfileBase:= 'game'; |
533 {$IFDEF PAS2C} |
|
534 logfileBase:= 'game_pas2c'; |
|
535 {$ELSE} |
|
536 logfileBase:= 'game'; |
|
537 {$ENDIF} |
475 end |
538 end |
476 else |
539 else |
|
540 {$IFDEF PAS2C} |
|
541 logfileBase:= 'preview_pas2c'; |
|
542 {$ELSE} |
477 logfileBase:= 'preview'; |
543 logfileBase:= 'preview'; |
|
544 {$ENDIF} |
478 {$IFDEF USE_VIDEO_RECORDING} |
545 {$IFDEF USE_VIDEO_RECORDING} |
479 InitCriticalSection(logMutex); |
546 InitCriticalSection(logMutex); |
480 {$ENDIF} |
547 {$ENDIF} |
481 {$I-} |
548 {$I-} |
482 f:= stderr; // if everything fails, write to stderr |
549 rwfailed:= false; |
483 if (UserPathPrefix <> '') then |
550 if (length(UserPathPrefix) > 0) then |
484 begin |
551 begin |
|
552 {$IFNDEF PAS2C} |
485 // create directory if it doesn't exist |
553 // create directory if it doesn't exist |
486 if not FileExists(UserPathPrefix + '/Logs/') then |
554 if not FileExists(UserPathPrefix + '/Logs/') then |
487 CreateDir(UserPathPrefix + '/Logs/'); |
555 CreateDir(UserPathPrefix + '/Logs/'); |
488 |
556 {$ENDIF} |
489 // if log is locked, write to the next one |
557 // if log is locked, write to the next one |
490 i:= 0; |
558 i:= 0; |
491 while(i < 7) do |
559 while(i < 7) do |
492 begin |
560 begin |
493 assign(f, UserPathPrefix + '/Logs/' + logfileBase + inttostr(i) + '.log'); |
561 assign(logFile, shortstring(UserPathPrefix) + '/Logs/' + logfileBase + inttostr(i) + '.log'); |
494 if IOResult = 0 then |
562 Rewrite(logFile); |
|
563 // note: IOResult is a function in pascal and a variable in pas2c |
|
564 rwfailed:= (IOResult <> 0); |
|
565 if (not rwfailed) then |
495 break; |
566 break; |
496 inc(i) |
567 inc(i) |
497 end; |
568 end; |
498 end; |
569 end; |
499 Rewrite(f); |
570 |
|
571 {$IFNDEF PAS2C} |
|
572 // if everything fails, write to stderr |
|
573 if (length(UserPathPrefix) = 0) or (rwfailed) then |
|
574 logFile:= stderr; |
|
575 {$ENDIF} |
500 {$I+} |
576 {$I+} |
501 {$ENDIF} |
577 {$ENDIF} |
502 |
578 |
503 //mobile stuff |
579 //mobile stuff |
504 {$IFDEF IPHONEOS} |
580 {$IFDEF IPHONEOS} |