DEADSOFTWARE

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