⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cmd.pas

📁 雷神之锤2(Quake2)Delphi源码
💻 PAS
📖 第 1 页 / 共 2 页
字号:
{----------------------------------------------------------------------------}
{                                                                            }
{ File(s): qcommon.h (part), cmd.c                                           }
{ Content: Quake2\QCommon\                                                   }
{                                                                            }
{ Initial conversion by : D-12 (Thomas.lavergne) - d-12@laposte.net          }
{ Initial conversion on :   -Jan-2002                                        }
{                                                                            }
{ This File contains part of convertion of Quake2 source to ObjectPascal.    }
{ More information about this project can be found at:                       }
{ http://www.sulaco.co.za/quake2/                                            }
{                                                                            }
{ Copyright (C) 1997-2001 Id Software, Inc.                                  }
{                                                                            }
{ This program is free software; you can redistribute it and/or              }
{ modify it under the terms of the GNU General Public License                }
{ as published by the Free Software Foundation; either version 2             }
{ of the License, or (at your option) any later version.                     }
{                                                                            }
{ This program is distributed in the hope that it will be useful,            }
{ but WITHOUT ANY WARRANTY; without even the implied warranty of             }
{ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                       }
{                                                                            }
{ See the GNU General Public License for more details.                       }
{                                                                            }
{----------------------------------------------------------------------------}
{ Updated on : 03-jun-2002                                                   }
{ Updated by : Juha Hartikainen (juha@linearteam.org)                        }
{ - Removed NODEPEND hack.                                                   }
{ - Fixed couple places to let this compile right. 		             }
{----------------------------------------------------------------------------}
{ * Still dependent (to compile correctly) on:                               }
{ - cl_main.pas                                                              }
{----------------------------------------------------------------------------}
{ * TODO:                                                                    }
{                                                                            }
{----------------------------------------------------------------------------}

unit cmd;

interface


uses
  q_shared, common, cl_main, SysUtils,
  CPas;


// From Quake2\QCommon\qcommon.h
(*
==============================================================

CMD

Command text buffering and command execution

==============================================================
*)

(*

Any number of commands can be added in a frame, from several different sources.
Most commands come from either keybindings or console line input, but remote
servers can also send across commands and entire text files can be execed.

The + command line options are also added to the command buffer.

The game starts with a Cbuf_AddText ('exec quake.rc'#10); Cbuf_Execute ();

*)

const
  EXEC_NOW    = 0;  // don't return until completed
  EXEC_INSERT = 1;  // insert at current position, but don't run yet
  EXEC_APPEND = 2;  // add to end of the command buffer

procedure Cbuf_Init; cdecl;
// allocates an initial text buffer that will grow as needed

procedure Cbuf_AddText(text_: PChar); cdecl;
// as new commands are generated from the console or keybindings,
// the text is added to the end of the command buffer.

procedure Cbuf_InsertText(text_: PChar); cdecl;
// when a command wants to issue other commands immediately, the text is
// inserted at the beginning of the buffer, before any remaining unexecuted
// commands.

procedure Cbuf_ExecuteText(exec_when: Integer; text_: PChar); cdecl;
// this can be used in place of either Cbuf_AddText or Cbuf_InsertText

procedure Cbuf_AddEarlyCommands(clear: qboolean); cdecl;
// adds all the +set commands from the command line

function Cbuf_AddLateCommands: qboolean; cdecl;
// adds all the remaining + commands from the command line
// Returns true if any late commands were added, which
// will keep the demoloop from immediately starting

procedure Cbuf_Execute; cdecl;
// Pulls off \n terminated lines of text from the command buffer and sends
// them through Cmd_ExecuteString.  Stops when the buffer is empty.
// Normally called once per frame, but may be explicitly invoked.
// Do not call inside a command function!

procedure Cbuf_CopyToDefer; cdecl;
procedure Cbuf_InsertFromDefer; cdecl;
// These two functions are used to defer any pending commands while a map
// is being loaded

//===========================================================================

(*

Command execution takes a null terminated string, breaks it into tokens,
then searches for a command or variable that matches the first token.

*)


procedure Cmd_Init; cdecl;

procedure Cmd_AddCommand(cmd_name: PChar; function_: tcdeclproc); cdecl;
// called by the init functions of other parts of the program to
// register commands and functions to call for them.
// The cmd_name is referenced later, so it should not be in temp memory
// if function is NULL, the command will be forwarded to the server
// as a clc_stringcmd instead of executed locally

procedure Cmd_RemoveCommand(cmd_name: PChar); cdecl;

function Cmd_Exists(cmd_name: PChar): qboolean; cdecl;
// used by the cvar code to check for cvar / command name overlap

function Cmd_CompleteCommand(partial: PChar): PChar; cdecl;
// attempts to match a partial command for automatic command line completion
// returns NULL if nothing fits

function Cmd_Argc: Integer; cdecl;
function Cmd_Argv(arg: Integer): PChar; cdecl;
function Cmd_Args: PChar; cdecl;
// The functions that execute commands get their parameters with these
// functions. Cmd_Argv () will return an empty string, not a NULL
// if arg > argc, so string operations are always safe.

procedure Cmd_TokenizeString(text_: PChar; macroExpand: qboolean); cdecl;
// Takes a null terminated string.  Does not need to be /n terminated.
// breaks the string up into arg tokens.

procedure Cmd_ExecuteString(text_: PChar);cdecl;
// Parses a single line of text into arguments and tries to execute it
// as if it was typed at the console

//procedure Cmd_ForwardToServer;
// adds the current command line as a clc_stringcmd to the client message.
// things like godmode, noclip, etc, are commands directed to the server,
// so when they are typed in at the console, they will need to be forwarded.

implementation

uses
  cvar, files;


// cmd.c -- Quake script command processing module

const
  MAX_ALIAS_NAME = 32;

type
  cmdalias_p = ^cmdalias_s;
  cmdalias_s = packed record
    next: cmdalias_p;
    name: array[0..MAX_ALIAS_NAME - 1] of Char;
    value: PChar;
  end;
  cmdalias_t = cmdalias_s;

var
  cmd_alias: cmdalias_p;

  cmd_wait: qboolean;

const
  ALIAS_LOOP_COUNT = 16;

var
  alias_count: Integer;

//=============================================================================

(*
============
Cmd_Wait_f

Causes execution of the remainder of the command buffer to be delayed until
next frame.  This allows commands like:
bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2"
============
*)

procedure Cmd_Wait_f; cdecl;
begin
  cmd_wait := True;
end;

(*
=============================================================================

						COMMAND BUFFER

=============================================================================
*)

var
  cmd_text: sizebuf_t;
  cmd_text_buf: array[0..8191] of Char;
  defer_text_buf: array[0..8191] of Char;

(*
============
Cbuf_Init
============
*)
procedure Cbuf_Init;
begin
  SZ_Init(cmd_text, PByte(@cmd_text_buf[0]), SizeOf(cmd_text_buf));
end;

(*
============
Cbuf_AddText

Adds command text at the end of the buffer
============
*)
procedure Cbuf_AddText(text_: PChar);
var
  l: Integer;
begin
  l := StrLen(text_);
  if (cmd_text.cursize + l) >= cmd_text.maxsize then
  begin
    Com_Printf('Cbuf_AddText: overflow'#10, []);
    Exit;
  end;
  SZ_Write(cmd_text, text_, strlen(text_));
end;

(*
============
Cbuf_InsertText

Adds command text immediately after the current command
Adds a \n(#10) to the text
FIXME: actually change the command buffer to do less copying
============
*)
procedure Cbuf_InsertText(text_: PChar);
var
  temp: PChar;
  templen: Integer;
begin
// copy off any commands still remaining in the exec buffer
  templen := cmd_text.cursize;
  if templen <> 0 then
  begin
    temp := Z_Malloc(templen);
    memcpy(temp, cmd_text.data, templen);
    SZ_Clear(cmd_text);
  end
  else
    temp := nil; // shut up compiler

// add the entire text of the file
  Cbuf_AddText(text_);

// add the copied off data
  if templen <> 0 then
  begin
    SZ_Write(cmd_text, temp, templen);
    Z_Free(temp);
  end;
end;

(*
============
Cbuf_CopyToDefer
============
*)
procedure Cbuf_CopyToDefer;
begin
  memcpy(@defer_text_buf[0], @cmd_text_buf[0], cmd_text.cursize);
  defer_text_buf[cmd_text.cursize] := #0;
  cmd_text.cursize := 0;
end;

(*
============
Cbuf_InsertFromDefer
============
*)
procedure Cbuf_InsertFromDefer;
begin
  Cbuf_InsertText(@defer_text_buf);
  defer_text_buf[0] := #0;
end;

(*
============
Cbuf_ExecuteText
============
*)
procedure Cbuf_ExecuteText(exec_when: Integer; text_: PChar);
begin
  case exec_when of
    EXEC_NOW: Cmd_ExecuteString(text_);
    EXEC_INSERT: Cbuf_InsertText(text_);
    EXEC_APPEND: Cbuf_AddText(text_);
    else Com_Error(ERR_FATAL, 'Cbuf_ExecuteText: bad exec_when', []);
  end;
end;

(*
============
Cbuf_Execute
============
*)
procedure Cbuf_Execute;
var
  i: Integer;
  text_: PChar;
  line: array[0..1023] of Char;
  quotes: Integer;
begin
  alias_count := 0; // don't allow infinite alias loops

  while cmd_text.cursize <> 0 do
  begin
// find a \n(#10) or ; line break
    text_ := PChar(cmd_text.data);

    quotes := 0;
    for i := 0 to cmd_text.cursize - 1 do
    begin
      if (text_[i] = '"') then
        Inc(quotes);
      if ((not ((quotes and 1) <> 0)) and (text_[i] = ';')) then
        Break;
      if (text_[i] = #10) then
        Break;
    end;

    memcpy(@line, text_, i);
    line[i] := #0;

// delete the text from the command buffer and move remaining commands down
// this is necessary because commands (exec, alias) can insert data at the
// beginning of the text buffer

    if (i = cmd_text.cursize) then
    begin
      cmd_text.cursize := 0;
    end
    else
    begin
      Inc(i);
      Dec(cmd_text.cursize, i);
      memmove(text_, text_ + i, cmd_text.cursize);
    end;

// execute the command line
    Cmd_ExecuteString(line);

    if cmd_wait then
    begin
      //skip out while text still remains in buffer, leaving it
      // for next frame
      cmd_wait := false;
      Break;
    end;
  end;
end;

(*
===============
Cbuf_AddEarlyCommands

Adds command line parameters as script statements
Commands lead with a +, and continue until another +

Set commands are added early, so they are guaranteed to be set before
the client and server initialize for the first time.

Other commands are added late, after all initialization is complete.
===============
*)
procedure Cbuf_AddEarlyCommands(clear: qboolean);
var
  i: Integer;
  s: PChar;
begin
  i := 0;
  while i < COM_Argc do
  begin
    s := COM_Argv(i);
    if strcmp(s, '+set') <> 0 then
    begin
      Inc(i, 1);
      Continue;
    end;
    Cbuf_AddText(va('set %s %s'#10, [COM_Argv(i + 1), COM_Argv(i + 2)]));
    if clear then
    begin
      COM_ClearArgv(i);
      COM_ClearArgv(i + 1);
      COM_ClearArgv(i + 2);
    end;
    Inc(i, 3);
  end;
end;

(*
=================
Cbuf_AddLateCommands

Adds command line parameters as script statements
Commands lead with a + and continue until another + or -
quake +vid_ref gl +map amlev1

Returns true if any late commands were added, which
will keep the demoloop from immediately starting
=================
*)
function Cbuf_AddLateCommands: qboolean;
var
  i, j: Integer;
  s: Integer;
  c: Char;
  text_, build: PChar;
  argc: Integer;
begin
// build the combined string to parse from
  s := 0;
  argc := COM_Argc;
  for i := 1 to argc - 1 do
    Inc(s, strlen(COM_Argv(i)) + 1);
  if s = 0 then
  begin
    Result := False;
    Exit;
  end;

  text_ := Z_Malloc(s + 1);
  text_[0] := #0;
  for i := 1 to argc - 1 do
  begin
    StrCat(text_, COM_Argv(i));
    if i <> (argc - 1) then
      strcat(text_, ' ');
  end;

// pull out the commands
  build := Z_Malloc(s + 1);
  build[0] := #0;

  i := 0;
  while i < s - 1 do
  begin
    if text_[i] = '+' then
    begin
      Inc(i);

      j := i;
      while (text_[j] <> '+') and (text_[j] <> '-') and (text_[j] <> #0) do
        Inc(j);

      c := text_[j];
      text_[j] := #0;

      strcat(build, text_ + i);
      strcat(build, #10);
      text_[j] := c;
      i := j - 1;
    end;
    Inc(i);
  end;

  Result := build[0] <> #0;
  if Result then
    Cbuf_AddText(build);

  Z_Free(text_);
  Z_Free(build);
end;

(*
==============================================================================

						SCRIPT COMMANDS

==============================================================================
*)

(*
===============
Cmd_Exec_f
===============
*)
procedure Cmd_Exec_f; cdecl;
var
  f, f2: PChar;
  len: Integer;
begin
  if Cmd_Argc <> 2 then
  begin
    Com_Printf('exec <filename> : execute a script file'#10, []);
    Exit;
  end;

  len := FS_LoadFile(Cmd_Argv(1), @f);
  if f = nil then
  begin
    Com_Printf('couldn''t exec %s'#10, [Cmd_Argv(1)]);
    Exit;
  end;
  Com_Printf('execing %s'#10, [Cmd_Argv(1)]);

  // the file doesn't have a trailing 0, so we need to copy it off
  f2 := Z_Malloc(len + 1);
  memcpy(f2, f, len);
  f2[len] := #0;

  Cbuf_InsertText(f2);

  Z_Free(f2);
  FS_FreeFile(f);
end;

(*
===============
Cmd_Echo_f

Just prints the rest of the line to the console
===============
*)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -