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

📄 g_main.pas

📁 雷神之锤2(Quake2)Delphi源码
💻 PAS
📖 第 1 页 / 共 2 页
字号:
{----------------------------------------------------------------------------}
{                                                                            }
{ File(s): g_local.h (part), g_main.c                                        }
{ Content: Quake2\Game-CTF\ game interface initialization / management       }
{                                                                            }
{ Initial conversion by : Clootie (Alexey Barkovoy) - clootie@reactor.ru     }
{ Initial conversion on : 26-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:                                                                 }
{ 1) 27-Jan-2002 - Clootie (clootie@reactor.ru)                              }
{    Corrected "strtok" function.                                            }
{ 2) 28-Jan-2002 - Clootie (clootie@reactor.ru)                              }
{    Linked to "g_svcmnds.pas" unit.                                         }
{ 3) 25-Feb-2002 - Clootie (clootie@reactor.ru)                              }
{    Resolved all dependency to G_Local.pas and G_Utils.pas.                 }
{ 4) 3-Mar-2002 - Carl Kenner (carl_kenner@hotmail.com)                      }
{    Made compatible with Capture The Flag and g_save                        }
{    Removed redefinitions of g_local stuff                                  }
{                                                                            }
{----------------------------------------------------------------------------}
{ * Still dependent (to compile correctly) on:                               }
{ -- Implementation: g_phys, p_client, g_spawn                               }
{----------------------------------------------------------------------------}
{ * TODO:                                                                    }
{ Clootie: "GAME_HARD_LINKED" on what project it should be defined ?         }
{----------------------------------------------------------------------------}
{ * NOTES:  --== Clootie ==--                                                }
{           This unit designed to be compatible with both Game and CTF build }
{           targets. By default unit compiles to GAME build target. To build }
{           for CTF one should define "CTF" global conditional define.       }
{----------------------------------------------------------------------------}

// Remove DOT before $DEFINE in next line to allow non-dependable compilation //
{$DEFINE NODEPEND}
// non-dependable compilation will use STUBS for some external symbols

unit g_main;

interface

uses
  Q_Shared, G_Local, GameUnit, CVar;

procedure G_RunFrame; cdecl;

function GetGameApi(const import: game_import_t): game_export_p; stdcall;

{$IFNDEF GAME_HARD_LINKED}
// this is only here so the functions in q_shared.c and q_shwin.c can link
procedure Sys_Error(error: PChar; args: array of const);
procedure Com_Printf(msg: PChar; args: array of const);
{$ENDIF}

implementation

uses
  SysUtils, Math,
  g_svcmds, g_save, g_utils
{$IFNDEF NODEPEND}
  , g_ai
{$IFDEF CTF}
  , g_ctf
{$ENDIF}
{$ENDIF}
   ;

{$IFDEF NODEPEND}
//Clootie:  From g_local.h, line 785 -> Should be in "p_view" ?
//
// p_view.c
//
procedure ClientEndServerFrame(ent: edict_p); begin end;

procedure M_CheckGround (ent : edict_p); begin end;
procedure ClientBeginServerFrame(ent: edict_p); begin end;
procedure G_RunEntity(ent: edict_p); begin end;

procedure BeginIntermission(targ: edict_p); begin end;// g_client

procedure AI_SetSightClient; begin end; // g_ai

procedure SpawnEntities(mapname, entities, spawnpoint: PChar); cdecl; begin end; // g_spawn.c
procedure ClientThink(ent: edict_p; cmd: usercmd_p); cdecl; begin end; // p_client.c
function ClientConnect(ent: edict_p; userinfo: PChar): qboolean; cdecl; begin Result:= False end; // p_client.c
procedure ClientUserinfoChanged(ent: edict_p; userinfo: PChar); cdecl; begin end; // p_client.c
procedure ClientDisconnect(ent: edict_p); cdecl; begin end; // p_client.c
procedure ClientBegin(ent: edict_p); cdecl; begin end; // p_client.c
procedure ClientCommand(ent: edict_p); cdecl; begin end; // p_client.c
procedure RunEntity(ent: edict_p); cdecl; begin end; // g_phys.c

