DEADSOFTWARE

31bce9a1aa2ef7f026ce71cd57e55637a6373b19
[d2df-sdl.git] / src / game / g_console.pas
1 unit g_console;
3 interface
5 procedure g_Console_Init();
6 procedure g_Console_Update();
7 procedure g_Console_Draw();
8 procedure g_Console_Switch();
9 procedure g_Console_Char(C: Char);
10 procedure g_Console_Control(K: Word);
11 procedure g_Console_Process(L: String; Quiet: Boolean = False);
12 procedure g_Console_Add(L: String; Show: Boolean = False);
13 procedure g_Console_Clear();
14 function g_Console_CommandBlacklisted(C: String): Boolean;
16 procedure g_Console_Chat_Switch(Team: Boolean = False);
18 var
19 gConsoleShow: Boolean; // True - êîíñîëü îòêðûòà èëè îòêðûâàåòñÿ
20 gChatShow: Boolean;
21 gChatTeam: Boolean = False;
22 gAllowConsoleMessages: Boolean = True;
23 gChatEnter: Boolean = True;
24 gJustChatted: Boolean = False; // ÷òîáû àäìèí â èíòåðå ÷àòÿñü íå ïðîìàòûâàë ñòàòèñòèêó
26 implementation
28 uses
29 g_textures, g_main, e_graphics, e_input, g_game,
30 SysUtils, g_basic, g_options, wadreader, Math,
31 g_menu, g_language, g_net, g_netmsg, e_log;
33 type
34 TCmdProc = procedure (P: SArray);
36 TCommand = record
37 Cmd: String;
38 Proc: TCmdProc;
39 end;
41 TAlias = record
42 Name: String;
43 Commands: SArray;
44 end;
46 const
47 Step = 32;
48 Alpha = 25;
49 MsgTime = 144;
50 MaxScriptRecursion = 16;
52 DEBUG_STRING = 'DEBUG MODE';
54 var
55 ID: DWORD;
56 RecursionDepth: Word = 0;
57 RecursionLimitHit: Boolean = False;
58 Cons_Y: SmallInt;
59 Cons_Shown: Boolean; // Ðèñîâàòü ëè êîíñîëü?
60 Line: String;
61 CPos: Word;
62 ConsoleHistory: SArray;
63 CommandHistory: SArray;
64 Whitelist: SArray;
65 Commands: Array of TCommand;
66 Aliases: Array of TAlias;
67 CmdIndex: Word;
68 Offset: Word;
69 MsgArray: Array [0..4] of record
70 Msg: String;
71 Time: Word;
72 end;
74 function GetStrACmd(var Str: String): String;
75 var
76 a: Integer;
77 begin
78 Result := '';
79 for a := 1 to Length(Str) do
80 if (a = Length(Str)) or (Str[a+1] = ';') then
81 begin
82 Result := Copy(Str, 1, a);
83 Delete(Str, 1, a+1);
84 Str := Trim(Str);
85 Exit;
86 end;
87 end;
89 function ParseAlias(Str: String): SArray;
90 begin
91 Result := nil;
93 Str := Trim(Str);
95 if Str = '' then
96 Exit;
98 while Str <> '' do
99 begin
100 SetLength(Result, Length(Result)+1);
101 Result[High(Result)] := GetStrACmd(Str);
102 end;
103 end;
105 procedure ConsoleCommands(P: SArray);
106 var
107 Cmd, s: String;
108 a, b: Integer;
109 F: TextFile;
110 begin
111 Cmd := LowerCase(P[0]);
112 s := '';
114 if Cmd = 'clear' then
115 begin
116 ConsoleHistory := nil;
118 for a := 0 to High(MsgArray) do
119 with MsgArray[a] do
120 begin
121 Msg := '';
122 Time := 0;
123 end;
124 end;
126 if Cmd = 'clearhistory' then
127 CommandHistory := nil;
129 if Cmd = 'showhistory' then
130 if CommandHistory <> nil then
131 begin
132 g_Console_Add('');
133 for a := 0 to High(CommandHistory) do
134 g_Console_Add(' '+CommandHistory[a]);
135 end;
137 if Cmd = 'commands' then
138 begin
139 g_Console_Add('');
140 g_Console_Add('Commands list:');
141 for a := High(Commands) downto 0 do
142 g_Console_Add(' '+Commands[a].Cmd);
143 end;
145 if Cmd = 'time' then
146 g_Console_Add(TimeToStr(Now), True);
148 if Cmd = 'date' then
149 g_Console_Add(DateToStr(Now), True);
151 if Cmd = 'echo' then
152 if Length(P) > 1 then
153 begin
154 if P[1] = 'ololo' then
155 gCheats := True
156 else
157 begin
158 s := '';
159 for a := 1 to High(P) do
160 s := s + P[a] + ' ';
161 g_Console_Add(b_Text_Format(s), True);
162 end;
163 end
164 else
165 g_Console_Add('');
167 if Cmd = 'dump' then
168 begin
169 if ConsoleHistory <> nil then
170 begin
171 if Length(P) > 1 then
172 s := P[1]
173 else
174 s := GameDir+'/console.txt';
176 {$I-}
177 AssignFile(F, s);
178 Rewrite(F);
179 if IOResult <> 0 then
180 begin
181 g_Console_Add(Format(_lc[I_CONSOLE_ERROR_WRITE], [s]));
182 CloseFile(F);
183 Exit;
184 end;
186 for a := 0 to High(ConsoleHistory) do
187 WriteLn(F, ConsoleHistory[a]);
189 CloseFile(F);
190 g_Console_Add(Format(_lc[I_CONSOLE_DUMPED], [s]));
191 {$I+}
192 end;
193 end;
195 if Cmd = 'exec' then
196 begin
197 // exec <filename>
198 if Length(P) > 1 then
199 begin
200 s := GameDir+'/'+P[1];
202 {$I-}
203 AssignFile(F, s);
204 Reset(F);
205 if IOResult <> 0 then
206 begin
207 g_Console_Add(Format(_lc[I_CONSOLE_ERROR_READ], [s]));
208 CloseFile(F);
209 Exit;
210 end;
211 g_Console_Add(Format(_lc[I_CONSOLE_EXEC], [s]));
213 while not EOF(F) do
214 begin
215 ReadLn(F, s);
216 if IOResult <> 0 then
217 begin
218 g_Console_Add(Format(_lc[I_CONSOLE_ERROR_READ], [s]));
219 CloseFile(F);
220 Exit;
221 end;
222 if Pos('#', s) <> 1 then // script comment
223 begin
224 // prevents endless loops
225 Inc(RecursionDepth);
226 RecursionLimitHit := (RecursionDepth > MaxScriptRecursion) or RecursionLimitHit;
227 if not RecursionLimitHit then
228 g_Console_Process(s, True);
229 Dec(RecursionDepth);
230 end;
231 end;
232 if (RecursionDepth = 0) and RecursionLimitHit then
233 begin
234 g_Console_Add(Format(_lc[I_CONSOLE_ERROR_CALL], [s]));
235 RecursionLimitHit := False;
236 end;
238 CloseFile(F);
239 {$I+}
240 end
241 else
242 g_Console_Add('exec <script file>');
243 end;
245 if Cmd = 'alias' then
246 begin
247 // alias [alias_name] [commands]
248 if Length(P) > 1 then
249 begin
250 for a := 0 to High(Aliases) do
251 if Aliases[a].Name = P[1] then
252 begin
253 if Length(P) > 2 then
254 Aliases[a].Commands := ParseAlias(P[2])
255 else
256 for b := 0 to High(Aliases[a].Commands) do
257 g_Console_Add(Aliases[a].Commands[b]);
258 Exit;
259 end;
260 SetLength(Aliases, Length(Aliases)+1);
261 a := High(Aliases);
262 Aliases[a].Name := P[1];
263 if Length(P) > 2 then
264 Aliases[a].Commands := ParseAlias(P[2])
265 else
266 for b := 0 to High(Aliases[a].Commands) do
267 g_Console_Add(Aliases[a].Commands[b]);
268 end else
269 for a := 0 to High(Aliases) do
270 if Aliases[a].Commands <> nil then
271 g_Console_Add(Aliases[a].Name);
272 end;
274 if Cmd = 'call' then
275 begin
276 // call <alias_name>
277 if Length(P) > 1 then
278 begin
279 if Aliases = nil then
280 Exit;
281 for a := 0 to High(Aliases) do
282 if Aliases[a].Name = P[1] then
283 begin
284 if Aliases[a].Commands <> nil then
285 begin
286 // with this system proper endless loop detection seems either impossible
287 // or very dirty to implement, so let's have this instead
288 // prevents endless loops
289 for b := 0 to High(Aliases[a].Commands) do
290 begin
291 Inc(RecursionDepth);
292 RecursionLimitHit := (RecursionDepth > MaxScriptRecursion) or RecursionLimitHit;
293 if not RecursionLimitHit then
294 g_Console_Process(Aliases[a].Commands[b], True);
295 Dec(RecursionDepth);
296 end;
297 if (RecursionDepth = 0) and RecursionLimitHit then
298 begin
299 g_Console_Add(Format(_lc[I_CONSOLE_ERROR_CALL], [s]));
300 RecursionLimitHit := False;
301 end;
302 end;
303 Exit;
304 end;
305 end
306 else
307 g_Console_Add('call <alias name>');
308 end;
309 end;
311 procedure WhitelistCommand(Cmd: string);
312 var
313 a: Integer;
314 begin
315 SetLength(Whitelist, Length(Whitelist)+1);
316 a := High(Whitelist);
317 Whitelist[a] := Cmd;
318 end;
320 procedure AddCommand(Cmd: String; Proc: TCmdProc);
321 var
322 a: Integer;
323 begin
324 SetLength(Commands, Length(Commands)+1);
325 a := High(Commands);
326 Commands[a].Cmd := Cmd;
327 Commands[a].Proc := Proc;
328 end;
330 procedure g_Console_Init();
331 var
332 a: Integer;
333 begin
334 g_Texture_CreateWAD(ID, GameWAD+':TEXTURES\CONSOLE');
335 Cons_Y := -(gScreenHeight div 2);
336 gConsoleShow := False;
337 gChatShow := False;
338 Cons_Shown := False;
339 CPos := 1;
341 for a := 0 to High(MsgArray) do
342 with MsgArray[a] do
343 begin
344 Msg := '';
345 Time := 0;
346 end;
348 AddCommand('clear', ConsoleCommands);
349 AddCommand('clearhistory', ConsoleCommands);
350 AddCommand('showhistory', ConsoleCommands);
351 AddCommand('commands', ConsoleCommands);
352 AddCommand('time', ConsoleCommands);
353 AddCommand('date', ConsoleCommands);
354 AddCommand('echo', ConsoleCommands);
355 AddCommand('dump', ConsoleCommands);
356 AddCommand('exec', ConsoleCommands);
357 AddCommand('alias', ConsoleCommands);
358 AddCommand('call', ConsoleCommands);
360 AddCommand('d_window', DebugCommands);
361 AddCommand('d_sounds', DebugCommands);
362 AddCommand('d_frames', DebugCommands);
363 AddCommand('d_winmsg', DebugCommands);
364 AddCommand('d_monoff', DebugCommands);
365 AddCommand('d_botoff', DebugCommands);
366 AddCommand('d_monster', DebugCommands);
367 AddCommand('d_health', DebugCommands);
368 AddCommand('d_player', DebugCommands);
369 AddCommand('d_joy', DebugCommands);
371 AddCommand('p1_name', GameCVars);
372 AddCommand('p2_name', GameCVars);
373 AddCommand('p1_color', GameCVars);
374 AddCommand('p2_color', GameCVars);
375 AddCommand('r_showfps', GameCVars);
376 AddCommand('r_showtime', GameCVars);
377 AddCommand('r_showscore', GameCVars);
378 AddCommand('r_showlives', GameCVars);
379 AddCommand('r_showstat', GameCVars);
380 AddCommand('r_showkillmsg', GameCVars);
381 AddCommand('r_showspect', GameCVars);
382 AddCommand('r_showping', GameCVars);
383 AddCommand('g_gamemode', GameCVars);
384 AddCommand('g_friendlyfire', GameCVars);
385 AddCommand('g_weaponstay', GameCVars);
386 AddCommand('g_allow_exit', GameCVars);
387 AddCommand('g_allow_monsters', GameCVars);
388 AddCommand('g_bot_vsmonsters', GameCVars);
389 AddCommand('g_bot_vsplayers', GameCVars);
390 AddCommand('g_scorelimit', GameCVars);
391 AddCommand('g_timelimit', GameCVars);
392 AddCommand('g_maxlives', GameCVars);
393 AddCommand('g_warmuptime', GameCVars);
394 AddCommand('net_interp', GameCVars);
395 AddCommand('net_forceplayerupdate', GameCVars);
396 AddCommand('net_predictself', GameCVars);
397 AddCommand('sv_name', GameCVars);
398 AddCommand('sv_passwd', GameCVars);
399 AddCommand('sv_maxplrs', GameCVars);
400 AddCommand('sv_public', GameCVars);
401 AddCommand('sv_intertime', GameCVars);
403 AddCommand('quit', GameCommands);
404 AddCommand('exit', GameCommands);
405 AddCommand('pause', GameCommands);
406 AddCommand('endgame', GameCommands);
407 AddCommand('restart', GameCommands);
408 AddCommand('addbot', GameCommands);
409 AddCommand('bot_add', GameCommands);
410 AddCommand('bot_addlist', GameCommands);
411 AddCommand('bot_addred', GameCommands);
412 AddCommand('bot_addblue', GameCommands);
413 AddCommand('bot_removeall', GameCommands);
414 AddCommand('chat', GameCommands);
415 AddCommand('teamchat', GameCommands);
416 AddCommand('game', GameCommands);
417 AddCommand('host', GameCommands);
418 AddCommand('map', GameCommands);
419 AddCommand('nextmap', GameCommands);
420 AddCommand('endmap', GameCommands);
421 AddCommand('goodbye', GameCommands);
422 AddCommand('suicide', GameCommands);
423 AddCommand('spectate', GameCommands);
424 AddCommand('ready', GameCommands);
425 AddCommand('kick', GameCommands);
426 AddCommand('kick_id', GameCommands);
427 AddCommand('ban', GameCommands);
428 AddCommand('permban', GameCommands);
429 AddCommand('ban_id', GameCommands);
430 AddCommand('permban_id', GameCommands);
431 AddCommand('unban', GameCommands);
432 AddCommand('connect', GameCommands);
433 AddCommand('disconnect', GameCommands);
434 AddCommand('reconnect', GameCommands);
435 AddCommand('say', GameCommands);
436 AddCommand('tell', GameCommands);
437 AddCommand('overtime', GameCommands);
438 AddCommand('rcon_password', GameCommands);
439 AddCommand('rcon', GameCommands);
440 AddCommand('callvote', GameCommands);
441 AddCommand('vote', GameCommands);
442 AddCommand('clientlist', GameCommands);
443 AddCommand('event', GameCommands);
445 AddCommand('god', GameCheats);
446 AddCommand('notarget', GameCheats);
447 AddCommand('give', GameCheats); // "exit" too ;-)
448 AddCommand('open', GameCheats);
449 AddCommand('fly', GameCheats);
450 AddCommand('noclip', GameCheats);
451 AddCommand('speedy', GameCheats);
452 AddCommand('jumpy', GameCheats);
453 AddCommand('noreload', GameCheats);
454 AddCommand('aimline', GameCheats);
455 AddCommand('automap', GameCheats);
457 WhitelistCommand('say');
458 WhitelistCommand('tell');
459 WhitelistCommand('overtime');
460 WhitelistCommand('ready');
461 WhitelistCommand('map');
462 WhitelistCommand('nextmap');
463 WhitelistCommand('endmap');
464 WhitelistCommand('restart');
465 WhitelistCommand('kick');
466 WhitelistCommand('ban');
468 WhitelistCommand('addbot');
469 WhitelistCommand('bot_add');
470 WhitelistCommand('bot_addred');
471 WhitelistCommand('bot_addblue');
472 WhitelistCommand('bot_removeall');
474 WhitelistCommand('g_gamemode');
475 WhitelistCommand('g_friendlyfire');
476 WhitelistCommand('g_weaponstay');
477 WhitelistCommand('g_allow_exit');
478 WhitelistCommand('g_allow_monsters');
479 WhitelistCommand('g_scorelimit');
480 WhitelistCommand('g_timelimit');
482 g_Console_Add(Format(_lc[I_CONSOLE_WELCOME], [GAME_VERSION]));
483 g_Console_Add('');
484 end;
486 procedure g_Console_Update();
487 var
488 a, b: Integer;
489 begin
490 if Cons_Shown then
491 begin
492 // Â ïðîöåññå îòêðûòèÿ:
493 if gConsoleShow and (Cons_Y < 0) then
494 begin
495 Cons_Y := Cons_Y+Step;
496 end;
498 // Â ïðîöåññå çàêðûòèÿ:
499 if (not gConsoleShow) and
500 (Cons_Y > -(gScreenHeight div 2)) then
501 Cons_Y := Cons_Y-Step;
503 // Îêîí÷àòåëüíî îòêðûëàñü:
504 if Cons_Y > 0 then
505 Cons_Y := 0;
507 // Îêîí÷àòåëüíî çàêðûëàñü:
508 if Cons_Y <= (-(gScreenHeight div 2)) then
509 begin
510 Cons_Y := -(gScreenHeight div 2);
511 Cons_Shown := False;
512 end;
513 end;
515 a := 0;
516 while a <= High(MsgArray) do
517 begin
518 if MsgArray[a].Time > 0 then
519 begin
520 if MsgArray[a].Time = 1 then
521 begin
522 if a < High(MsgArray) then
523 begin
524 for b := a to High(MsgArray)-1 do
525 MsgArray[b] := MsgArray[b+1];
527 MsgArray[High(MsgArray)].Time := 0;
529 a := a - 1;
530 end;
531 end
532 else
533 Dec(MsgArray[a].Time);
534 end;
536 a := a + 1;
537 end;
538 end;
540 procedure g_Console_Draw();
541 var
542 CWidth, CHeight: Byte;
543 mfW, mfH: Word;
544 a, b, c, d: Integer;
545 begin
546 e_TextureFontGetSize(gStdFont, CWidth, CHeight);
548 for a := 0 to High(MsgArray) do
549 if MsgArray[a].Time > 0 then
550 e_TextureFontPrintFmt(0, CHeight*a, MsgArray[a].Msg,
551 gStdFont, True);
553 if not Cons_Shown then
554 begin
555 if gChatShow then
556 begin
557 if gChatTeam then
558 begin
559 e_TextureFontPrintEx(0, gScreenHeight - CHeight - 1, 'say team> ' + Line,
560 gStdFont, 255, 255, 255, 1, True);
561 e_TextureFontPrintEx((CPos + 9)*CWidth, gScreenHeight - CHeight - 1, '_',
562 gStdFont, 255, 255, 255, 1, True);
563 end
564 else
565 begin
566 e_TextureFontPrintEx(0, gScreenHeight - CHeight - 1, 'say> ' + Line,
567 gStdFont, 255, 255, 255, 1, True);
568 e_TextureFontPrintEx((CPos + 4)*CWidth, gScreenHeight - CHeight - 1, '_',
569 gStdFont, 255, 255, 255, 1, True);
570 end;
571 end;
572 Exit;
573 end;
575 if gDebugMode then
576 begin
577 e_CharFont_GetSize(gMenuFont, DEBUG_STRING, mfW, mfH);
578 a := (gScreenWidth - 2*mfW) div 2;
579 b := Cons_Y + ((gScreenHeight div 2) - 2*mfH) div 2;
580 e_CharFont_PrintEx(gMenuFont, a div 2, b div 2, DEBUG_STRING,
581 _RGB(128, 0, 0), 2.0);
582 end;
584 e_DrawSize(ID, 0, Cons_Y, Alpha, False, False, gScreenWidth, gScreenHeight div 2);
585 e_TextureFontPrint(0, Cons_Y+(gScreenHeight div 2)-CHeight-4, '> '+Line, gStdFont);
587 if ConsoleHistory <> nil then
588 begin
589 b := 0;
590 if CHeight > 0 then
591 if Length(ConsoleHistory) > ((gScreenHeight div 2) div CHeight)-1 then
592 b := Length(ConsoleHistory)-((gScreenHeight div 2) div CHeight)+1;
594 b := Max(b-Offset, 0);
595 d := Max(High(ConsoleHistory)-Offset, 0);
597 c := 2;
598 for a := d downto b do
599 begin
600 e_TextureFontPrintFmt(0, (gScreenHeight div 2)-4-c*CHeight-Abs(Cons_Y), ConsoleHistory[a],
601 gStdFont, True);
602 c := c + 1;
603 end;
604 end;
606 e_TextureFontPrint((CPos+1)*CWidth, Cons_Y+(gScreenHeight div 2)-21, '_', gStdFont);
607 end;
609 procedure g_Console_Switch();
610 begin
611 if gChatShow then Exit;
612 gConsoleShow := not gConsoleShow;
613 Cons_Shown := True;
614 end;
616 procedure g_Console_Chat_Switch(Team: Boolean = False);
617 begin
618 if gConsoleShow then Exit;
619 if not g_Game_IsNet then Exit;
620 gChatShow := not gChatShow;
621 gChatTeam := Team;
622 if gChatShow then
623 gChatEnter := False;
624 Line := '';
625 CPos := 1;
626 end;
628 procedure g_Console_Char(C: Char);
629 begin
630 if gChatShow and (not gChatEnter) then
631 Exit;
632 Insert(C, Line, CPos);
633 CPos := CPos + 1;
634 end;
636 procedure Complete();
637 var
638 i: Integer;
639 t: Array of String;
640 begin
641 if Line = '' then
642 Exit;
644 t := nil;
646 for i := 0 to High(Commands) do
647 if LowerCase(Line) = LowerCase(Copy(Commands[i].Cmd, 0, Length(Line))) then
648 begin
649 SetLength(t, Length(t) + 1);
650 t[Length(t)-1] := Commands[i].Cmd;
651 end;
653 if t = nil then
654 Exit;
656 if Length(t) = 1 then
657 begin
658 Line := t[0]+' ';
659 CPos := Length(Line)+1;
660 end
661 else
662 begin
663 g_Console_Add('');
664 for i := 0 to High(t) do
665 g_Console_Add(' '+t[i]);
666 end;
667 end;
669 procedure g_Console_Control(K: Word);
670 begin
671 case K of
672 IK_BACKSPACE:
673 if (Length(Line) > 0) and (CPos > 1) then
674 begin
675 Delete(Line, CPos-1, 1);
676 CPos := CPos-1;
677 end;
678 IK_DELETE:
679 if (Length(Line) > 0) and (CPos <= Length(Line)) then
680 Delete(Line, CPos, 1);
681 IK_LEFT, IK_KPLEFT:
682 if CPos > 1 then
683 CPos := CPos - 1;
684 IK_RIGHT, IK_KPRIGHT:
685 if CPos <= Length(Line) then
686 CPos := CPos + 1;
687 IK_RETURN, IK_KPRETURN:
688 begin
689 if Cons_Shown then
690 g_Console_Process(Line)
691 else
692 if gChatShow then
693 begin
694 if (Length(Line) > 0) and g_Game_IsNet then
695 begin
696 if gChatTeam then
697 begin
698 if g_Game_IsClient then
699 MC_SEND_Chat(b_Text_Format(Line), NET_CHAT_TEAM)
700 else
701 MH_SEND_Chat('[' + gPlayer1Settings.Name + ']: ' + b_Text_Format(Line),
702 NET_CHAT_TEAM, gPlayer1Settings.Team);
703 end
704 else
705 begin
706 if g_Game_IsClient then
707 MC_SEND_Chat(b_Text_Format(Line), NET_CHAT_PLAYER)
708 else
709 MH_SEND_Chat('[' + gPlayer1Settings.Name + ']: ' + b_Text_Format(Line),
710 NET_CHAT_PLAYER);
711 end;
712 end;
714 Line := '';
715 CPos := 1;
716 gChatShow := False;
717 gJustChatted := True;
718 end;
719 end;
720 IK_TAB:
721 if not gChatShow then
722 Complete();
723 IK_DOWN, IK_KPDOWN:
724 if not gChatShow then
725 if (CommandHistory <> nil) and
726 (CmdIndex < Length(CommandHistory)) then
727 begin
728 if CmdIndex < Length(CommandHistory)-1 then
729 CmdIndex := CmdIndex + 1;
730 Line := CommandHistory[CmdIndex];
731 CPos := Length(Line) + 1;
732 end;
733 IK_UP, IK_KPUP:
734 if not gChatShow then
735 if (CommandHistory <> nil) and
736 (CmdIndex <= Length(CommandHistory)) then
737 begin
738 if CmdIndex > 0 then
739 CmdIndex := CmdIndex - 1;
740 Line := CommandHistory[CmdIndex];
741 Cpos := Length(Line) + 1;
742 end;
743 IK_PAGEUP, IK_KPPAGEUP: // PgUp
744 if not gChatShow then
745 IncMax(OffSet, Length(ConsoleHistory)-1);
746 IK_PAGEDN, IK_KPPAGEDN: // PgDown
747 if not gChatShow then
748 DecMin(OffSet, 0);
749 IK_HOME, IK_KPHOME:
750 CPos := 1;
751 IK_END, IK_KPEND:
752 CPos := Length(Line) + 1;
753 end;
754 end;
756 function GetStr(var Str: String): String;
757 var
758 a, b: Integer;
759 begin
760 Result := '';
761 if Str[1] = '"' then
762 begin
763 for b := 1 to Length(Str) do
764 if (b = Length(Str)) or (Str[b+1] = '"') then
765 begin
766 Result := Copy(Str, 2, b-1);
767 Delete(Str, 1, b+1);
768 Str := Trim(Str);
769 Exit;
770 end;
771 end;
773 for a := 1 to Length(Str) do
774 if (a = Length(Str)) or (Str[a+1] = ' ') then
775 begin
776 Result := Copy(Str, 1, a);
777 Delete(Str, 1, a+1);
778 Str := Trim(Str);
779 Exit;
780 end;
781 end;
783 function ParseString(Str: String): SArray;
784 begin
785 Result := nil;
787 Str := Trim(Str);
789 if Str = '' then
790 Exit;
792 while Str <> '' do
793 begin
794 SetLength(Result, Length(Result)+1);
795 Result[High(Result)] := GetStr(Str);
796 end;
797 end;
799 procedure g_Console_Add(L: String; Show: Boolean = False);
800 var
801 a: Integer;
802 begin
803 // Âûâîä ñòðîê ñ ïåðåíîñàìè ïî î÷åðåäè
804 while Pos(#10, L) > 0 do
805 begin
806 g_Console_Add(Copy(L, 1, Pos(#10, L) - 1), Show);
807 Delete(L, 1, Pos(#10, L));
808 end;
810 SetLength(ConsoleHistory, Length(ConsoleHistory)+1);
811 ConsoleHistory[High(ConsoleHistory)] := L;
813 Show := Show and gAllowConsoleMessages;
815 if Show and gShowMessages then
816 begin
817 for a := 0 to High(MsgArray) do
818 with MsgArray[a] do
819 if Time = 0 then
820 begin
821 Msg := L;
822 Time := MsgTime;
823 Exit;
824 end;
826 for a := 0 to High(MsgArray)-1 do
827 MsgArray[a] := MsgArray[a+1];
829 with MsgArray[High(MsgArray)] do
830 begin
831 Msg := L;
832 Time := MsgTime;
833 end;
834 end;
836 {$IFDEF HEADLESS}
837 e_WriteLog('CON: ' + L, MSG_NOTIFY);
838 {$ENDIF}
839 end;
841 procedure g_Console_Clear();
842 begin
843 ConsoleHistory := nil;
844 Offset := 0;
845 end;
847 procedure AddToHistory(L: String);
848 var
849 len: Integer;
850 begin
851 len := Length(CommandHistory);
853 if (len = 0) or
854 (LowerCase(CommandHistory[len-1]) <> LowerCase(L)) then
855 begin
856 SetLength(CommandHistory, len+1);
857 CommandHistory[len] := L;
858 end;
860 CmdIndex := Length(CommandHistory);
861 end;
863 function g_Console_CommandBlacklisted(C: String): Boolean;
864 var
865 Arr: SArray;
866 i: Integer;
867 begin
868 Result := True;
870 Arr := nil;
872 if Trim(C) = '' then
873 Exit;
875 Arr := ParseString(C);
876 if Arr = nil then
877 Exit;
879 for i := 0 to High(Whitelist) do
880 if Whitelist[i] = LowerCase(Arr[0]) then
881 Result := False;
882 end;
884 procedure g_Console_Process(L: String; Quiet: Boolean = False);
885 var
886 Arr: SArray;
887 i: Integer;
888 begin
889 Arr := nil;
891 if Trim(L) = '' then
892 Exit;
894 if not Quiet then
895 begin
896 g_Console_Add('> '+L);
897 Line := '';
898 CPos := 1;
899 end;
901 Arr := ParseString(L);
902 if Arr = nil then
903 Exit;
905 if Commands = nil then
906 Exit;
908 if not Quiet then
909 AddToHistory(L);
911 for i := 0 to High(Commands) do
912 if Commands[i].Cmd = LowerCase(Arr[0]) then
913 if @Commands[i].Proc <> nil then
914 begin
915 Commands[i].Proc(Arr);
916 Exit;
917 end;
919 g_Console_Add(Format(_lc[I_CONSOLE_UNKNOWN], [Arr[0]]));
920 end;
922 end.