{$IFDEF CTF}
var ctf: cvar_p; // g_ctf.h
function CTFCheckRules: qboolean; // g_ctf.c
begin
  Result:=false;
end;
function CTFInMatch: qboolean; // g_ctf.c
begin
  Result:=false;
end;
function CTFNextMap: qboolean; // g_ctf.c
begin
  Result:=false;
end;

{$ENDIF}


// Real code starts HERE...
{$ENDIF}


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


procedure ShutdownGame; cdecl;
begin
  gi_dprintf('==== ShutdownGame ===='#10, ['']);

  gi.FreeTags(TAG_LEVEL);
  gi.FreeTags(TAG_GAME);
end;


(*
=================
GetGameAPI

Returns a pointer to the structure with all entry points
and global variables
=================
*)
function GetGameApi(const import: game_import_t): game_export_p; stdcall;
begin
  gi := import;

  globals.apiversion := GAME_API_VERSION;
  globals.Init := InitGame;
  globals.Shutdown := ShutdownGame;
  globals.SpawnEntities := SpawnEntities;

  globals.WriteGame := WriteGame;
  globals.ReadGame := ReadGame;
  globals.WriteLevel := WriteLevel;
  globals.ReadLevel := ReadLevel;

  globals.ClientThink := ClientThink;
  globals.ClientConnect := ClientConnect;
  globals.ClientUserinfoChanged := ClientUserinfoChanged;
  globals.ClientDisconnect := ClientDisconnect;
  globals.ClientBegin := ClientBegin;
  globals.ClientCommand := ClientCommand;

  globals.RunFrame := G_RunFrame;

  globals.ServerCommand := ServerCommand;

  globals.edict_size := SizeOf(edict_t);

  Result := @globals;
end;

{$IFNDEF GAME_HARD_LINKED}

// this is only here so the functions in q_shared.c and q_shwin.c can link
procedure Sys_Error(error: PChar; args: array of const);
var
  text: array [0..1023] of Char;
begin
  StrFmt(text, error, args);
  //Clootie: code error in C source file - probably it's never compiles
  //         - as Game.dll exist in all Quake-series games
  // gi.error(ERR_FATAL, '%s', [text]);
  gi_error({ERR_FATAL, }'%s', [text]);
end;

procedure Com_Printf(msg: PChar; args: array of const);
var
  text: array [0..1023] of Char;
begin
  StrFmt(text, msg, args);
  gi_dprintf('%s', [text]);
end;

{$ENDIF}

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


(*
=================
ClientEndServerFrames
=================
*)
procedure ClientEndServerFrames;
var
  i: Integer;
  ent: edict_p;
begin
  // calc the player views now that all pushing
  // and damage has been added
  for i := 0 to Round(maxclients.value - 1) do
  begin
    // ent = g_edicts + 1 + i;
    ent := @g_edicts[1 + i];
    if (not ent.inuse or (ent.client = nil)) then
      Continue;
    ClientEndServerFrame(ent);
  end;
end;

(*
=================
CreateTargetChangeLevel

Returns the created target changelevel
=================
*)
function CreateTargetChangeLevel(map: PChar): edict_p;
var
  ent: edict_p;
begin
  ent := G_Spawn;
  ent.classname := 'target_changelevel';
  Com_sprintf(level.nextmap, sizeof(level.nextmap), '%s', [map]);
  ent.map := level.nextmap;
  Result := ent;
end;


threadvar
  strtok_save: PChar; // this is saving point for "strtok" fuction
//todo: "strtok" is not tested!!!
function strtok(s1, s2: PChar): PChar;
var
  sp: PChar; // register const _TCHAR *
begin
  if (s1 = nil) then s1 := strtok_save;

  (* First skip separators *)
  while (s1^ <> #0) do
  begin
    // for (sp = s2; *sp; sp++)
    sp := s2;
    while (sp^ <> #0) do
    begin
      if (sp^ = s1^) then Break;
      Inc(sp);
    end;
    if (sp^ = #0) then Break;
    Inc(s1);
  end;
  if (s1^ = #0) then
  begin
    strtok_save := s1;
    Result:= nil;
    Exit;
  end;
  Result := s1;
  while (s1^ <> #0) do
  begin
    // for (sp = s2; *sp; sp++)
    sp := s2;
    while (sp^ <> #0) do
    begin
      if (sp^ = s1^) then
      begin
        s1^:= #0; Inc(s1);
        strtok_save := s1;
        Exit;
      end;
    end;
    Inc(s1);
  end;
  strtok_save := s1;
  Exit;
end;

(*
=================
EndDMLevel

The timelimit or fraglimit has been exceeded
=================
*)
procedure EndDMLevel;
var
  ent: edict_p;
  s, t, f: PChar;
const
  seps = ' ,'#10#13; // static const char *
begin
  // stay on same level flag
  if (Round(dmflags.value) and DF_SAME_LEVEL) <> 0 then
  begin
    BeginIntermission(CreateTargetChangeLevel(level.mapname));
    Exit;
  end;

{$IFDEF CTF}
  if (PChar(@level.forcemap)^ <> #0) then
  begin
    BeginIntermission(CreateTargetChangeLevel(level.forcemap));
    Exit;
  end;

{$ENDIF}
  // see if it's in the map list
  if (sv_maplist.string_^ <> #0) then
  begin
     s := StrNew(sv_maplist.string_);
     f := nil;
     t := strtok(s, seps);
     while (t <> nil) do
     begin
       if (Q_stricmp(t, level.mapname) = 0) then
       begin
         // it's in the list, go to the next one
         t := strtok(nil, seps);
         if (t = nil) then // end of list, go to first one
         begin
           if (f = nil) then // there isn't a first one, same level
             BeginIntermission(CreateTargetChangeLevel(level.mapname))
           else
             BeginIntermission(CreateTargetChangeLevel(f));
         end else
               BeginIntermission(CreateTargetChangeLevel(t));
         StrDispose(s);
         Exit;
       end;
       if (f = nil) then f := t;
       t := strtok(nil, seps);
     end;
     StrDispose(s);
  end;

  if (level.nextmap[0] <> #0) then // go to a specific map
    BeginIntermission(CreateTargetChangeLevel(level.nextmap))
  else
  begin	// search for a changelevel
    // #define FOFS(x) (int)&(((edict_t *)0)->x)
    // ent := G_Find(nil, FOFS(classname), 'target_changelevel');
    ent := G_Find(nil, Integer(@edict_p(nil).classname), 'target_changelevel');
    if (ent = nil) then
    begin	// the map designer didn't include a changelevel,
      // so create a fake ent that goes back to the same level
      BeginIntermission(CreateTargetChangeLevel(level.mapname));
      Exit;
    end;
    BeginIntermission(ent);
  end;
end;

{$IFNDEF CTF}

(*
=================
CheckNeedPass
=================
*)
procedure CheckNeedPass;
var
  need: Integer;
begin
  // if password or spectator_password has changed, update needpass
  // as needed
  if (password.modified or spectator_password.modified) then
  begin
    password.modified := (spectator_password.modified = False);

    need := 0;

    if (password.string_ <> nil) and
       (Q_stricmp(password.string_, 'none') <> 0)
    then need := need or 1;

    if (spectator_password.string_ <> nil) and
       (Q_stricmp(spectator_password.string_, 'none') <> 0)
    then need := need or 2;

    gi.cvar_set('needpass', va('%d', [need]));
  end;
end;

{$ENDIF}

(*
=================
CheckDMRules
=================
*)
procedure CheckDMRules;
var
  i: Integer;
  cl: gclient_p;
begin
  if (level.intermissiontime <> 0) then Exit;

⌨️ 快捷键说明

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