X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_game.pas;h=019fdc48445c2c861b49055aff9302419817fc90;hb=16342bee09fa001d05697571124e48a93cd35f2c;hp=4a79f98ebfd67d496271b8ed577b844402f19b2c;hpb=be2ad7bf5e09b4ee91a0c5ee741503ace8c7887c;p=d2df-sdl.git diff --git a/src/game/g_game.pas b/src/game/g_game.pas index 4a79f98..019fdc4 100644 --- a/src/game/g_game.pas +++ b/src/game/g_game.pas @@ -17,12 +17,15 @@ unit g_game; interface -uses - SysUtils, Classes, - MAPDEF, - g_basic, g_player, e_graphics, g_res_downloader, - g_sound, g_gui, utils, md5, mempool, xprofiler, - g_touch, g_weapons; + uses + {$IFDEF ENABLE_MENU} + g_gui, + {$ENDIF} + SysUtils, Classes, MAPDEF, + g_base, g_basic, g_player, g_res_downloader, + g_sound, utils, md5, mempool, xprofiler, + g_weapons + ; type TGameSettings = record @@ -84,10 +87,8 @@ procedure g_Game_Free (freeTextures: Boolean=true); procedure g_Game_LoadData(); procedure g_Game_FreeData(); procedure g_Game_Update(); -procedure g_Game_Draw(); +procedure g_Game_PreUpdate(); procedure g_Game_Quit(); -procedure g_Game_SetupScreenSize(); -procedure g_Game_ChangeResolution(newWidth, newHeight: Word; nowFull, nowMax: Boolean); function g_Game_ModeToText(Mode: Byte): string; function g_Game_TextToMode(Mode: string): Byte; procedure g_Game_ExecuteEvent(Name: String); @@ -112,7 +113,6 @@ function g_Game_GetNextMap(): String; procedure g_Game_NextLevel(); procedure g_Game_Pause(Enable: Boolean); procedure g_Game_HolmesPause(Enable: Boolean); -procedure g_Game_InGameMenu(Show: Boolean); function g_Game_IsWatchedPlayer(UID: Word): Boolean; function g_Game_IsWatchedTeam(Team: Byte): Boolean; procedure g_Game_Message(Msg: String; Time: Word); @@ -127,7 +127,9 @@ procedure g_Game_Announce_KillCombo(Param: Integer); procedure g_Game_Announce_BodyKill(SpawnerUID: Word); procedure g_Game_StartVote(Command, Initiator: string); procedure g_Game_CheckVote; -procedure g_TakeScreenShot(Filename: string = ''); +{$IFNDEF HEADLESS} + procedure g_TakeScreenShot(Filename: string = ''); +{$ENDIF} procedure g_FatalError(Text: String); procedure g_SimpleError(Text: String); function g_Game_IsTestMap(): Boolean; @@ -143,8 +145,19 @@ procedure g_Game_SetLoadingText(Text: String; Max: Integer; reWrite: Boolean); procedure g_Game_StepLoading(Value: Integer = -1); procedure g_Game_ClearLoading(); procedure g_Game_SetDebugMode(); -procedure DrawLoadingStat(); -procedure DrawMenuBackground(tex: AnsiString); + +function IsActivePlayer(p: TPlayer): Boolean; +function GetActivePlayerID_Next(Skip: Integer = -1): Integer; +procedure SortGameStat(var stat: TPlayerStatArray); + + +{$IFDEF ENABLE_MENU} + procedure g_Game_InGameMenu(Show: Boolean); +{$ENDIF} +{$IFNDEF HEADLESS} + procedure CharPress (C: AnsiChar); +{$ENDIF} + procedure KeyPress (K: Word); { procedure SetWinPause(Enable: Boolean); } @@ -167,22 +180,23 @@ const GM_COOP = 4; GM_SINGLE = 5; - MESSAGE_DIKEY = WM_USER + 1; - EXIT_QUIT = 1; EXIT_SIMPLE = 2; EXIT_RESTART = 3; EXIT_ENDLEVELSINGLE = 4; EXIT_ENDLEVELCUSTOM = 5; - GAME_OPTION_RESERVED = 1; - GAME_OPTION_TEAMDAMAGE = 2; - GAME_OPTION_ALLOWEXIT = 4; - GAME_OPTION_WEAPONSTAY = 8; - GAME_OPTION_MONSTERS = 16; - GAME_OPTION_BOTVSPLAYER = 32; - GAME_OPTION_BOTVSMONSTER = 64; - GAME_OPTION_DMKEYS = 128; + GAME_OPTION_RESERVED = 1; + GAME_OPTION_TEAMDAMAGE = 2; + GAME_OPTION_ALLOWEXIT = 4; + GAME_OPTION_WEAPONSTAY = 8; + GAME_OPTION_MONSTERS = 16; + GAME_OPTION_BOTVSPLAYER = 32; + GAME_OPTION_BOTVSMONSTER = 64; + GAME_OPTION_DMKEYS = 128; + GAME_OPTION_TEAMHITTRACE = 256; + GAME_OPTION_TEAMHITPROJECTILE = 512; + GAME_OPTION_TEAMABSORBDAMAGE = 1024; STATE_NONE = 0; STATE_MENU = 1; @@ -228,7 +242,6 @@ const STATFILE_VERSION = $03; var - gStdFont: DWORD; gGameSettings: TGameSettings; gPlayer1Settings: TPlayerSettings; gPlayer2Settings: TPlayerSettings; @@ -240,6 +253,7 @@ var gPlayer2: TPlayer = nil; gPlayerDrawn: TPlayer = nil; gTime: LongWord; + gLerpFactor: Single = 1.0; gSwitchGameMode: Byte = GM_DM; gHearPoint1, gHearPoint2: THearPoint; gSoundEffectsDF: Boolean = False; @@ -265,6 +279,7 @@ var gShowFPS: Boolean = False; gShowGoals: Boolean = True; gShowStat: Boolean = True; + gShowPIDs: Boolean = False; gShowKillMsg: Boolean = True; gShowLives: Boolean = True; gShowPing: Boolean = False; @@ -365,6 +380,7 @@ var g_rlayer_water: Boolean = true; g_rlayer_fore: Boolean = true; + wNeedTimeReset: Boolean = false; procedure g_ResetDynlights (); procedure g_AddDynLight (x, y, radius: Integer; r, g, b, a: Single); @@ -373,64 +389,444 @@ procedure g_DynLightExplosion (x, y, radius: Integer; r, g, b: Single); function conIsCheatsEnabled (): Boolean; inline; function gPause (): Boolean; inline; + type (* private state *) + TEndCustomGameStat = record + PlayerStat: TPlayerStatArray; + TeamStat: TTeamStat; + GameTime: LongWord; + GameMode: Byte; + Map, MapName: String; + end; + + TEndSingleGameStat = record + PlayerStat: Array [0..1] of record + Kills: Integer; + Secrets: Integer; + end; + GameTime: LongWord; + TwoPlayers: Boolean; + TotalSecrets: Integer; + end; + + TLoadingStat = record + CurValue: Integer; + MaxValue: Integer; + ShowCount: Integer; + Msgs: Array of String; + NextMsg: Word; + PBarWasHere: Boolean; // did we draw a progress bar for this message? + end; + + TDynLight = record + x, y, radius: Integer; + r, g, b, a: Single; + exploCount: Integer; + exploRadius: Integer; + end; + + var (* private state *) + CustomStat: TEndCustomGameStat; + StatShotDone: Boolean; + StatFilename: string = ''; // used by stat screenshot to save with the same name as the csv + SingleStat: TEndSingleGameStat; + LoadingStat: TLoadingStat; + MessageText: String; + IsDrawStat: Boolean; + EndingGameCounter: Byte; + UPS: Word; + g_playerLight: Boolean; + g_dynLights: array of TDynLight = nil; + g_dynLightCount: Integer = 0; + EndPicPath: AnsiString; // full path, used by render implementation uses -{$INCLUDE ../nogl/noGLuses.inc} -{$IFDEF ENABLE_HOLMES} - g_holmes, -{$ENDIF} - e_texture, e_res, g_textures, g_window, g_menu, + {$IFDEF ENABLE_HOLMES} + g_holmes, + {$ENDIF} + {$IFDEF ENABLE_MENU} + g_menu, + {$ENDIF} + {$IFDEF ENABLE_GFX} + g_gfx, + {$ENDIF} + {$IFDEF ENABLE_GIBS} + g_gibs, + {$ENDIF} + {$IFNDEF HEADLESS} + r_render, g_system, + {$ENDIF} + e_res, g_window, e_input, e_log, g_console, g_items, g_map, g_panel, - g_playermodel, g_gfx, g_options, Math, + g_playermodel, g_options, Math, g_triggers, g_monsters, e_sound, CONFIG, - g_language, g_net, g_main, + g_language, g_net, g_phys, ENet, e_msg, g_netmsg, g_netmaster, - sfs, wadreader, g_system; + sfs, wadreader; + var + charbuff: packed array [0..15] of AnsiChar = ( + ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' + ); +function Translit (const S: AnsiString): AnsiString; var - hasPBarGfx: Boolean = false; - + i: Integer; +begin + Result := S; + for i := 1 to Length(Result) do + begin + case Result[i] of + #$C9: Result[i] := 'Q'; + #$D6: Result[i] := 'W'; + #$D3: Result[i] := 'E'; + #$CA: Result[i] := 'R'; + #$C5: Result[i] := 'T'; + #$CD: Result[i] := 'Y'; + #$C3: Result[i] := 'U'; + #$D8: Result[i] := 'I'; + #$D9: Result[i] := 'O'; + #$C7: Result[i] := 'P'; + #$D5: Result[i] := '['; //Chr(219); + #$DA: Result[i] := ']'; //Chr(221); + #$D4: Result[i] := 'A'; + #$DB: Result[i] := 'S'; + #$C2: Result[i] := 'D'; + #$C0: Result[i] := 'F'; + #$CF: Result[i] := 'G'; + #$D0: Result[i] := 'H'; + #$CE: Result[i] := 'J'; + #$CB: Result[i] := 'K'; + #$C4: Result[i] := 'L'; + #$C6: Result[i] := ';'; //Chr(186); + #$DD: Result[i] := #39; //Chr(222); + #$DF: Result[i] := 'Z'; + #$D7: Result[i] := 'X'; + #$D1: Result[i] := 'C'; + #$CC: Result[i] := 'V'; + #$C8: Result[i] := 'B'; + #$D2: Result[i] := 'N'; + #$DC: Result[i] := 'M'; + #$C1: Result[i] := ','; //Chr(188); + #$DE: Result[i] := '.'; //Chr(190); + end; + end; +end; -// ////////////////////////////////////////////////////////////////////////// // -function gPause (): Boolean; inline; begin result := gPauseMain or gPauseHolmes; end; +function CheckCheat (ct: TStrings_Locale; eofs: Integer=0): Boolean; +var + ls1, ls2: string; +begin + ls1 := CheatEng[ct]; + ls2 := Translit(CheatRus[ct]); + if length(ls1) = 0 then ls1 := '~'; + if length(ls2) = 0 then ls2 := '~'; + result := + (Copy(charbuff, 17-Length(ls1)-eofs, Length(ls1)) = ls1) or + (Translit(Copy(charbuff, 17-Length(ls1)-eofs, Length(ls1))) = ls1) or + (Copy(charbuff, 17-Length(ls2)-eofs, Length(ls2)) = ls2) or + (Translit(Copy(charbuff, 17-Length(ls2)-eofs, Length(ls2))) = ls2); + { + if ct = I_GAME_CHEAT_JETPACK then + begin + e_WriteLog('ls1: ['+ls1+']', MSG_NOTIFY); + e_WriteLog('ls2: ['+ls2+']', MSG_NOTIFY); + e_WriteLog('bf0: ['+Copy(charbuff, 17-Length(ls1)-eofs, Length(ls1))+']', MSG_NOTIFY); + e_WriteLog('bf1: ['+Translit(Copy(charbuff, 17-Length(ls1)-eofs, Length(ls1)))+']', MSG_NOTIFY); + e_WriteLog('bf2: ['+Copy(charbuff, 17-Length(ls2)-eofs, Length(ls2))+']', MSG_NOTIFY); + e_WriteLog('bf3: ['+Translit(Copy(charbuff, 17-Length(ls2)-eofs, Length(ls2)))+']', MSG_NOTIFY); + end; + } +end; -// ////////////////////////////////////////////////////////////////////////// // -function conIsCheatsEnabled (): Boolean; inline; +procedure Cheat (); +const + CHEAT_DAMAGE = 500; +label + Cheated; +var + s, s2: string; + c: ShortString; + a: Integer; begin - result := false; - if g_Game_IsNet then exit; - if not gDebugMode then + { + if (not gGameOn) or (not gCheats) or ((gGameSettings.GameType <> GT_SINGLE) and + (gGameSettings.GameMode <> GM_COOP) and (not gDebugMode)) + or g_Game_IsNet then Exit; + } + if not gGameOn then exit; + if not conIsCheatsEnabled then exit; + + s := 'SOUND_GAME_RADIO'; + + // + if CheckCheat(I_GAME_CHEAT_GODMODE) then begin - //if not gCheats then exit; - if not (gGameSettings.GameType in [GT_SINGLE, GT_CUSTOM]) then exit; - if not (gGameSettings.GameMode in [GM_COOP, GM_SINGLE]) then exit; + if gPlayer1 <> nil then gPlayer1.GodMode := not gPlayer1.GodMode; + if gPlayer2 <> nil then gPlayer2.GodMode := not gPlayer2.GodMode; + goto Cheated; end; - result := true; + // RAMBO + if CheckCheat(I_GAME_CHEAT_WEAPONS) then + begin + if gPlayer1 <> nil then gPlayer1.AllRulez(False); + if gPlayer2 <> nil then gPlayer2.AllRulez(False); + goto Cheated; + end; + // TANK + if CheckCheat(I_GAME_CHEAT_HEALTH) then + begin + if gPlayer1 <> nil then gPlayer1.AllRulez(True); + if gPlayer2 <> nil then gPlayer2.AllRulez(True); + goto Cheated; + end; + // IDDQD + if CheckCheat(I_GAME_CHEAT_DEATH) then + begin + if gPlayer1 <> nil then gPlayer1.Damage(CHEAT_DAMAGE, 0, 0, 0, HIT_TRAP); + if gPlayer2 <> nil then gPlayer2.Damage(CHEAT_DAMAGE, 0, 0, 0, HIT_TRAP); + s := 'SOUND_MONSTER_HAHA'; + goto Cheated; + end; + // + if CheckCheat(I_GAME_CHEAT_DOORS) then + begin + g_Triggers_OpenAll(); + goto Cheated; + end; + // GOODBYE + if CheckCheat(I_GAME_CHEAT_NEXTMAP) then + begin + if gTriggers <> nil then + for a := 0 to High(gTriggers) do + if gTriggers[a].TriggerType = TRIGGER_EXIT then + begin + gExitByTrigger := True; + //g_Game_ExitLevel(gTriggers[a].Data.MapName); + g_Game_ExitLevel(gTriggers[a].tgcMap); + Break; + end; + goto Cheated; + end; + // + s2 := Copy(charbuff, 15, 2); + if CheckCheat(I_GAME_CHEAT_CHANGEMAP, 2) and (s2[1] >= '0') and (s2[1] <= '9') and (s2[2] >= '0') and (s2[2] <= '9') then + begin + if g_Map_Exist(gGameSettings.WAD + ':\MAP' + s2) then + begin + c := 'MAP' + s2; + g_Game_ExitLevel(c); + end; + goto Cheated; + end; + // + if CheckCheat(I_GAME_CHEAT_FLY) then + begin + gFly := not gFly; + goto Cheated; + end; + // BULLFROG + if CheckCheat(I_GAME_CHEAT_JUMPS) then + begin + VEL_JUMP := 30-VEL_JUMP; + goto Cheated; + end; + // FORMULA1 + if CheckCheat(I_GAME_CHEAT_SPEED) then + begin + MAX_RUNVEL := 32-MAX_RUNVEL; + goto Cheated; + end; + // CONDOM + if CheckCheat(I_GAME_CHEAT_SUIT) then + begin + if gPlayer1 <> nil then gPlayer1.GiveItem(ITEM_SUIT); + if gPlayer2 <> nil then gPlayer2.GiveItem(ITEM_SUIT); + goto Cheated; + end; + // + if CheckCheat(I_GAME_CHEAT_AIR) then + begin + if gPlayer1 <> nil then gPlayer1.GiveItem(ITEM_OXYGEN); + if gPlayer2 <> nil then gPlayer2.GiveItem(ITEM_OXYGEN); + goto Cheated; + end; + // PURELOVE + if CheckCheat(I_GAME_CHEAT_BERSERK) then + begin + if gPlayer1 <> nil then gPlayer1.GiveItem(ITEM_MEDKIT_BLACK); + if gPlayer2 <> nil then gPlayer2.GiveItem(ITEM_MEDKIT_BLACK); + goto Cheated; + end; + // + if CheckCheat(I_GAME_CHEAT_JETPACK) then + begin + if gPlayer1 <> nil then gPlayer1.GiveItem(ITEM_JETPACK); + if gPlayer2 <> nil then gPlayer2.GiveItem(ITEM_JETPACK); + goto Cheated; + end; + // CASPER + if CheckCheat(I_GAME_CHEAT_NOCLIP) then + begin + if gPlayer1 <> nil then gPlayer1.SwitchNoClip; + if gPlayer2 <> nil then gPlayer2.SwitchNoClip; + goto Cheated; + end; + // + if CheckCheat(I_GAME_CHEAT_NOTARGET) then + begin + if gPlayer1 <> nil then gPlayer1.NoTarget := not gPlayer1.NoTarget; + if gPlayer2 <> nil then gPlayer2.NoTarget := not gPlayer2.NoTarget; + goto Cheated; + end; + // INFERNO + if CheckCheat(I_GAME_CHEAT_NORELOAD) then + begin + if gPlayer1 <> nil then gPlayer1.NoReload := not gPlayer1.NoReload; + if gPlayer2 <> nil then gPlayer2.NoReload := not gPlayer2.NoReload; + goto Cheated; + end; + if CheckCheat(I_GAME_CHEAT_AIMLINE) then + begin + gAimLine := not gAimLine; + goto Cheated; + end; + if CheckCheat(I_GAME_CHEAT_AUTOMAP) then + begin + gShowMap := not gShowMap; + goto Cheated; + end; + Exit; + +Cheated: + g_Sound_PlayEx(s); end; -// ////////////////////////////////////////////////////////////////////////// // -var - profileFrameDraw: TProfiler = nil; +{$IFDEF ENABLE_MENU} +procedure KeyPress (K: Word); + var Msg: g_gui.TMessage; +begin + case K of + VK_ESCAPE: // : + begin + if (g_ActiveWindow <> nil) then + begin + Msg.Msg := WM_KEYDOWN; + Msg.WParam := VK_ESCAPE; + g_ActiveWindow.OnMessage(Msg); + if (not g_Game_IsNet) and (g_ActiveWindow = nil) then g_Game_Pause(false); //Fn loves to do this + end + else if (gState <> STATE_FOLD) then + begin + if gGameOn or (gState = STATE_INTERSINGLE) or (gState = STATE_INTERCUSTOM) then + begin + g_Game_InGameMenu(True); + end + else if (gExit = 0) and (gState <> STATE_SLIST) then + begin + if (gState <> STATE_MENU) then + begin + if (NetMode <> NET_NONE) then + begin + g_Game_StopAllSounds(True); + g_Game_Free; + gState := STATE_MENU; + Exit; + end; + end; + g_GUI_ShowWindow('MainMenu'); + g_Sound_PlayEx('MENU_OPEN'); + end; + end; + end; + IK_F2, IK_F3, IK_F4, IK_F5, IK_F6, IK_F7, IK_F10: + begin // .. � + if gGameOn and (not gConsoleShow) and (not gChatShow) then + begin + while (g_ActiveWindow <> nil) do g_GUI_HideWindow(False); + if (not g_Game_IsNet) then g_Game_Pause(True); + case K of + IK_F2: g_Menu_Show_SaveMenu(); + IK_F3: g_Menu_Show_LoadMenu(); + IK_F4: g_Menu_Show_GameSetGame(); + IK_F5: g_Menu_Show_OptionsVideo(); + IK_F6: g_Menu_Show_OptionsSound(); + IK_F7: g_Menu_Show_EndGameMenu(); + IK_F10: g_Menu_Show_QuitGameMenu(); + end; + end; + end; -// ////////////////////////////////////////////////////////////////////////// // -type - TDynLight = record - x, y, radius: Integer; - r, g, b, a: Single; - exploCount: Integer; - exploRadius: Integer; + else + begin + gJustChatted := False; + if gConsoleShow or gChatShow then + begin + g_Console_Control(K); + end + else if (g_ActiveWindow <> nil) then + begin + Msg.Msg := WM_KEYDOWN; + Msg.WParam := K; + g_ActiveWindow.OnMessage(Msg); + end + else if (gState = STATE_MENU) then + begin + g_GUI_ShowWindow('MainMenu'); + g_Sound_PlayEx('MENU_OPEN'); + end; + end; + end; +end; +{$ELSE} + procedure KeyPress (K: Word); + begin + gJustChatted := False; + if gConsoleShow or gChatShow then + begin + g_Console_Control(K); + end end; +{$ENDIF} -var - g_dynLights: array of TDynLight = nil; - g_dynLightCount: Integer = 0; - g_playerLight: Boolean = false; +{$IFNDEF HEADLESS} + procedure CharPress (C: AnsiChar); + {$IFDEF ENABLE_MENU} + var Msg: g_gui.TMessage; + {$ENDIF} + var a: Integer; + begin + if gConsoleShow or gChatShow then + begin + g_Console_Char(C); + end + {$IFDEF ENABLE_MENU} + else if g_ActiveWindow <> nil then + begin + Msg.Msg := WM_CHAR; + Msg.WParam := Ord(C); + g_ActiveWindow.OnMessage(Msg); + end + {$ENDIF} + else + begin + for a := 0 to 14 do + begin + charbuff[a] := charbuff[a + 1]; + end; + charbuff[15] := upcase1251(C); + Cheat; + end; + end; +{$ENDIF} + + +// ////////////////////////////////////////////////////////////////////////// // +function gPause (): Boolean; inline; begin result := gPauseMain or gPauseHolmes; end; procedure g_ResetDynlights (); var @@ -492,75 +888,22 @@ begin Inc(g_dynLightCount); end; - // ////////////////////////////////////////////////////////////////////////// // -function calcProfilesHeight (prof: TProfiler): Integer; -begin - result := 0; - if (prof = nil) then exit; - if (length(prof.bars) = 0) then exit; - result := length(prof.bars)*(16+2); -end; - -// returns width -function drawProfiles (x, y: Integer; prof: TProfiler): Integer; -var - wdt, hgt: Integer; - yy: Integer; - ii: Integer; +function conIsCheatsEnabled (): Boolean; inline; begin - result := 0; - if (prof = nil) then exit; - // gScreenWidth - if (length(prof.bars) = 0) then exit; - wdt := 192; - hgt := calcProfilesHeight(prof); - if (x < 0) then x := gScreenWidth-(wdt-1)+x; - if (y < 0) then y := gScreenHeight-(hgt-1)+y; - // background - //e_DrawFillQuad(x, y, x+wdt-1, y+hgt-1, 255, 255, 255, 200, B_BLEND); - //e_DrawFillQuad(x, y, x+wdt-1, y+hgt-1, 20, 20, 20, 0, B_NONE); - e_DarkenQuadWH(x, y, wdt, hgt, 150); - // title - yy := y+2; - for ii := 0 to High(prof.bars) do - begin - e_TextureFontPrintEx(x+2+4*prof.bars[ii].level, yy, Format('%s: %d', [prof.bars[ii].name, prof.bars[ii].value]), gStdFont, 255, 255, 0, 1, false); - Inc(yy, 16+2); - end; - result := wdt; + result := false; + if g_Game_IsNet then exit; + if not gDebugMode then + begin + //if not gCheats then exit; + if not (gGameSettings.GameType in [GT_SINGLE, GT_CUSTOM]) then exit; + if not (gGameSettings.GameMode in [GM_COOP, GM_SINGLE]) then exit; + end; + result := true; end; - // ////////////////////////////////////////////////////////////////////////// // type - TEndCustomGameStat = record - PlayerStat: TPlayerStatArray; - TeamStat: TTeamStat; - GameTime: LongWord; - GameMode: Byte; - Map, MapName: String; - end; - - TEndSingleGameStat = record - PlayerStat: Array [0..1] of record - Kills: Integer; - Secrets: Integer; - end; - GameTime: LongWord; - TwoPlayers: Boolean; - TotalSecrets: Integer; - end; - - TLoadingStat = record - CurValue: Integer; - MaxValue: Integer; - ShowCount: Integer; - Msgs: Array of String; - NextMsg: Word; - PBarWasHere: Boolean; // did we draw a progress bar for this message? - end; - TParamStrValue = record Name: String; Value: String; @@ -574,44 +917,19 @@ const INTER_ACTION_MUSIC = 3; var - FPS, UPS: Word; - FPSCounter, UPSCounter: Word; - FPSTime, UPSTime: LongWord; + UPSCounter: Word; + UPSTime: LongWord; DataLoaded: Boolean = False; - IsDrawStat: Boolean = False; - CustomStat: TEndCustomGameStat; - SingleStat: TEndSingleGameStat; - LoadingStat: TLoadingStat; - EndingGameCounter: Byte = 0; - MessageText: String; MessageTime: Word; - MessageLineLength: Integer = 80; MapList: SSArray = nil; MapIndex: Integer = -1; InterReadyTime: Integer = -1; - StatShotDone: Boolean = False; - StatFilename: string = ''; // used by stat screenshot to save with the same name as the csv StatDate: string = ''; MegaWAD: record info: TMegaWADInfo; endpic: String; endmus: String; - res: record - text: Array of ShortString; - anim: Array of ShortString; - pic: Array of ShortString; - mus: Array of ShortString; - end; - triggers: Array of record - event: ShortString; - actions: Array of record - action, p1, p2: Integer; - end; - end; - cur_trigger: Integer; - cur_action: Integer; end; - //InterPic: String; InterText: record lines: SSArray; img: String; @@ -800,37 +1118,20 @@ begin FreeMem(p); end; -procedure g_Game_FreeWAD(); -var - a: Integer; -begin - for a := 0 to High(MegaWAD.res.pic) do - if MegaWAD.res.pic[a] <> '' then - g_Texture_Delete(MegaWAD.res.pic[a]); - - for a := 0 to High(MegaWAD.res.mus) do - if MegaWAD.res.mus[a] <> '' then - g_Sound_Delete(MegaWAD.res.mus[a]); - - MegaWAD.res.pic := nil; - MegaWAD.res.text := nil; - MegaWAD.res.anim := nil; - MegaWAD.res.mus := nil; - MegaWAD.triggers := nil; - - g_Texture_Delete('TEXTURE_endpic'); - g_Sound_Delete('MUSIC_endmus'); - - ZeroMemory(@MegaWAD, SizeOf(MegaWAD)); - gGameSettings.WAD := ''; -end; + procedure g_Game_FreeWAD; + begin + EndPicPath := ''; + g_Sound_Delete('MUSIC_endmus'); + ZeroMemory(@MegaWAD, SizeOf(MegaWAD)); + gGameSettings.WAD := ''; + end; procedure g_Game_LoadWAD(WAD: string); var w: TWADFile; cfg: TConfig; p: Pointer; - {b, }len: Integer; + len: Integer; s: AnsiString; begin g_Game_FreeWAD(); @@ -851,41 +1152,12 @@ begin cfg := TConfig.CreateMem(p, len); - {b := 1; - while True do - begin - s := cfg.ReadStr('pic', 'pic'+IntToStr(b), ''); - if s = '' then Break; - b := b+1; - - SetLength(MegaWAD.res.pic, Length(MegaWAD.res.pic)+1); - MegaWAD.res.pic[High(MegaWAD.res.pic)] := s; - - g_Texture_CreateWADEx(s, s); - end; - - b := 1; - while True do - begin - s := cfg.ReadStr('mus', 'mus'+IntToStr(b), ''); - if s = '' then Break; - b := b+1; - - SetLength(MegaWAD.res.mus, Length(MegaWAD.res.mus)+1); - MegaWAD.res.mus[High(MegaWAD.res.mus)] := s; - - g_Music_CreateWADEx(s, s); - end;} - + EndPicPath := ''; MegaWAD.endpic := cfg.ReadStr('megawad', 'endpic', ''); if MegaWAD.endpic <> '' then - begin - TEXTUREFILTER := GL_LINEAR; - s := e_GetResourcePath(WadDirs, MegaWAD.endpic, WAD); - g_Texture_CreateWADEx('TEXTURE_endpic', s); - TEXTUREFILTER := GL_NEAREST; - end; - MegaWAD.endmus := cfg.ReadStr('megawad', 'endmus', 'Standart.wad:D2DMUS\ÊÎÍÅÖ'); + EndPicPath := e_GetResourcePath(WadDirs, MegaWAD.endpic, WAD); + + MegaWAD.endmus := cfg.ReadStr('megawad', 'endmus', 'Standart.wad:D2DMUS\КОНЕЦ'); if MegaWAD.endmus <> '' then begin s := e_GetResourcePath(WadDirs, MegaWAD.endmus, WAD); @@ -961,7 +1233,7 @@ begin gDelayedEvents[n].DENum := Num; gDelayedEvents[n].DEStr := Str; if DEType = DE_GLOBEVENT then - gDelayedEvents[n].Time := (sys_GetTicks() {div 1000}) + Time + gDelayedEvents[n].Time := (GetTickCount64() {div 1000}) + Time else gDelayedEvents[n].Time := gTime + Time; Result := n; @@ -976,7 +1248,7 @@ begin if g_Game_IsNet and g_Game_IsServer then MH_SEND_GameEvent(NET_EV_MAPEND, Byte(gMissionFailed)); -// Ñòîï èãðà: +// Стоп игра: gPauseMain := false; gPauseHolmes := false; gGameOn := false; @@ -987,31 +1259,37 @@ begin MessageText := ''; EndingGameCounter := 0; + +{$IFDEF ENABLE_MENU} g_ActiveWindow := nil; +{$ENDIF} gLMSRespawn := LMS_RESPAWN_NONE; gLMSRespawnTime := 0; case gExit of - EXIT_SIMPLE: // Âûõîä ÷åðåç ìåíþ èëè êîíåö òåñòà + EXIT_SIMPLE: // Выход через меню или конец теста begin g_Game_Free(); - if gMapOnce then - begin // Ýòî áûë òåñò - g_Game_Quit(); - end + begin // Это был тест + g_Game_Quit(); + end else - begin // Âûõîä â ãëàâíîå ìåíþ + begin // Выход в главное меню + {$IFDEF DISABLE_MENU} + gState := STATE_MENU; // ??? + {$ELSE} gMusic.SetByName('MUSIC_MENU'); gMusic.Play(); if gState <> STATE_SLIST then begin g_GUI_ShowWindow('MainMenu'); gState := STATE_MENU; - end else + end + else begin - // Îáíîâëÿåì ñïèñîê ñåðâåðîâ + // Обновляем список серверов slReturnPressed := True; if g_Net_Slist_Fetch(slCurrent) then begin @@ -1022,19 +1300,19 @@ begin slWaitStr := _lc[I_NET_SLIST_ERROR]; g_Serverlist_GenerateTable(slCurrent, slTable); end; - - g_Game_ExecuteEvent('ongameend'); - end; + {$ENDIF} + g_Game_ExecuteEvent('ongameend'); + end; end; - EXIT_RESTART: // Íà÷àòü óðîâåíü ñíà÷àëà + EXIT_RESTART: // Начать уровень сначала begin if not g_Game_IsClient then g_Game_Restart(); end; - EXIT_ENDLEVELCUSTOM: // Çàêîí÷èëñÿ óðîâåíü â Ñâîåé èãðå + EXIT_ENDLEVELCUSTOM: // Закончился уровень в Своей игре begin - // Ñòàòèñòèêà Ñâîåé èãðû: + // Статистика Своей игры: FileName := g_ExtractWadName(gMapInfo.Map); CustomStat.GameTime := gTime; @@ -1046,7 +1324,7 @@ begin CustomStat.PlayerStat := nil; - // Ñòàòèñòèêà èãðîêîâ: + // Статистика игроков: if gPlayers <> nil then begin for a := 0 to High(gPlayers) do @@ -1086,7 +1364,7 @@ begin if not g_Game_IsClient then g_Player_ResetReady; gInterReadyCount := 0; - // Çàòóõàþùèé ýêðàí: + // Затухающий экран: EndingGameCounter := 255; gState := STATE_FOLD; gInterTime := 0; @@ -1096,16 +1374,16 @@ begin gInterEndTime := gDefInterTime * 1000; end; - EXIT_ENDLEVELSINGLE: // Çàêîí÷èëñÿ óðîâåíü â Îäèíî÷íîé èãðå + EXIT_ENDLEVELSINGLE: // Закончился уровень в Одиночной игре begin - // Ñòàòèñòèêà Îäèíî÷íîé èãðû: + // Статистика Одиночной игры: SingleStat.GameTime := gTime; SingleStat.TwoPlayers := gPlayer2 <> nil; SingleStat.TotalSecrets := gSecretsCount; - // Ñòàòèñòèêà ïåðâîãî èãðîêà: + // Статистика первого игрока: SingleStat.PlayerStat[0].Kills := gPlayer1.MonsterKills; SingleStat.PlayerStat[0].Secrets := gPlayer1.Secrets; - // Ñòàòèñòèêà âòîðîãî èãðîêà (åñëè åñòü): + // Статистика второго игрока (если есть): if SingleStat.TwoPlayers then begin SingleStat.PlayerStat[1].Kills := gPlayer2.MonsterKills; @@ -1114,7 +1392,7 @@ begin g_Game_ExecuteEvent('onmapend'); - // Åñòü åùå êàðòû: + // Есть еще карты: if gNextMap <> '' then begin gMusic.SetByName('MUSIC_INTERMUS'); @@ -1124,314 +1402,41 @@ begin g_Game_ExecuteEvent('oninter'); end - else // Áîëüøå íåò êàðò + else // Больше нет карт begin - // Çàòóõàþùèé ýêðàí: + // Затухающий экран: EndingGameCounter := 255; gState := STATE_FOLD; end; end; end; -// Îêîí÷àíèå îáðàáîòàíî: +// Окончание обработано: if gExit <> EXIT_QUIT then gExit := 0; end; -procedure drawTime(X, Y: Integer); inline; +procedure g_Game_Init(); begin - e_TextureFontPrint(x, y, - Format('%d:%.2d:%.2d', [ - gTime div 1000 div 3600, - (gTime div 1000 div 60) mod 60, - gTime div 1000 mod 60 - ]), - gStdFont); -end; + gExit := 0; + gMapToDelete := ''; + gTempDelete := False; -procedure DrawStat(); -var - pc, x, y, w, h: Integer; - w1, w2, w3, w4: Integer; - a, aa: Integer; - cw, ch, r, g, b, rr, gg, bb: Byte; - s1, s2, s3: String; - _y: Integer; - stat: TPlayerStatArray; - wad, map: string; - mapstr: string; -begin - s1 := ''; - s2 := ''; - s3 := ''; - pc := g_Player_GetCount; - e_TextureFontGetSize(gStdFont, cw, ch); - - w := gScreenWidth-(gScreenWidth div 5); - if gGameSettings.GameMode in [GM_TDM, GM_CTF] then - h := 32+ch*(11+pc) - else - h := 40+ch*5+(ch+8)*pc; - x := (gScreenWidth div 2)-(w div 2); - y := (gScreenHeight div 2)-(h div 2); + sfsGCDisable(); // temporary disable removing of temporary volumes - e_DrawFillQuad(x, y, x+w-1, y+h-1, 64, 64, 64, 32); - e_DrawQuad(x, y, x+w-1, y+h-1, 255, 127, 0); + try + g_Game_ClearLoading(); + g_Game_SetLoadingText(Format('Doom 2D: Forever %s', [GAME_VERSION]), 0, False); + g_Game_SetLoadingText('', 0, False); - drawTime(x+w-78, y+8); +// g_Game_SetLoadingText(_lc[I_LOAD_MODELS], 0, False); - wad := g_ExtractWadNameNoPath(gMapInfo.Map); - map := g_ExtractFileName(gMapInfo.Map); - mapstr := wad + ':\' + map + ' - ' + gMapInfo.Name; + gGameOn := false; + gPauseMain := false; + gPauseHolmes := false; + gTime := 0; - case gGameSettings.GameMode of - GM_DM: - begin - if gGameSettings.MaxLives = 0 then - s1 := _lc[I_GAME_DM] - else - s1 := _lc[I_GAME_LMS]; - s2 := Format(_lc[I_GAME_FRAG_LIMIT], [gGameSettings.GoalLimit]); - s3 := Format(_lc[I_GAME_TIME_LIMIT], [gGameSettings.TimeLimit div 3600, (gGameSettings.TimeLimit div 60) mod 60, gGameSettings.TimeLimit mod 60]); - end; - - GM_TDM: - begin - if gGameSettings.MaxLives = 0 then - s1 := _lc[I_GAME_TDM] - else - s1 := _lc[I_GAME_TLMS]; - s2 := Format(_lc[I_GAME_FRAG_LIMIT], [gGameSettings.GoalLimit]); - s3 := Format(_lc[I_GAME_TIME_LIMIT], [gGameSettings.TimeLimit div 3600, (gGameSettings.TimeLimit div 60) mod 60, gGameSettings.TimeLimit mod 60]); - end; - - GM_CTF: - begin - s1 := _lc[I_GAME_CTF]; - s2 := Format(_lc[I_GAME_SCORE_LIMIT], [gGameSettings.GoalLimit]); - s3 := Format(_lc[I_GAME_TIME_LIMIT], [gGameSettings.TimeLimit div 3600, (gGameSettings.TimeLimit div 60) mod 60, gGameSettings.TimeLimit mod 60]); - end; - - GM_COOP: - begin - if gGameSettings.MaxLives = 0 then - s1 := _lc[I_GAME_COOP] - else - s1 := _lc[I_GAME_SURV]; - s2 := _lc[I_GAME_MONSTERS] + ' ' + IntToStr(gCoopMonstersKilled) + '/' + IntToStr(gTotalMonsters); - s3 := _lc[I_GAME_SECRETS] + ' ' + IntToStr(gCoopSecretsFound) + '/' + IntToStr(gSecretsCount); - end; - - else - begin - s1 := ''; - s2 := ''; - end; - end; - - _y := y+8; - e_TextureFontPrintEx(x+(w div 2)-(Length(s1)*cw div 2), _y, s1, gStdFont, 255, 255, 255, 1); - _y := _y+ch+8; - e_TextureFontPrintEx(x+(w div 2)-(Length(mapstr)*cw div 2), _y, mapstr, gStdFont, 200, 200, 200, 1); - _y := _y+ch+8; - e_TextureFontPrintEx(x+16, _y, s2, gStdFont, 200, 200, 200, 1); - - e_TextureFontPrintEx(x+w-16-(Length(s3))*cw, _y, s3, - gStdFont, 200, 200, 200, 1); - - if NetMode = NET_SERVER then - e_TextureFontPrintEx(x+8, y + 8, _lc[I_NET_SERVER], gStdFont, 255, 255, 255, 1) - else - if NetMode = NET_CLIENT then - e_TextureFontPrintEx(x+8, y + 8, - NetClientIP + ':' + IntToStr(NetClientPort), gStdFont, 255, 255, 255, 1); - - if pc = 0 then - Exit; - stat := g_Player_GetStats(); - SortGameStat(stat); - - w2 := (w-16) div 6 + 48; // øèðèíà 2 ñòîëáöà - w3 := (w-16) div 6; // øèðèíà 3 è 4 ñòîëáöîâ - w4 := w3; - w1 := w-16-w2-w3-w4; // îñòàâøååñÿ ïðîñòðàíñòâî - äëÿ öâåòà è èìåíè èãðîêà - - if gGameSettings.GameMode in [GM_TDM, GM_CTF] then - begin - _y := _y+ch+ch; - - for a := TEAM_RED to TEAM_BLUE do - begin - if a = TEAM_RED then - begin - s1 := _lc[I_GAME_TEAM_RED]; - r := 255; - g := 0; - b := 0; - end - else - begin - s1 := _lc[I_GAME_TEAM_BLUE]; - r := 0; - g := 0; - b := 255; - end; - - e_TextureFontPrintEx(x+16, _y, s1, gStdFont, r, g, b, 1); - e_TextureFontPrintEx(x+w1+16, _y, IntToStr(gTeamStat[a].Goals), - gStdFont, r, g, b, 1); - - _y := _y+ch+(ch div 4); - e_DrawLine(1, x+16, _y, x+w-16, _y, r, g, b); - _y := _y+(ch div 4); - - for aa := 0 to High(stat) do - if stat[aa].Team = a then - with stat[aa] do - begin - if Spectator then - begin - rr := r div 2; - gg := g div 2; - bb := b div 2; - end - else - begin - rr := r; - gg := g; - bb := b; - end; - // Èìÿ - e_TextureFontPrintEx(x+16, _y, Name, gStdFont, rr, gg, bb, 1); - // Ïèíã/ïîòåðè - e_TextureFontPrintEx(x+w1+16, _y, Format(_lc[I_GAME_PING_MS], [Ping, Loss]), gStdFont, rr, gg, bb, 1); - // Ôðàãè - e_TextureFontPrintEx(x+w1+w2+16, _y, IntToStr(Frags), gStdFont, rr, gg, bb, 1); - // Ñìåðòè - e_TextureFontPrintEx(x+w1+w2+w3+16, _y, IntToStr(Deaths), gStdFont, rr, gg, bb, 1); - _y := _y+ch; - end; - - _y := _y+ch; - end; - end - else if gGameSettings.GameMode in [GM_DM, GM_COOP] then - begin - _y := _y+ch+ch; - e_TextureFontPrintEx(x+16, _y, _lc[I_GAME_PLAYER_NAME], gStdFont, 255, 127, 0, 1); - e_TextureFontPrintEx(x+16+w1, _y, _lc[I_GAME_PING], gStdFont, 255, 127, 0, 1); - e_TextureFontPrintEx(x+16+w1+w2, _y, _lc[I_GAME_FRAGS], gStdFont, 255, 127, 0, 1); - e_TextureFontPrintEx(x+16+w1+w2+w3, _y, _lc[I_GAME_DEATHS], gStdFont, 255, 127, 0, 1); - - _y := _y+ch+8; - for aa := 0 to High(stat) do - with stat[aa] do - begin - if Spectator then - begin - r := 127; - g := 64; - end - else - begin - r := 255; - g := 127; - end; - // Öâåò èãðîêà - e_DrawFillQuad(x+16, _y+4, x+32-1, _y+16+4-1, Color.R, Color.G, Color.B, 0); - e_DrawQuad(x+16, _y+4, x+32-1, _y+16+4-1, 192, 192, 192); - // Èìÿ - e_TextureFontPrintEx(x+16+16+8, _y+4, Name, gStdFont, r, g, 0, 1); - // Ïèíã/ïîòåðè - e_TextureFontPrintEx(x+w1+16, _y+4, Format(_lc[I_GAME_PING_MS], [Ping, Loss]), gStdFont, r, g, 0, 1); - // Ôðàãè - e_TextureFontPrintEx(x+w1+w2+16, _y+4, IntToStr(Frags), gStdFont, r, g, 0, 1); - // Ñìåðòè - e_TextureFontPrintEx(x+w1+w2+w3+16, _y+4, IntToStr(Deaths), gStdFont, r, g, 0, 1); - _y := _y+ch+8; - end; - end -end; - -procedure g_Game_Init(); -var - SR: TSearchRec; - knownFiles: array of AnsiString = nil; - found: Boolean; - wext, s: AnsiString; - f: Integer; -begin - gExit := 0; - gMapToDelete := ''; - gTempDelete := False; - - sfsGCDisable(); // temporary disable removing of temporary volumes - - try - TEXTUREFILTER := GL_LINEAR; - g_Texture_CreateWADEx('MENU_BACKGROUND', GameWAD+':TEXTURES\TITLE'); - g_Texture_CreateWADEx('INTER', GameWAD+':TEXTURES\INTER'); - g_Texture_CreateWADEx('ENDGAME_EN', GameWAD+':TEXTURES\ENDGAME_EN'); - g_Texture_CreateWADEx('ENDGAME_RU', GameWAD+':TEXTURES\ENDGAME_RU'); - TEXTUREFILTER := GL_NEAREST; - - LoadStdFont('STDTXT', 'STDFONT', gStdFont); - LoadFont('MENUTXT', 'MENUFONT', gMenuFont); - LoadFont('SMALLTXT', 'SMALLFONT', gMenuSmallFont); - - g_Game_ClearLoading(); - g_Game_SetLoadingText(Format('Doom 2D: Forever %s', [GAME_VERSION]), 0, False); - g_Game_SetLoadingText('', 0, False); - - g_Game_SetLoadingText(_lc[I_LOAD_CONSOLE], 0, False); - g_Console_Init(); - - g_Game_SetLoadingText(_lc[I_LOAD_MODELS], 0, False); - g_PlayerModel_LoadData(); - - // load models from all possible wad types, in all known directories - // this does a loosy job (linear search, ooph!), but meh - for wext in wadExtensions do - begin - for f := High(ModelDirs) downto Low(ModelDirs) do - begin - if (FindFirst(ModelDirs[f]+DirectorySeparator+'*'+wext, faAnyFile, SR) = 0) then - begin - repeat - found := false; - for s in knownFiles do - begin - if (strEquCI1251(forceFilenameExt(SR.Name, ''), forceFilenameExt(ExtractFileName(s), ''))) then - begin - found := true; - break; - end; - end; - if not found then - begin - SetLength(knownFiles, length(knownFiles)+1); - knownFiles[High(knownFiles)] := ModelDirs[f]+DirectorySeparator+SR.Name; - end; - until (FindNext(SR) <> 0); - end; - FindClose(SR); - end; - end; - - if (length(knownFiles) = 0) then raise Exception.Create('no player models found!'); - - if (length(knownFiles) = 1) then e_LogWriteln('1 player model found.', TMsgType.Notify) else e_LogWritefln('%d player models found.', [Integer(length(knownFiles))], TMsgType.Notify); - for s in knownFiles do - begin - if not g_PlayerModel_Load(s) then e_LogWritefln('Error loading model "%s"', [s], TMsgType.Warning); - end; - - gGameOn := false; - gPauseMain := false; - gPauseHolmes := false; - gTime := 0; - - {e_MouseInfo.Accel := 1.0;} + {e_MouseInfo.Accel := 1.0;} g_Game_SetLoadingText(_lc[I_LOAD_GAME_DATA], 0, False); g_Game_LoadData(); @@ -1442,11 +1447,6 @@ begin g_Sound_CreateWADEx('MUSIC_ROUNDMUS', GameWAD+':MUSIC\ROUNDMUS', True, True); g_Sound_CreateWADEx('MUSIC_STDENDMUS', GameWAD+':MUSIC\ENDMUS', True); -{$IFNDEF HEADLESS} - g_Game_SetLoadingText(_lc[I_LOAD_MENUS], 0, False); - g_Menu_Init(); -{$ENDIF} - gMusic := TMusic.Create(); gMusic.SetByName('MUSIC_MENU'); gMusic.Play(); @@ -1493,25 +1493,6 @@ begin Result := (not p.FDummy) and (not p.FSpectator); end; -function GetActivePlayer_ByID(ID: Integer): TPlayer; -var - a: Integer; -begin - Result := nil; - if ID < 0 then - Exit; - if gPlayers = nil then - Exit; - for a := Low(gPlayers) to High(gPlayers) do - if IsActivePlayer(gPlayers[a]) then - begin - if gPlayers[a].UID <> ID then - continue; - Result := gPlayers[a]; - break; - end; -end; - function GetActivePlayerID_Next(Skip: Integer = -1): Integer; var a, idx: Integer; @@ -1629,13 +1610,13 @@ begin MoveButton := MoveButton and $0F; if gPlayerAction[p, ACTION_MOVELEFT] and (not gPlayerAction[p, ACTION_MOVERIGHT]) then - MoveButton := 1 // Íàæàòà òîëüêî "Âëåâî" + MoveButton := 1 // Нажата только "Влево" else if (not gPlayerAction[p, ACTION_MOVELEFT]) and gPlayerAction[p, ACTION_MOVERIGHT] then - MoveButton := 2 // Íàæàòà òîëüêî "Âïðàâî" + MoveButton := 2 // Нажата только "Вправо" else if (not gPlayerAction[p, ACTION_MOVELEFT]) and (not gPlayerAction[p, ACTION_MOVERIGHT]) then - MoveButton := 0; // Íå íàæàòû íè "Âëåâî", íè "Âïðàâî" + MoveButton := 0; // Не нажаты ни "Влево", ни "Вправо" - // Ñåé÷àñ èëè ðàíüøå áûëè íàæàòû "Âëåâî"/"Âïðàâî" => ïåðåäàåì èãðîêó: + // Сейчас или раньше были нажаты "Влево"/"Вправо" => передаем игроку: if MoveButton = 1 then plr.PressKey(KEY_LEFT, time) else if MoveButton = 2 then @@ -1656,13 +1637,13 @@ begin else begin strafeDir := 0; // not strafing anymore - // Ðàíüøå áûëà íàæàòà "Âïðàâî", à ñåé÷àñ "Âëåâî" => áåæèì âïðàâî, ñìîòðèì âëåâî: + // Раньше была нажата "Вправо", а сейчас "Влево" => бежим вправо, смотрим влево: if (MoveButton = 2) and gPlayerAction[p, ACTION_MOVELEFT] then plr.SetDirection(TDirection.D_LEFT) - // Ðàíüøå áûëà íàæàòà "Âëåâî", à ñåé÷àñ "Âïðàâî" => áåæèì âëåâî, ñìîòðèì âïðàâî: + // Раньше была нажата "Влево", а сейчас "Вправо" => бежим влево, смотрим вправо: else if (MoveButton = 1) and gPlayerAction[p, ACTION_MOVERIGHT] then plr.SetDirection(TDirection.D_RIGHT) - // ×òî-òî áûëî íàæàòî è íå èçìåíèëîñü => êóäà áåæèì, òóäà è ñìîòðèì: + // Что-то было нажато и не изменилось => куда бежим, туда и смотрим: else if MoveButton <> 0 then plr.SetDirection(TDirection(MoveButton-1)) end; @@ -1670,7 +1651,7 @@ begin // fix movebutton state MoveButton := MoveButton or (strafeDir shl 4); - // Îñòàëüíûå êëàâèøè: + // Остальные клавиши: if gPlayerAction[p, ACTION_JUMP] then plr.PressKey(KEY_JUMP, time); if gPlayerAction[p, ACTION_LOOKUP] then plr.PressKey(KEY_UP, time); if gPlayerAction[p, ACTION_LOOKDOWN] then plr.PressKey(KEY_DOWN, time); @@ -1691,6 +1672,7 @@ begin end end; +{$IFDEF ENABLE_MENU} // HACK: add dynlight here if gwin_k8_enable_light_experiments then begin @@ -1705,6 +1687,7 @@ begin end; if gwin_has_stencil and g_playerLight then g_AddDynLight(plr.GameX+32, plr.GameY+40, 128, 1, 1, 0, 0.6); +{$ENDIF} end; // HACK: don't have a "key was pressed" function @@ -1715,13 +1698,26 @@ begin MC_SEND_CheatRequest(NET_CHEAT_READY); end; +procedure g_Game_PreUpdate(); +begin + // these are in separate PreUpdate functions because they can interact during Update() + // and are synced over the net + // we don't care that much about corpses and gibs + g_Player_PreUpdate(); + g_Monsters_PreUpdate(); + g_Items_PreUpdate(); + g_Weapon_PreUpdate(); +end; + procedure g_Game_Update(); -var - Msg: g_gui.TMessage; - Time: Int64; - a: Byte; - w: Word; - i, b: Integer; + var + {$IFDEF ENABLE_MENU} + Msg: g_gui.TMessage; + w: Word; + {$ENDIF} + Time: Int64; + a: Byte; + i, b: Integer; function sendMonsPos (mon: TMonster): Boolean; begin @@ -1754,10 +1750,10 @@ begin g_ResetDynlights(); framePool.reset(); -// Ïîðà âûêëþ÷àòü èãðó: +// Пора выключать игру: if gExit = EXIT_QUIT then Exit; -// Èãðà çàêîí÷èëàñü - îáðàáàòûâàåì: +// Игра закончилась - обрабатываем: if gExit <> 0 then begin EndGame(); @@ -1765,10 +1761,10 @@ begin Exit; end; - // ×èòàåì êëàâèàòóðó è äæîéñòèê, åñëè îêíî àêòèâíî + // Читаем клавиатуру и джойстик, если окно активно // no need to, as we'll do it in event handler -// Îáíîâëÿåì êîíñîëü (äâèæåíèå è ñîîáùåíèÿ): +// Обновляем консоль (движение и сообщения): g_Console_Update(); if (NetMode = NET_NONE) and (g_Game_IsNet) and (gGameOn or (gState in [STATE_FOLD, STATE_INTERCUSTOM])) then @@ -1782,10 +1778,10 @@ begin g_Net_Slist_Pulse(); case gState of - STATE_INTERSINGLE, // Ñòàòèñòêà ïîñëå ïðîõîæäåíèÿ óðîâíÿ â Îäèíî÷íîé èãðå - STATE_INTERCUSTOM, // Ñòàòèñòêà ïîñëå ïðîõîæäåíèÿ óðîâíÿ â Ñâîåé èãðå - STATE_INTERTEXT, // Òåêñò ìåæäó óðîâíÿìè - STATE_INTERPIC: // Êàðòèíêà ìåæäó óðîâíÿìè + STATE_INTERSINGLE, // Статистка после прохождения уровня в Одиночной игре + STATE_INTERCUSTOM, // Статистка после прохождения уровня в Своей игре + STATE_INTERTEXT, // Текст между уровнями + STATE_INTERPIC: // Картинка между уровнями begin if g_Game_IsNet and g_Game_IsServer then begin @@ -1808,32 +1804,36 @@ begin e_KeyPressed(JOY2_ATTACK) or e_KeyPressed(JOY3_ATTACK) ) and (not gJustChatted) and (not gConsoleShow) and (not gChatShow) +{$IFDEF ENABLE_MENU} and (g_ActiveWindow = nil) +{$ENDIF} ) or (g_Game_IsNet and ((gInterTime > gInterEndTime) or ((gInterReadyCount >= NetClientCount) and (NetClientCount > 0)))) ) then - begin // Íàæàëè /<Ïðîáåë> èëè ïðîøëî äîñòàòî÷íî âðåìåíè: + begin // Нажали /<Пробел> или прошло достаточно времени: g_Game_StopAllSounds(True); - if gMapOnce then // Ýòî áûë òåñò + if gMapOnce then // Это был тест gExit := EXIT_SIMPLE else - if gNextMap <> '' then // Ïåðåõîäèì íà ñëåäóþùóþ êàðòó + if gNextMap <> '' then // Переходим на следующую карту g_Game_ChangeMap(gNextMap) - else // Ñëåäóþùåé êàðòû íåò + else // Следующей карты нет begin if gGameSettings.GameType in [GT_CUSTOM, GT_SERVER] then begin - // Âûõîä â ãëàâíîå ìåíþ: + // Выход в главное меню: g_Game_Free; +{$IFDEF ENABLE_MENU} g_GUI_ShowWindow('MainMenu'); gMusic.SetByName('MUSIC_MENU'); gMusic.Play(); +{$ENDIF} gState := STATE_MENU; end else begin - // Ôèíàëüíàÿ êàðòèíêà: + // Финальная картинка: g_Game_ExecuteEvent('onwadend'); g_Game_Free(); if not gMusic.SetByName('MUSIC_endmus') then @@ -1855,7 +1855,9 @@ begin e_KeyPressed(JOY2_ATTACK) or e_KeyPressed(JOY3_ATTACK) ) and (not gJustChatted) and (not gConsoleShow) and (not gChatShow) +{$IFDEF ENABLE_MENU} and (g_ActiveWindow = nil) +{$ENDIF} ) then begin @@ -1868,11 +1870,11 @@ begin InterText.counter := InterText.counter - 1; end; - STATE_FOLD: // Çàòóõàíèå ýêðàíà + STATE_FOLD: // Затухание экрана begin if EndingGameCounter = 0 then begin - // Çàêîí÷èëñÿ óðîâåíü â Ñâîåé èãðå: + // Закончился уровень в Своей игре: if gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT] then begin InterReadyTime := -1; @@ -1889,7 +1891,7 @@ begin gState := STATE_INTERCUSTOM; e_UnpressAllKeys(); end - else // Çàêîí÷èëàñü ïîñëåäíÿÿ êàðòà â Îäèíî÷íîé èãðå + else // Закончилась последняя карта в Одиночной игре begin gMusic.SetByName('MUSIC_INTERMUS'); gMusic.Play(); @@ -1902,9 +1904,9 @@ begin DecMin(EndingGameCounter, 6, 0); end; - STATE_ENDPIC: // Êàðòèíêà îêîí÷àíèÿ ìåãàÂàäà + STATE_ENDPIC: // Картинка окончания мегаВада begin - if gMapOnce then // Ýòî áûë òåñò + if gMapOnce then // Это был тест begin gExit := EXIT_SIMPLE; Exit; @@ -1915,17 +1917,17 @@ begin g_Serverlist_Control(slCurrent, slTable); end; -// Ñòàòèñòèêà ïî Tab: +// Статистика по Tab: if gGameOn then IsDrawStat := (not gConsoleShow) and (not gChatShow) and (gGameSettings.GameType <> GT_SINGLE) and g_Console_Action(ACTION_SCORES); -// Èãðà èäåò: +// Игра идет: if gGameOn and not gPause and (gState <> STATE_FOLD) then begin - // Âðåìÿ += 28 ìèëëèñåêóíä: + // Время += 28 миллисекунд: gTime := gTime + GAME_TICK; - // Ñîîáùåíèå ïîñåðåäèíå ýêðàíà: + // Сообщение посередине экрана: if MessageTime = 0 then MessageText := ''; if MessageTime > 0 then @@ -1933,19 +1935,19 @@ begin if (g_Game_IsServer) then begin - // Áûë çàäàí ëèìèò âðåìåíè: + // Был задан лимит времени: if (gGameSettings.TimeLimit > 0) then if (gTime - gGameStartTime) div 1000 >= gGameSettings.TimeLimit then - begin // Îí ïðîøåë => êîíåö óðîâíÿ + begin // Он прошел => конец уровня g_Game_NextLevel(); Exit; end; - // Íàäî ðåñïàâíèòü èãðîêîâ â LMS: + // Надо респавнить игроков в LMS: if (gLMSRespawn > LMS_RESPAWN_NONE) and (gLMSRespawnTime < gTime) then g_Game_RestartRound(gLMSSoftSpawn); - // Ïðîâåðèì ðåçóëüòàò ãîëîñîâàíèÿ, åñëè âðåìÿ ïðîøëî + // Проверим результат голосования, если время прошло if gVoteInProgress and (gVoteTimer < gTime) then g_Game_CheckVote else if gVotePassed and (gVoteCmdTimer < gTime) then @@ -1955,19 +1957,19 @@ begin gVotePassed := False; end; - // Çàìåðÿåì âðåìÿ çàõâàòà ôëàãîâ + // Замеряем время захвата флагов if gFlags[FLAG_RED].State = FLAG_STATE_CAPTURED then gFlags[FLAG_RED].CaptureTime := gFlags[FLAG_RED].CaptureTime + GAME_TICK; if gFlags[FLAG_BLUE].State = FLAG_STATE_CAPTURED then gFlags[FLAG_BLUE].CaptureTime := gFlags[FLAG_BLUE].CaptureTime + GAME_TICK; - // Áûë çàäàí ëèìèò ïîáåä: + // Был задан лимит побед: if (gGameSettings.GoalLimit > 0) then begin b := 0; if gGameSettings.GameMode = GM_DM then - begin //  DM èùåì èãðîêà ñ max ôðàãàìè + begin // В DM ищем игрока с max фрагами for i := 0 to High(gPlayers) do if gPlayers[i] <> nil then if gPlayers[i].Frags > b then @@ -1975,11 +1977,11 @@ begin end else if gGameSettings.GameMode in [GM_TDM, GM_CTF] then - begin //  CTF/TDM âûáèðàåì êîìàíäó ñ íàèáîëüøèì ñ÷åòîì + begin // В CTF/TDM выбираем команду с наибольшим счетом b := Max(gTeamStat[TEAM_RED].Goals, gTeamStat[TEAM_BLUE].Goals); end; - // Ëèìèò ïîáåä íàáðàí => êîíåö óðîâíÿ: + // Лимит побед набран => конец уровня: if b >= gGameSettings.GoalLimit then begin g_Game_NextLevel(); @@ -1987,10 +1989,14 @@ begin end; end; - // Îáðàáàòûâàåì êëàâèøè èãðîêîâ: + // Обрабатываем клавиши игроков: if gPlayer1 <> nil then gPlayer1.ReleaseKeys(); if gPlayer2 <> nil then gPlayer2.ReleaseKeys(); +{$IFDEF DISABLE_MENU} + if (not gConsoleShow) and (not gChatShow) then +{$ELSE} if (not gConsoleShow) and (not gChatShow) and (g_ActiveWindow = nil) then +{$ENDIF} begin ProcessPlayerControls(gPlayer1, 0, P1MoveButton); ProcessPlayerControls(gPlayer2, 1, P2MoveButton); @@ -2002,9 +2008,13 @@ begin // process weapon switch queue end; // if server - // Íàáëþäàòåëü - if (gPlayer1 = nil) and (gPlayer2 = nil) and - (not gConsoleShow) and (not gChatShow) and (g_ActiveWindow = nil) then + // Наблюдатель + if (gPlayer1 = nil) and (gPlayer2 = nil) + and (not gConsoleShow) and (not gChatShow) +{$IFDEF ENABLE_MENU} + and (g_ActiveWindow = nil) +{$ENDIF} + then begin if not gSpectKeyPress then begin @@ -2161,14 +2171,19 @@ begin end; end; - // Îáíîâëÿåì âñå îñòàëüíîå: + // Обновляем все остальное: g_Map_Update(); g_Items_Update(); g_Triggers_Update(); g_Weapon_Update(); g_Monsters_Update(); - g_GFX_Update(); + {$IFDEF ENABLE_GFX} + g_GFX_Update; + {$ENDIF} g_Player_UpdateAll(); + {$IFDEF ENABLE_GIBS} + g_Gibs_Update; + {$ENDIF} g_Player_UpdatePhysicalObjects(); // server: send newly spawned monsters unconditionally @@ -2247,7 +2262,8 @@ begin end; end; // if gameOn ... -// Àêòèâíî îêíî èíòåðôåéñà - ïåðåäàåì êëàâèøè åìó: +// Активно окно интерфейса - передаем клавиши ему: +{$IFDEF ENABLE_MENU} if g_ActiveWindow <> nil then begin w := e_GetFirstKeyPressed(); @@ -2259,33 +2275,33 @@ begin g_ActiveWindow.OnMessage(Msg); end; - // Åñëè îíî îò ýòîãî íå çàêðûëîñü, òî îáíîâëÿåì: + // Если оно от этого не закрылось, то обновляем: if g_ActiveWindow <> nil then g_ActiveWindow.Update(); - // Íóæíî ñìåíèòü ðàçðåøåíèå: + // Нужно сменить разрешение: if gResolutionChange then begin - e_WriteLog('Changing resolution', TMsgType.Notify); - g_Game_ChangeResolution(gRC_Width, gRC_Height, gRC_FullScreen, gRC_Maximized); + {$IFNDEF HEADLESS} + e_WriteLog('Changing resolution', TMsgType.Notify); + r_Render_Apply; + {$ENDIF} gResolutionChange := False; g_ActiveWindow := nil; end; - // Íóæíî ñìåíèòü ÿçûê: + // Нужно сменить язык: if gLanguageChange then begin //e_WriteLog('Read language file', MSG_NOTIFY); //g_Language_Load(DataDir + gLanguage + '.txt'); g_Language_Set(gLanguage); -{$IFNDEF HEADLESS} g_Menu_Reset(); -{$ENDIF} gLanguageChange := False; end; end; -// Ãîðÿ÷àÿ êëàâèøà äëÿ âûçîâà ìåíþ âûõîäà èç èãðû (F10): +// Горячая клавиша для вызова меню выхода из игры (F10): if e_KeyPressed(IK_F10) and gGameOn and (not gConsoleShow) and @@ -2293,10 +2309,11 @@ begin begin KeyPress(IK_F10); end; +{$ENDIF} - Time := sys_GetTicks() {div 1000}; + Time := GetTickCount64() {div 1000}; -// Îáðàáîòêà îòëîæåííûõ ñîáûòèé: +// Обработка отложенных событий: if gDelayedEvents <> nil then for a := 0 to High(gDelayedEvents) do if gDelayedEvents[a].Pending and @@ -2325,7 +2342,7 @@ begin gDelayedEvents[a].Pending := False; end; -// Êàæäóþ ñåêóíäó îáíîâëÿåì ñ÷åò÷èê îáíîâëåíèé: +// Каждую секунду обновляем счетчик обновлений: UPSCounter := UPSCounter + 1; if Time - UPSTime >= 1000 then begin @@ -2399,61 +2416,11 @@ begin end; procedure g_Game_LoadData(); -var - wl, hl: Integer; - wr, hr: Integer; - wb, hb: Integer; - wm, hm: Integer; begin if DataLoaded then Exit; e_WriteLog('Loading game data...', TMsgType.Notify); - g_Texture_CreateWADEx('NOTEXTURE', GameWAD+':TEXTURES\NOTEXTURE'); - g_Texture_CreateWADEx('TEXTURE_PLAYER_HUD', GameWAD+':TEXTURES\HUD'); - g_Texture_CreateWADEx('TEXTURE_PLAYER_HUDAIR', GameWAD+':TEXTURES\AIRBAR'); - g_Texture_CreateWADEx('TEXTURE_PLAYER_HUDJET', GameWAD+':TEXTURES\JETBAR'); - g_Texture_CreateWADEx('TEXTURE_PLAYER_HUDBG', GameWAD+':TEXTURES\HUDBG'); - g_Texture_CreateWADEx('TEXTURE_PLAYER_ARMORHUD', GameWAD+':TEXTURES\ARMORHUD'); - g_Texture_CreateWADEx('TEXTURE_PLAYER_REDFLAG', GameWAD+':TEXTURES\FLAGHUD_R_BASE'); - g_Texture_CreateWADEx('TEXTURE_PLAYER_REDFLAG_S', GameWAD+':TEXTURES\FLAGHUD_R_STOLEN'); - g_Texture_CreateWADEx('TEXTURE_PLAYER_REDFLAG_D', GameWAD+':TEXTURES\FLAGHUD_R_DROP'); - g_Texture_CreateWADEx('TEXTURE_PLAYER_BLUEFLAG', GameWAD+':TEXTURES\FLAGHUD_B_BASE'); - g_Texture_CreateWADEx('TEXTURE_PLAYER_BLUEFLAG_S', GameWAD+':TEXTURES\FLAGHUD_B_STOLEN'); - g_Texture_CreateWADEx('TEXTURE_PLAYER_BLUEFLAG_D', GameWAD+':TEXTURES\FLAGHUD_B_DROP'); - g_Texture_CreateWADEx('TEXTURE_PLAYER_TALKBUBBLE', GameWAD+':TEXTURES\TALKBUBBLE'); - g_Texture_CreateWADEx('TEXTURE_PLAYER_INVULPENTA', GameWAD+':TEXTURES\PENTA'); - g_Texture_CreateWADEx('TEXTURE_PLAYER_INDICATOR', GameWAD+':TEXTURES\PLRIND'); - - hasPBarGfx := true; - if not g_Texture_CreateWADEx('UI_GFX_PBAR_LEFT', GameWAD+':TEXTURES\LLEFT') then hasPBarGfx := false; - if not g_Texture_CreateWADEx('UI_GFX_PBAR_MARKER', GameWAD+':TEXTURES\LMARKER') then hasPBarGfx := false; - if not g_Texture_CreateWADEx('UI_GFX_PBAR_MIDDLE', GameWAD+':TEXTURES\LMIDDLE') then hasPBarGfx := false; - if not g_Texture_CreateWADEx('UI_GFX_PBAR_RIGHT', GameWAD+':TEXTURES\LRIGHT') then hasPBarGfx := false; - - if hasPBarGfx then - begin - g_Texture_GetSize('UI_GFX_PBAR_LEFT', wl, hl); - g_Texture_GetSize('UI_GFX_PBAR_RIGHT', wr, hr); - g_Texture_GetSize('UI_GFX_PBAR_MIDDLE', wb, hb); - g_Texture_GetSize('UI_GFX_PBAR_MARKER', wm, hm); - if (wl > 0) and (hl > 0) and (wr > 0) and (hr = hl) and (wb > 0) and (hb = hl) and (wm > 0) and (hm > 0) and (hm <= hl) then - begin - // yay! - end - else - begin - hasPBarGfx := false; - end; - end; - - g_Frames_CreateWAD(nil, 'FRAMES_TELEPORT', GameWAD+':TEXTURES\TELEPORT', 64, 64, 10, False); - g_Frames_CreateWAD(nil, 'FRAMES_PUNCH', GameWAD+':WEAPONS\PUNCH', 64, 64, 4, False); - g_Frames_CreateWAD(nil, 'FRAMES_PUNCH_UP', GameWAD+':WEAPONS\PUNCH_UP', 64, 64, 4, False); - g_Frames_CreateWAD(nil, 'FRAMES_PUNCH_DN', GameWAD+':WEAPONS\PUNCH_DN', 64, 64, 4, False); - g_Frames_CreateWAD(nil, 'FRAMES_PUNCH_BERSERK', GameWAD+':WEAPONS\PUNCHB', 64, 64, 4, False); - g_Frames_CreateWAD(nil, 'FRAMES_PUNCH_BERSERK_UP', GameWAD+':WEAPONS\PUNCHB_UP', 64, 64, 4, False); - g_Frames_CreateWAD(nil, 'FRAMES_PUNCH_BERSERK_DN', GameWAD+':WEAPONS\PUNCHB_DN', 64, 64, 4, False); g_Sound_CreateWADEx('SOUND_GAME_TELEPORT', GameWAD+':SOUNDS\TELEPORT'); g_Sound_CreateWADEx('SOUND_GAME_NOTELEPORT', GameWAD+':SOUNDS\NOTELEPORT'); g_Sound_CreateWADEx('SOUND_GAME_SECRET', GameWAD+':SOUNDS\SECRET'); @@ -2546,6 +2513,29 @@ begin DataLoaded := True; end; +procedure g_Game_Quit(); +begin + g_Game_StopAllSounds(True); + gMusic.Free(); + g_Game_FreeData(); + g_PlayerModel_FreeData(); +{$IFNDEF HEADLESS} + //g_Menu_Free(); //k8: this segfaults after resolution change; who cares? +{$ENDIF} + + if NetInitDone then g_Net_Free; + +// remove map after test + if gMapToDelete <> '' then + g_Game_DeleteTestMap(); + + gExit := EXIT_QUIT; + + {$IFNDEF HEADLESS} + sys_RequestQuit; + {$ENDIF} +end; + procedure g_Game_FreeData(); begin if not DataLoaded then Exit; @@ -2556,25 +2546,6 @@ begin e_WriteLog('Releasing game data...', TMsgType.Notify); - g_Texture_Delete('NOTEXTURE'); - g_Texture_Delete('TEXTURE_PLAYER_HUD'); - g_Texture_Delete('TEXTURE_PLAYER_HUDBG'); - g_Texture_Delete('TEXTURE_PLAYER_ARMORHUD'); - g_Texture_Delete('TEXTURE_PLAYER_REDFLAG'); - g_Texture_Delete('TEXTURE_PLAYER_REDFLAG_S'); - g_Texture_Delete('TEXTURE_PLAYER_REDFLAG_D'); - g_Texture_Delete('TEXTURE_PLAYER_BLUEFLAG'); - g_Texture_Delete('TEXTURE_PLAYER_BLUEFLAG_S'); - g_Texture_Delete('TEXTURE_PLAYER_BLUEFLAG_D'); - g_Texture_Delete('TEXTURE_PLAYER_TALKBUBBLE'); - g_Texture_Delete('TEXTURE_PLAYER_INVULPENTA'); - g_Frames_DeleteByName('FRAMES_TELEPORT'); - g_Frames_DeleteByName('FRAMES_PUNCH'); - g_Frames_DeleteByName('FRAMES_PUNCH_UP'); - g_Frames_DeleteByName('FRAMES_PUNCH_DN'); - g_Frames_DeleteByName('FRAMES_PUNCH_BERSERK'); - g_Frames_DeleteByName('FRAMES_PUNCH_BERSERK_UP'); - g_Frames_DeleteByName('FRAMES_PUNCH_BERSERK_DN'); g_Sound_Delete('SOUND_GAME_TELEPORT'); g_Sound_Delete('SOUND_GAME_NOTELEPORT'); g_Sound_Delete('SOUND_GAME_SECRET'); @@ -2603,1593 +2574,40 @@ begin killsnd[2].Free(); killsnd[3].Free(); - g_Sound_Delete('SOUND_ANNOUNCER_KILL2X'); - g_Sound_Delete('SOUND_ANNOUNCER_KILL3X'); - g_Sound_Delete('SOUND_ANNOUNCER_KILL4X'); - g_Sound_Delete('SOUND_ANNOUNCER_KILLMX'); - - hahasnd[0].Free(); - hahasnd[1].Free(); - hahasnd[2].Free(); - - g_Sound_Delete('SOUND_ANNOUNCER_MUHAHA1'); - g_Sound_Delete('SOUND_ANNOUNCER_MUHAHA2'); - g_Sound_Delete('SOUND_ANNOUNCER_MUHAHA3'); - - sound_get_flag[0].Free(); - sound_get_flag[1].Free(); - sound_lost_flag[0].Free(); - sound_lost_flag[1].Free(); - sound_ret_flag[0].Free(); - sound_ret_flag[1].Free(); - sound_cap_flag[0].Free(); - sound_cap_flag[1].Free(); - - g_Sound_Delete('SOUND_CTF_GET1'); - g_Sound_Delete('SOUND_CTF_GET2'); - g_Sound_Delete('SOUND_CTF_LOST1'); - g_Sound_Delete('SOUND_CTF_LOST2'); - g_Sound_Delete('SOUND_CTF_RETURN1'); - g_Sound_Delete('SOUND_CTF_RETURN2'); - g_Sound_Delete('SOUND_CTF_CAPTURE1'); - g_Sound_Delete('SOUND_CTF_CAPTURE2'); - - g_Game_FreeChatSounds(); - - DataLoaded := False; -end; - -procedure DrawCustomStat(); -var - pc, x, y, w, _y, - w1, w2, w3, - t, p, m: Integer; - ww1, hh1: Word; - ww2, hh2, r, g, b, rr, gg, bb: Byte; - s1, s2, topstr: String; -begin - e_TextureFontGetSize(gStdFont, ww2, hh2); - - sys_HandleInput; - - if g_Console_Action(ACTION_SCORES) then - begin - if not gStatsPressed then - begin - gStatsOff := not gStatsOff; - gStatsPressed := True; - end; - end - else - gStatsPressed := False; - - if gStatsOff then - begin - s1 := _lc[I_MENU_INTER_NOTICE_TAB]; - w := (Length(s1) * ww2) div 2; - x := gScreenWidth div 2 - w; - y := 8; - e_TextureFontPrint(x, y, s1, gStdFont); - Exit; - end; - - if (gGameSettings.GameMode = GM_COOP) then - begin - if gMissionFailed then - topstr := _lc[I_MENU_INTER_MISSION_FAIL] - else - topstr := _lc[I_MENU_INTER_LEVEL_COMPLETE]; - end - else - topstr := _lc[I_MENU_INTER_ROUND_OVER]; - - e_CharFont_GetSize(gMenuFont, topstr, ww1, hh1); - e_CharFont_Print(gMenuFont, (gScreenWidth div 2)-(ww1 div 2), 16, topstr); - - if g_Game_IsNet then - begin - topstr := Format(_lc[I_MENU_INTER_NOTICE_TIME], [gServInterTime]); - if not gChatShow then - e_TextureFontPrintEx((gScreenWidth div 2)-(Length(topstr)*ww2 div 2), - gScreenHeight-(hh2+4)*2, topstr, gStdFont, 255, 255, 255, 1); - end; - - if g_Game_IsClient then - topstr := _lc[I_MENU_INTER_NOTICE_MAP] - else - topstr := _lc[I_MENU_INTER_NOTICE_SPACE]; - if not gChatShow then - e_TextureFontPrintEx((gScreenWidth div 2)-(Length(topstr)*ww2 div 2), - gScreenHeight-(hh2+4), topstr, gStdFont, 255, 255, 255, 1); - - x := 32; - y := 16+hh1+16; - - w := gScreenWidth-x*2; - - w2 := (w-16) div 6; - w3 := w2; - w1 := w-16-w2-w3; - - e_DrawFillQuad(x, y, gScreenWidth-x-1, gScreenHeight-y-1, 64, 64, 64, 32); - e_DrawQuad(x, y, gScreenWidth-x-1, gScreenHeight-y-1, 255, 127, 0); - - m := Max(Length(_lc[I_MENU_MAP])+1, Length(_lc[I_GAME_GAME_TIME])+1)*ww2; - - case CustomStat.GameMode of - GM_DM: - begin - if gGameSettings.MaxLives = 0 then - s1 := _lc[I_GAME_DM] - else - s1 := _lc[I_GAME_LMS]; - end; - GM_TDM: - begin - if gGameSettings.MaxLives = 0 then - s1 := _lc[I_GAME_TDM] - else - s1 := _lc[I_GAME_TLMS]; - end; - GM_CTF: s1 := _lc[I_GAME_CTF]; - GM_COOP: - begin - if gGameSettings.MaxLives = 0 then - s1 := _lc[I_GAME_COOP] - else - s1 := _lc[I_GAME_SURV]; - end; - else s1 := ''; - end; - - _y := y+16; - e_TextureFontPrintEx(x+(w div 2)-(Length(s1)*ww2 div 2), _y, s1, gStdFont, 255, 255, 255, 1); - _y := _y+8; - - _y := _y+16; - e_TextureFontPrintEx(x+8, _y, _lc[I_MENU_MAP], gStdFont, 255, 127, 0, 1); - e_TextureFontPrint(x+8+m, _y, Format('%s - %s', [CustomStat.Map, CustomStat.MapName]), gStdFont); - - _y := _y+16; - e_TextureFontPrintEx(x+8, _y, _lc[I_GAME_GAME_TIME], gStdFont, 255, 127, 0, 1); - e_TextureFontPrint(x+8+m, _y, Format('%d:%.2d:%.2d', [CustomStat.GameTime div 1000 div 3600, - (CustomStat.GameTime div 1000 div 60) mod 60, - CustomStat.GameTime div 1000 mod 60]), gStdFont); - - pc := Length(CustomStat.PlayerStat); - if pc = 0 then Exit; - - if CustomStat.GameMode = GM_COOP then - begin - m := Max(Length(_lc[I_GAME_MONSTERS])+1, Length(_lc[I_GAME_SECRETS])+1)*ww2; - _y := _y+32; - s2 := _lc[I_GAME_MONSTERS]; - e_TextureFontPrintEx(x+8, _y, s2, gStdFont, 255, 127, 0, 1); - e_TextureFontPrintEx(x+8+m, _y, IntToStr(gCoopMonstersKilled) + '/' + IntToStr(gTotalMonsters), gStdFont, 255, 255, 255, 1); - _y := _y+16; - s2 := _lc[I_GAME_SECRETS]; - e_TextureFontPrintEx(x+8, _y, s2, gStdFont, 255, 127, 0, 1); - e_TextureFontPrintEx(x+8+m, _y, IntToStr(gCoopSecretsFound) + '/' + IntToStr(gSecretsCount), gStdFont, 255, 255, 255, 1); - if gLastMap then - begin - m := Max(Length(_lc[I_GAME_MONSTERS_TOTAL])+1, Length(_lc[I_GAME_SECRETS_TOTAL])+1)*ww2; - _y := _y-16; - s2 := _lc[I_GAME_MONSTERS_TOTAL]; - e_TextureFontPrintEx(x+250, _y, s2, gStdFont, 255, 127, 0, 1); - e_TextureFontPrintEx(x+250+m, _y, IntToStr(gCoopTotalMonstersKilled) + '/' + IntToStr(gCoopTotalMonsters), gStdFont, 255, 255, 255, 1); - _y := _y+16; - s2 := _lc[I_GAME_SECRETS_TOTAL]; - e_TextureFontPrintEx(x+250, _y, s2, gStdFont, 255, 127, 0, 1); - e_TextureFontPrintEx(x+250+m, _y, IntToStr(gCoopTotalSecretsFound) + '/' + IntToStr(gCoopTotalSecrets), gStdFont, 255, 255, 255, 1); - end; - end; - - if CustomStat.GameMode in [GM_TDM, GM_CTF] then - begin - _y := _y+16+16; - - with CustomStat do - if TeamStat[TEAM_RED].Goals > TeamStat[TEAM_BLUE].Goals then s1 := _lc[I_GAME_WIN_RED] - else if TeamStat[TEAM_BLUE].Goals > TeamStat[TEAM_RED].Goals then s1 := _lc[I_GAME_WIN_BLUE] - else s1 := _lc[I_GAME_WIN_DRAW]; - - e_TextureFontPrintEx(x+8+(w div 2)-(Length(s1)*ww2 div 2), _y, s1, gStdFont, 255, 255, 255, 1); - _y := _y+40; - - for t := TEAM_RED to TEAM_BLUE do - begin - if t = TEAM_RED then - begin - e_TextureFontPrintEx(x+8, _y, _lc[I_GAME_TEAM_RED], - gStdFont, 255, 0, 0, 1); - e_TextureFontPrintEx(x+w1+8, _y, IntToStr(CustomStat.TeamStat[TEAM_RED].Goals), - gStdFont, 255, 0, 0, 1); - r := 255; - g := 0; - b := 0; - end - else - begin - e_TextureFontPrintEx(x+8, _y, _lc[I_GAME_TEAM_BLUE], - gStdFont, 0, 0, 255, 1); - e_TextureFontPrintEx(x+w1+8, _y, IntToStr(CustomStat.TeamStat[TEAM_BLUE].Goals), - gStdFont, 0, 0, 255, 1); - r := 0; - g := 0; - b := 255; - end; - - e_DrawLine(1, x+8, _y+20, x-8+w, _y+20, r, g, b); - _y := _y+24; - - for p := 0 to High(CustomStat.PlayerStat) do - if CustomStat.PlayerStat[p].Team = t then - with CustomStat.PlayerStat[p] do - begin - if Spectator then - begin - rr := r div 2; - gg := g div 2; - bb := b div 2; - end - else - begin - rr := r; - gg := g; - bb := b; - end; - if (gPlayers[Num] <> nil) and (gPlayers[Num].FReady) then - e_TextureFontPrintEx(x+16, _y, Name + ' *', gStdFont, rr, gg, bb, 1) - else - e_TextureFontPrintEx(x+16, _y, Name, gStdFont, rr, gg, bb, 1); - e_TextureFontPrintEx(x+w1+16, _y, IntToStr(Frags), gStdFont, rr, gg, bb, 1); - e_TextureFontPrintEx(x+w1+w2+16, _y, IntToStr(Deaths), gStdFont, rr, gg, bb, 1); - _y := _y+24; - end; - - _y := _y+16+16; - end; - end - else if CustomStat.GameMode in [GM_DM, GM_COOP] then - begin - _y := _y+40; - e_TextureFontPrintEx(x+8, _y, _lc[I_GAME_PLAYER_NAME], gStdFont, 255, 127, 0, 1); - e_TextureFontPrintEx(x+8+w1, _y, _lc[I_GAME_FRAGS], gStdFont, 255, 127, 0, 1); - e_TextureFontPrintEx(x+8+w1+w2, _y, _lc[I_GAME_DEATHS], gStdFont, 255, 127, 0, 1); - - _y := _y+24; - for p := 0 to High(CustomStat.PlayerStat) do - with CustomStat.PlayerStat[p] do - begin - e_DrawFillQuad(x+8, _y+4, x+24-1, _y+16+4-1, Color.R, Color.G, Color.B, 0); - - if Spectator then - r := 127 - else - r := 255; - - if (gPlayers[Num] <> nil) and (gPlayers[Num].FReady) then - e_TextureFontPrintEx(x+8+16+8, _y+4, Name + ' *', gStdFont, r, r, r, 1, True) - else - e_TextureFontPrintEx(x+8+16+8, _y+4, Name, gStdFont, r, r, r, 1, True); - e_TextureFontPrintEx(x+w1+8+16+8, _y+4, IntToStr(Frags), gStdFont, r, r, r, 1, True); - e_TextureFontPrintEx(x+w1+w2+8+16+8, _y+4, IntToStr(Deaths), gStdFont, r, r, r, 1, True); - _y := _y+24; - end; - end; - - // HACK: take stats screenshot immediately after the first frame of the stats showing - if gScreenshotStats and (not StatShotDone) and (Length(CustomStat.PlayerStat) > 1) then - begin - g_TakeScreenShot('stats/' + StatFilename); - StatShotDone := True; - end; -end; - -procedure DrawSingleStat(); -var - tm, key_x, val_x, y: Integer; - w1, w2, h: Word; - s1, s2: String; - - procedure player_stat(n: Integer); - var - kpm: Real; - - begin - // "Kills: # / #": - s1 := Format(' %d ', [SingleStat.PlayerStat[n].Kills]); - s2 := Format(' %d', [gTotalMonsters]); - - e_CharFont_Print(gMenuFont, key_x, y, _lc[I_MENU_INTER_KILLS]); - e_CharFont_PrintEx(gMenuFont, val_x, y, s1, _RGB(255, 0, 0)); - e_CharFont_GetSize(gMenuFont, s1, w1, h); - e_CharFont_Print(gMenuFont, val_x+w1, y, '/'); - s1 := s1 + '/'; - e_CharFont_GetSize(gMenuFont, s1, w1, h); - e_CharFont_PrintEx(gMenuFont, val_x+w1, y, s2, _RGB(255, 0, 0)); - - // "Kills-per-minute: ##.#": - s1 := _lc[I_MENU_INTER_KPM]; - if tm > 0 then - kpm := (SingleStat.PlayerStat[n].Kills / tm) * 60 - else - kpm := SingleStat.PlayerStat[n].Kills; - s2 := Format(' %.1f', [kpm]); - - e_CharFont_Print(gMenuFont, key_x, y+32, s1); - e_CharFont_PrintEx(gMenuFont, val_x, y+32, s2, _RGB(255, 0, 0)); - - // "Secrets found: # / #": - s1 := Format(' %d ', [SingleStat.PlayerStat[n].Secrets]); - s2 := Format(' %d', [SingleStat.TotalSecrets]); - - e_CharFont_Print(gMenuFont, key_x, y+64, _lc[I_MENU_INTER_SECRETS]); - e_CharFont_PrintEx(gMenuFont, val_x, y+64, s1, _RGB(255, 0, 0)); - e_CharFont_GetSize(gMenuFont, s1, w1, h); - e_CharFont_Print(gMenuFont, val_x+w1, y+64, '/'); - s1 := s1 + '/'; - e_CharFont_GetSize(gMenuFont, s1, w1, h); - e_CharFont_PrintEx(gMenuFont, val_x+w1, y+64, s2, _RGB(255, 0, 0)); - end; - -begin -// "Level Complete": - e_CharFont_GetSize(gMenuFont, _lc[I_MENU_INTER_LEVEL_COMPLETE], w1, h); - e_CharFont_Print(gMenuFont, (gScreenWidth-w1) div 2, 32, _lc[I_MENU_INTER_LEVEL_COMPLETE]); - -// Îïðåäåëÿåì êîîðäèíàòû âûðàâíèâàíèÿ ïî ñàìîé äëèííîé ñòðîêå: - s1 := _lc[I_MENU_INTER_KPM]; - e_CharFont_GetSize(gMenuFont, s1, w1, h); - Inc(w1, 16); - s1 := ' 9999.9'; - e_CharFont_GetSize(gMenuFont, s1, w2, h); - - key_x := (gScreenWidth-w1-w2) div 2; - val_x := key_x + w1; - -// "Time: #:##:##": - tm := SingleStat.GameTime div 1000; - s1 := _lc[I_MENU_INTER_TIME]; - s2 := Format(' %d:%.2d:%.2d', [tm div (60*60), (tm mod (60*60)) div 60, tm mod 60]); - - e_CharFont_Print(gMenuFont, key_x, 80, s1); - e_CharFont_PrintEx(gMenuFont, val_x, 80, s2, _RGB(255, 0, 0)); - - if SingleStat.TwoPlayers then - begin - // "Player 1": - s1 := _lc[I_MENU_PLAYER_1]; - e_CharFont_GetSize(gMenuFont, s1, w1, h); - e_CharFont_Print(gMenuFont, (gScreenWidth-w1) div 2, 128, s1); - - // Ñòàòèñòèêà ïåðâîãî èãðîêà: - y := 176; - player_stat(0); - - // "Player 2": - s1 := _lc[I_MENU_PLAYER_2]; - e_CharFont_GetSize(gMenuFont, s1, w1, h); - e_CharFont_Print(gMenuFont, (gScreenWidth-w1) div 2, 288, s1); - - // Ñòàòèñòèêà âòîðîãî èãðîêà: - y := 336; - player_stat(1); - end - else - begin - // Ñòàòèñòèêà ïåðâîãî èãðîêà: - y := 128; - player_stat(0); - end; -end; - -procedure DrawLoadingStat(); - procedure drawRect (x, y, w, h: Integer); - begin - if (w < 1) or (h < 1) then exit; - glBegin(GL_QUADS); - glVertex2f(x+0.375, y+0.375); - glVertex2f(x+w+0.375, y+0.375); - glVertex2f(x+w+0.375, y+h+0.375); - glVertex2f(x+0.375, y+h+0.375); - glEnd(); - end; - - function drawPBar (cur, total: Integer; washere: Boolean): Boolean; - var - rectW, rectH: Integer; - x0, y0: Integer; - wdt: Integer; - wl, hl: Integer; - wr, hr: Integer; - wb, hb: Integer; - wm, hm: Integer; - idl, idr, idb, idm: LongWord; - f, my: Integer; - begin - result := false; - if (total < 1) then exit; - if (cur < 1) then exit; // don't blink - if (not washere) and (cur >= total) then exit; // don't blink - //if (cur < 0) then cur := 0; - //if (cur > total) then cur := total; - result := true; - - if (hasPBarGfx) then - begin - g_Texture_Get('UI_GFX_PBAR_LEFT', idl); - g_Texture_GetSize('UI_GFX_PBAR_LEFT', wl, hl); - g_Texture_Get('UI_GFX_PBAR_RIGHT', idr); - g_Texture_GetSize('UI_GFX_PBAR_RIGHT', wr, hr); - g_Texture_Get('UI_GFX_PBAR_MIDDLE', idb); - g_Texture_GetSize('UI_GFX_PBAR_MIDDLE', wb, hb); - g_Texture_Get('UI_GFX_PBAR_MARKER', idm); - g_Texture_GetSize('UI_GFX_PBAR_MARKER', wm, hm); - - //rectW := gScreenWidth-360; - rectW := trunc(624.0*gScreenWidth/1024.0); - rectH := hl; - - x0 := (gScreenWidth-rectW) div 2; - y0 := gScreenHeight-rectH-64; - if (y0 < 2) then y0 := 2; - - glEnable(GL_SCISSOR_TEST); - - // left and right - glScissor(x0, gScreenHeight-y0-rectH, rectW, rectH); - e_DrawSize(idl, x0, y0, 0, true, false, wl, hl); - e_DrawSize(idr, x0+rectW-wr, y0, 0, true, false, wr, hr); - - // body - glScissor(x0+wl, gScreenHeight-y0-rectH, rectW-wl-wr, rectH); - f := x0+wl; - while (f < x0+rectW) do - begin - e_DrawSize(idb, f, y0, 0, true, false, wb, hb); - f += wb; - end; - - // filled part - wdt := (rectW-wl-wr)*cur div total; - if (wdt > rectW-wl-wr) then wdt := rectW-wr-wr; - if (wdt > 0) then - begin - my := y0; // don't be so smart, ketmar: +(rectH-wm) div 2; - glScissor(x0+wl, gScreenHeight-my-rectH, wdt, hm); - f := x0+wl; - while (wdt > 0) do - begin - e_DrawSize(idm, f, y0, 0, true, false, wm, hm); - f += wm; - wdt -= wm; - end; - end; - - glScissor(0, 0, gScreenWidth, gScreenHeight); - end - else - begin - rectW := gScreenWidth-64; - rectH := 16; - - x0 := (gScreenWidth-rectW) div 2; - y0 := gScreenHeight-rectH-64; - if (y0 < 2) then y0 := 2; - - glDisable(GL_BLEND); - glDisable(GL_TEXTURE_2D); - - //glClearColor(0, 0, 0, 0); - //glClear(GL_COLOR_BUFFER_BIT); - - glColor4ub(127, 127, 127, 255); - drawRect(x0-2, y0-2, rectW+4, rectH+4); - - glColor4ub(0, 0, 0, 255); - drawRect(x0-1, y0-1, rectW+2, rectH+2); - - glColor4ub(127, 127, 127, 255); - wdt := rectW*cur div total; - if (wdt > rectW) then wdt := rectW; - drawRect(x0, y0, wdt, rectH); - end; - end; - -var - ww, hh: Word; - xx, yy, i: Integer; - s: String; -begin - if (Length(LoadingStat.Msgs) = 0) then exit; - - e_CharFont_GetSize(gMenuFont, _lc[I_MENU_LOADING], ww, hh); - yy := (gScreenHeight div 3); - e_CharFont_Print(gMenuFont, (gScreenWidth div 2)-(ww div 2), yy-2*hh, _lc[I_MENU_LOADING]); - xx := (gScreenWidth div 3); - - with LoadingStat do - begin - for i := 0 to NextMsg-1 do - begin - if (i = (NextMsg-1)) and (MaxValue > 0) then - s := Format('%s: %d/%d', [Msgs[i], CurValue, MaxValue]) - else - s := Msgs[i]; - - e_CharFont_PrintEx(gMenuSmallFont, xx, yy, s, _RGB(255, 0, 0)); - yy := yy + LOADING_INTERLINE; - PBarWasHere := drawPBar(CurValue, MaxValue, PBarWasHere); - end; - end; -end; - -procedure DrawMenuBackground(tex: AnsiString); -var - w, h: Word; - ID: DWord; - -begin - if g_Texture_Get(tex, ID) then - begin - e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0); - e_GetTextureSize(ID, @w, @h); - if w = h then - w := round(w * 1.333 * (gScreenHeight / h)) - else - w := trunc(w * (gScreenHeight / h)); - e_DrawSize(ID, (gScreenWidth - w) div 2, 0, 0, False, False, w, gScreenHeight); - end - else e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0); -end; - -procedure DrawMinimap(p: TPlayer; RenderRect: e_graphics.TRect); -var - a, aX, aY, aX2, aY2, Scale, ScaleSz: Integer; - - function monDraw (mon: TMonster): Boolean; - begin - result := false; // don't stop - with mon do - begin - if alive then - begin - // Ëåâûé âåðõíèé óãîë - aX := Obj.X div ScaleSz + 1; - aY := Obj.Y div ScaleSz + 1; - // Ðàçìåðû - aX2 := max(Obj.Rect.Width div ScaleSz, 1); - aY2 := max(Obj.Rect.Height div ScaleSz, 1); - // Ïðàâûé íèæíèé óãîë - aX2 := aX + aX2 - 1; - aY2 := aY + aY2 - 1; - e_DrawFillQuad(aX, aY, aX2, aY2, 255, 255, 0, 0); - end; - end; - end; - -begin - if (gMapInfo.Width > RenderRect.Right - RenderRect.Left) or - (gMapInfo.Height > RenderRect.Bottom - RenderRect.Top) then - begin - Scale := 1; - // Ñêîëüêî ïèêñåëîâ êàðòû â 1 ïèêñåëå ìèíè-êàðòû: - ScaleSz := 16 div Scale; - // Ðàçìåðû ìèíè-êàðòû: - aX := max(gMapInfo.Width div ScaleSz, 1); - aY := max(gMapInfo.Height div ScaleSz, 1); - // Ðàìêà êàðòû: - e_DrawFillQuad(0, 0, aX-1, aY-1, 0, 0, 0, 0); - - if gWalls <> nil then - begin - // Ðèñóåì ñòåíû: - for a := 0 to High(gWalls) do - with gWalls[a] do - if PanelType <> 0 then - begin - // Ëåâûé âåðõíèé óãîë: - aX := X div ScaleSz; - aY := Y div ScaleSz; - // Ðàçìåðû: - aX2 := max(Width div ScaleSz, 1); - aY2 := max(Height div ScaleSz, 1); - // Ïðàâûé íèæíèé óãîë: - aX2 := aX + aX2 - 1; - aY2 := aY + aY2 - 1; - - case PanelType of - PANEL_WALL: e_DrawFillQuad(aX, aY, aX2, aY2, 208, 208, 208, 0); - PANEL_OPENDOOR, PANEL_CLOSEDOOR: - if Enabled then e_DrawFillQuad(aX, aY, aX2, aY2, 160, 160, 160, 0); - end; - end; - end; - if gSteps <> nil then - begin - // Ðèñóåì ñòóïåíè: - for a := 0 to High(gSteps) do - with gSteps[a] do - if PanelType <> 0 then - begin - // Ëåâûé âåðõíèé óãîë: - aX := X div ScaleSz; - aY := Y div ScaleSz; - // Ðàçìåðû: - aX2 := max(Width div ScaleSz, 1); - aY2 := max(Height div ScaleSz, 1); - // Ïðàâûé íèæíèé óãîë: - aX2 := aX + aX2 - 1; - aY2 := aY + aY2 - 1; - - e_DrawFillQuad(aX, aY, aX2, aY2, 128, 128, 128, 0); - end; - end; - if gLifts <> nil then - begin - // Ðèñóåì ëèôòû: - for a := 0 to High(gLifts) do - with gLifts[a] do - if PanelType <> 0 then - begin - // Ëåâûé âåðõíèé óãîë: - aX := X div ScaleSz; - aY := Y div ScaleSz; - // Ðàçìåðû: - aX2 := max(Width div ScaleSz, 1); - aY2 := max(Height div ScaleSz, 1); - // Ïðàâûé íèæíèé óãîë: - aX2 := aX + aX2 - 1; - aY2 := aY + aY2 - 1; - - case LiftType of - LIFTTYPE_UP: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 72, 36, 0); - LIFTTYPE_DOWN: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 124, 96, 0); - LIFTTYPE_LEFT: e_DrawFillQuad(aX, aY, aX2, aY2, 200, 80, 4, 0); - LIFTTYPE_RIGHT: e_DrawFillQuad(aX, aY, aX2, aY2, 252, 140, 56, 0); - end; - end; - end; - if gWater <> nil then - begin - // Ðèñóåì âîäó: - for a := 0 to High(gWater) do - with gWater[a] do - if PanelType <> 0 then - begin - // Ëåâûé âåðõíèé óãîë: - aX := X div ScaleSz; - aY := Y div ScaleSz; - // Ðàçìåðû: - aX2 := max(Width div ScaleSz, 1); - aY2 := max(Height div ScaleSz, 1); - // Ïðàâûé íèæíèé óãîë: - aX2 := aX + aX2 - 1; - aY2 := aY + aY2 - 1; - - e_DrawFillQuad(aX, aY, aX2, aY2, 0, 0, 192, 0); - end; - end; - if gAcid1 <> nil then - begin - // Ðèñóåì êèñëîòó 1: - for a := 0 to High(gAcid1) do - with gAcid1[a] do - if PanelType <> 0 then - begin - // Ëåâûé âåðõíèé óãîë: - aX := X div ScaleSz; - aY := Y div ScaleSz; - // Ðàçìåðû: - aX2 := max(Width div ScaleSz, 1); - aY2 := max(Height div ScaleSz, 1); - // Ïðàâûé íèæíèé óãîë: - aX2 := aX + aX2 - 1; - aY2 := aY + aY2 - 1; - - e_DrawFillQuad(aX, aY, aX2, aY2, 0, 176, 0, 0); - end; - end; - if gAcid2 <> nil then - begin - // Ðèñóåì êèñëîòó 2: - for a := 0 to High(gAcid2) do - with gAcid2[a] do - if PanelType <> 0 then - begin - // Ëåâûé âåðõíèé óãîë: - aX := X div ScaleSz; - aY := Y div ScaleSz; - // Ðàçìåðû: - aX2 := max(Width div ScaleSz, 1); - aY2 := max(Height div ScaleSz, 1); - // Ïðàâûé íèæíèé óãîë: - aX2 := aX + aX2 - 1; - aY2 := aY + aY2 - 1; - - e_DrawFillQuad(aX, aY, aX2, aY2, 176, 0, 0, 0); - end; - end; - if gPlayers <> nil then - begin - // Ðèñóåì èãðîêîâ: - for a := 0 to High(gPlayers) do - if gPlayers[a] <> nil then with gPlayers[a] do - if alive then begin - // Ëåâûé âåðõíèé óãîë: - aX := Obj.X div ScaleSz + 1; - aY := Obj.Y div ScaleSz + 1; - // Ðàçìåðû: - aX2 := max(Obj.Rect.Width div ScaleSz, 1); - aY2 := max(Obj.Rect.Height div ScaleSz, 1); - // Ïðàâûé íèæíèé óãîë: - aX2 := aX + aX2 - 1; - aY2 := aY + aY2 - 1; - - if gPlayers[a] = p then - e_DrawFillQuad(aX, aY, aX2, aY2, 0, 255, 0, 0) - else - case Team of - TEAM_RED: e_DrawFillQuad(aX, aY, aX2, aY2, 255, 0, 0, 0); - TEAM_BLUE: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 0, 255, 0); - else e_DrawFillQuad(aX, aY, aX2, aY2, 255, 128, 0, 0); - end; - end; - end; - // Ðèñóåì ìîíñòðîâ - g_Mons_ForEach(monDraw); - end; -end; - - -procedure renderAmbientQuad (hasAmbient: Boolean; constref ambColor: TDFColor); -begin - if not hasAmbient then exit; - e_AmbientQuad(sX, sY, sWidth, sHeight, ambColor.r, ambColor.g, ambColor.b, ambColor.a); -end; - - -// setup sX, sY, sWidth, sHeight, and transformation matrix before calling this! -//FIXME: broken for splitscreen mode -procedure renderDynLightsInternal (); -var - //hasAmbient: Boolean; - //ambColor: TDFColor; - lln: Integer; - lx, ly, lrad: Integer; - scxywh: array[0..3] of GLint; - wassc: Boolean; -begin - if e_NoGraphics then exit; - - //TODO: lights should be in separate grid, i think - // but on the other side: grid may be slower for dynlights, as their lifetime is short - if (not gwin_k8_enable_light_experiments) or (not gwin_has_stencil) or (g_dynLightCount < 1) then exit; - - // rendering mode - //ambColor := gCurrentMap['light_ambient'].rgba; - //hasAmbient := (not ambColor.isOpaque) or (not ambColor.isBlack); - - { // this will multiply incoming color to alpha from framebuffer - glEnable(GL_BLEND); - glBlendFunc(GL_DST_ALPHA, GL_ONE); - } - - (* - * light rendering: (INVALID!) - * glStencilFunc(GL_EQUAL, 0, $ff); - * for each light: - * glClear(GL_STENCIL_BUFFER_BIT); - * glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); - * draw shadow volume into stencil buffer - * glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // modify color buffer - * glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // don't modify stencil buffer - * turn off blending - * draw color-less quad with light alpha (WARNING! don't touch color!) - * glEnable(GL_BLEND); - * glBlendFunc(GL_DST_ALPHA, GL_ONE); - * draw all geometry up to and including walls (with alpha-testing, probably) -- this does lighting - *) - wassc := (glIsEnabled(GL_SCISSOR_TEST) <> 0); - if wassc then glGetIntegerv(GL_SCISSOR_BOX, @scxywh[0]) else glGetIntegerv(GL_VIEWPORT, @scxywh[0]); - - // setup OpenGL parameters - glStencilMask($FFFFFFFF); - glStencilFunc(GL_ALWAYS, 0, $FFFFFFFF); - glEnable(GL_STENCIL_TEST); - glEnable(GL_SCISSOR_TEST); - glClear(GL_STENCIL_BUFFER_BIT); - glStencilFunc(GL_EQUAL, 0, $ff); - - for lln := 0 to g_dynLightCount-1 do - begin - lx := g_dynLights[lln].x; - ly := g_dynLights[lln].y; - lrad := g_dynLights[lln].radius; - if (lrad < 3) then continue; - - if (lx-sX+lrad < 0) then continue; - if (ly-sY+lrad < 0) then continue; - if (lx-sX-lrad >= gPlayerScreenSize.X) then continue; - if (ly-sY-lrad >= gPlayerScreenSize.Y) then continue; - - // set scissor to optimize drawing - if (g_dbg_scale = 1.0) then - begin - glScissor((lx-sX)-lrad+2, gPlayerScreenSize.Y-(ly-sY)-lrad-1+2, lrad*2-4, lrad*2-4); - end - else - begin - glScissor(0, 0, gScreenWidth, gScreenHeight); - end; - // no need to clear stencil buffer, light blitting will do it for us... but only for normal scale - if (g_dbg_scale <> 1.0) then glClear(GL_STENCIL_BUFFER_BIT); - glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); - // draw extruded panels - glDisable(GL_TEXTURE_2D); - glDisable(GL_BLEND); - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // no need to modify color buffer - if (lrad > 4) then g_Map_DrawPanelShadowVolumes(lx, ly, lrad); - // render light texture - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // modify color buffer - glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); // draw light, and clear stencil buffer - // blend it - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_TEXTURE_2D); - // color and opacity - glColor4f(g_dynLights[lln].r, g_dynLights[lln].g, g_dynLights[lln].b, g_dynLights[lln].a); - glBindTexture(GL_TEXTURE_2D, g_Texture_Light()); - glBegin(GL_QUADS); - glTexCoord2f(0.0, 0.0); glVertex2i(lx-lrad, ly-lrad); // top-left - glTexCoord2f(1.0, 0.0); glVertex2i(lx+lrad, ly-lrad); // top-right - glTexCoord2f(1.0, 1.0); glVertex2i(lx+lrad, ly+lrad); // bottom-right - glTexCoord2f(0.0, 1.0); glVertex2i(lx-lrad, ly+lrad); // bottom-left - glEnd(); - end; - - // done - glDisable(GL_STENCIL_TEST); - glDisable(GL_BLEND); - glDisable(GL_SCISSOR_TEST); - //glScissor(0, 0, sWidth, sHeight); - - glScissor(scxywh[0], scxywh[1], scxywh[2], scxywh[3]); - if wassc then glEnable(GL_SCISSOR_TEST) else glDisable(GL_SCISSOR_TEST); -end; - - -function fixViewportForScale (): Boolean; -var - nx0, ny0, nw, nh: Integer; -begin - result := false; - if (g_dbg_scale <> 1.0) then - begin - result := true; - nx0 := round(sX-(gPlayerScreenSize.X-(sWidth*g_dbg_scale))/2/g_dbg_scale); - ny0 := round(sY-(gPlayerScreenSize.Y-(sHeight*g_dbg_scale))/2/g_dbg_scale); - nw := round(sWidth/g_dbg_scale); - nh := round(sHeight/g_dbg_scale); - sX := nx0; - sY := ny0; - sWidth := nw; - sHeight := nh; - end; -end; - - -// setup sX, sY, sWidth, sHeight, and transformation matrix before calling this! -// WARNING! this WILL CALL `glTranslatef()`, but won't restore matrices! -procedure renderMapInternal (backXOfs, backYOfs: Integer; setTransMatrix: Boolean); -type - TDrawCB = procedure (); - -var - hasAmbient: Boolean; - ambColor: TDFColor; - doAmbient: Boolean = false; - - procedure drawPanelType (profname: AnsiString; panType: DWord; doDraw: Boolean); - var - tagmask: Integer; - pan: TPanel; - begin - if (profileFrameDraw <> nil) then profileFrameDraw.sectionBegin(profname); - if gdbg_map_use_accel_render then - begin - tagmask := panelTypeToTag(panType); - while (gDrawPanelList.count > 0) do - begin - pan := TPanel(gDrawPanelList.front()); - if ((pan.tag and tagmask) = 0) then break; - if doDraw then pan.Draw(doAmbient, ambColor); - gDrawPanelList.popFront(); - end; - end - else - begin - if doDraw then g_Map_DrawPanels(panType, hasAmbient, ambColor); - end; - if (profileFrameDraw <> nil) then profileFrameDraw.sectionEnd(); - end; - - procedure drawOther (profname: AnsiString; cb: TDrawCB); - begin - if (profileFrameDraw <> nil) then profileFrameDraw.sectionBegin(profname); - if assigned(cb) then cb(); - if (profileFrameDraw <> nil) then profileFrameDraw.sectionEnd(); - end; - -begin - if (profileFrameDraw <> nil) then profileFrameDraw.sectionBegin('total'); - - // our accelerated renderer will collect all panels to gDrawPanelList - // we can use panel tag to render level parts (see GridTagXXX in g_map.pas) - if (profileFrameDraw <> nil) then profileFrameDraw.sectionBegin('collect'); - if gdbg_map_use_accel_render then - begin - g_Map_CollectDrawPanels(sX, sY, sWidth, sHeight); - end; - if (profileFrameDraw <> nil) then profileFrameDraw.sectionEnd(); - - if (profileFrameDraw <> nil) then profileFrameDraw.sectionBegin('skyback'); - g_Map_DrawBack(backXOfs, backYOfs); - if (profileFrameDraw <> nil) then profileFrameDraw.sectionEnd(); - - if setTransMatrix then - begin - //if (g_dbg_scale <> 1.0) then glTranslatef(0.0, -0.375/2, 0); - glScalef(g_dbg_scale, g_dbg_scale, 1.0); - glTranslatef(-sX, -sY, 0); - end; - - // rendering mode - ambColor := gCurrentMap['light_ambient'].rgba; - hasAmbient := (not ambColor.isOpaque) or (not ambColor.isBlack); - - { - if hasAmbient then - begin - //writeln('color: (', ambColor.r, ',', ambColor.g, ',', ambColor.b, ',', ambColor.a, ')'); - glColor4ub(ambColor.r, ambColor.g, ambColor.b, ambColor.a); - glClear(GL_COLOR_BUFFER_BIT); - end; - } - //writeln('color: (', ambColor.r, ',', ambColor.g, ',', ambColor.b, ',', ambColor.a, ')'); - - - drawPanelType('*back', PANEL_BACK, g_rlayer_back); - drawPanelType('*step', PANEL_STEP, g_rlayer_step); - drawOther('items', @g_Items_Draw); - drawOther('weapons', @g_Weapon_Draw); - drawOther('shells', @g_Player_DrawShells); - drawOther('drawall', @g_Player_DrawAll); - drawOther('corpses', @g_Player_DrawCorpses); - drawPanelType('*wall', PANEL_WALL, g_rlayer_wall); - drawOther('monsters', @g_Monsters_Draw); - drawOther('itemdrop', @g_Items_DrawDrop); - drawPanelType('*door', PANEL_CLOSEDOOR, g_rlayer_door); - drawOther('gfx', @g_GFX_Draw); - drawOther('flags', @g_Map_DrawFlags); - drawPanelType('*acid1', PANEL_ACID1, g_rlayer_acid1); - drawPanelType('*acid2', PANEL_ACID2, g_rlayer_acid2); - drawPanelType('*water', PANEL_WATER, g_rlayer_water); - drawOther('dynlights', @renderDynLightsInternal); - - if hasAmbient {and ((not g_playerLight) or (not gwin_has_stencil) or (g_dynLightCount < 1))} then - begin - renderAmbientQuad(hasAmbient, ambColor); - end; - - doAmbient := true; - drawPanelType('*fore', PANEL_FORE, g_rlayer_fore); - - - if g_debug_HealthBar then - begin - g_Monsters_DrawHealth(); - g_Player_DrawHealth(); - end; - - if (profileFrameDraw <> nil) then profileFrameDraw.mainEnd(); // map rendering -end; - - -procedure DrawMapView(x, y, w, h: Integer); - -var - bx, by: Integer; -begin - glPushMatrix(); - - bx := Round(x/(gMapInfo.Width - w)*(gBackSize.X - w)); - by := Round(y/(gMapInfo.Height - h)*(gBackSize.Y - h)); - - sX := x; - sY := y; - sWidth := w; - sHeight := h; - - fixViewportForScale(); - renderMapInternal(-bx, -by, true); - - glPopMatrix(); -end; - - -procedure DrawPlayer(p: TPlayer); -var - px, py, a, b, c, d, i: Integer; - //R: TRect; -begin - if (p = nil) or (p.FDummy) then - begin - glPushMatrix(); - g_Map_DrawBack(0, 0); - glPopMatrix(); - Exit; - end; - - if (profileFrameDraw = nil) then profileFrameDraw := TProfiler.Create('RENDER', g_profile_history_size); - if (profileFrameDraw <> nil) then profileFrameDraw.mainBegin(g_profile_frame_draw); - - gPlayerDrawn := p; - - glPushMatrix(); - - px := p.GameX + PLAYER_RECT_CX; - py := p.GameY + PLAYER_RECT_CY+p.Obj.slopeUpLeft; - - if (g_dbg_scale = 1.0) and (not g_dbg_ignore_bounds) then - begin - if (px > (gPlayerScreenSize.X div 2)) then a := -px+(gPlayerScreenSize.X div 2) else a := 0; - if (py > (gPlayerScreenSize.Y div 2)) then b := -py+(gPlayerScreenSize.Y div 2) else b := 0; - - if (px > gMapInfo.Width-(gPlayerScreenSize.X div 2)) then a := -gMapInfo.Width+gPlayerScreenSize.X; - if (py > gMapInfo.Height-(gPlayerScreenSize.Y div 2)) then b := -gMapInfo.Height+gPlayerScreenSize.Y; - - if (gMapInfo.Width = gPlayerScreenSize.X) then a := 0 - else if (gMapInfo.Width < gPlayerScreenSize.X) then - begin - // hcenter - a := (gPlayerScreenSize.X-gMapInfo.Width) div 2; - end; - - if (gMapInfo.Height = gPlayerScreenSize.Y) then b := 0 - else if (gMapInfo.Height < gPlayerScreenSize.Y) then - begin - // vcenter - b := (gPlayerScreenSize.Y-gMapInfo.Height) div 2; - end; - end - else - begin - // scaled, ignore level bounds - a := -px+(gPlayerScreenSize.X div 2); - b := -py+(gPlayerScreenSize.Y div 2); - end; - - sX := -a; - sY := -b; - sWidth := gPlayerScreenSize.X; - sHeight := gPlayerScreenSize.Y; - fixViewportForScale(); - - i := py - (sY + sHeight div 2); - if (p.IncCam > 0) then - begin - // clamp to level bounds - if (sY - p.IncCam < 0) then - p.IncCam := nclamp(sY, 0, 120); - // clamp around player position - if (i > 0) then - p.IncCam := nclamp(p.IncCam, 0, max(0, 120 - i)); - end - else if (p.IncCam < 0) then - begin - // clamp to level bounds - if (sY + sHeight - p.IncCam > gMapInfo.Height) then - p.IncCam := nclamp(sY + sHeight - gMapInfo.Height, -120, 0); - // clamp around player position - if (i < 0) then - p.IncCam := nclamp(p.IncCam, min(0, -120 - i), 0); - end; - - sY := sY - p.IncCam; - - if (not g_dbg_ignore_bounds) then - begin - if (sX+sWidth > gMapInfo.Width) then sX := gMapInfo.Width-sWidth; - if (sY+sHeight > gMapInfo.Height) then sY := gMapInfo.Height-sHeight; - if (sX < 0) then sX := 0; - if (sY < 0) then sY := 0; - end; - - if (gBackSize.X <= gPlayerScreenSize.X) or (gMapInfo.Width <= sWidth) then c := 0 else c := trunc((gBackSize.X-gPlayerScreenSize.X)*sX/(gMapInfo.Width-sWidth)); - if (gBackSize.Y <= gPlayerScreenSize.Y) or (gMapInfo.Height <= sHeight) then d := 0 else d := trunc((gBackSize.Y-gPlayerScreenSize.Y)*sY/(gMapInfo.Height-sHeight)); - - //r_smallmap_h: 0: left; 1: center; 2: right - //r_smallmap_v: 0: top; 1: center; 2: bottom - // horiz small map? - if (gMapInfo.Width = sWidth) then - begin - sX := 0; - end - else if (gMapInfo.Width < sWidth) then - begin - case r_smallmap_h of - 1: sX := -((sWidth-gMapInfo.Width) div 2); // center - 2: sX := -(sWidth-gMapInfo.Width); // right - else sX := 0; // left - end; - end; - // vert small map? - if (gMapInfo.Height = sHeight) then - begin - sY := 0; - end - else if (gMapInfo.Height < sHeight) then - begin - case r_smallmap_v of - 1: sY := -((sHeight-gMapInfo.Height) div 2); // center - 2: sY := -(sHeight-gMapInfo.Height); // bottom - else sY := 0; // top - end; - end; - - p.viewPortX := sX; - p.viewPortY := sY; - p.viewPortW := sWidth; - p.viewPortH := sHeight; - -{$IFDEF ENABLE_HOLMES} - if (p = gPlayer1) then - begin - g_Holmes_plrViewPos(sX, sY); - g_Holmes_plrViewSize(sWidth, sHeight); - end; -{$ENDIF} - - renderMapInternal(-c, -d, true); - - if (gGameSettings.GameMode <> GM_SINGLE) and (gPlayerIndicator > 0) then - case gPlayerIndicator of - 1: - p.DrawIndicator(_RGB(255, 255, 255)); - - 2: - for i := 0 to High(gPlayers) do - if gPlayers[i] <> nil then - if gPlayers[i] = p then p.DrawIndicator(_RGB(255, 255, 255)) - else if (gPlayers[i].Team = p.Team) and (gPlayers[i].Team <> TEAM_NONE) then - if gPlayerIndicatorStyle = 1 then - gPlayers[i].DrawIndicator(_RGB(192, 192, 192)) - else gPlayers[i].DrawIndicator(gPlayers[i].GetColor); - end; - - if p.FSpectator then - e_TextureFontPrintEx(p.GameX + PLAYER_RECT_CX - 4, - p.GameY + PLAYER_RECT_CY - 4, - 'X', gStdFont, 255, 255, 255, 1, True); - { - for a := 0 to High(gCollideMap) do - for b := 0 to High(gCollideMap[a]) do - begin - d := 0; - if ByteBool(gCollideMap[a, b] and MARK_WALL) then - d := d + 1; - if ByteBool(gCollideMap[a, b] and MARK_DOOR) then - d := d + 2; - - case d of - 1: e_DrawPoint(1, b, a, 200, 200, 200); - 2: e_DrawPoint(1, b, a, 64, 64, 255); - 3: e_DrawPoint(1, b, a, 255, 0, 255); - end; - end; - } - - glPopMatrix(); - - p.DrawPain(); - p.DrawPickup(); - p.DrawRulez(); - if gShowMap then DrawMinimap(p, _TRect(0, 0, 128, 128)); - if g_Debug_Player then - g_Player_DrawDebug(p); - p.DrawGUI(); -end; - -procedure drawProfilers (); -var - px: Integer = -1; - py: Integer = -1; -begin - if g_profile_frame_draw and (profileFrameDraw <> nil) then px := px-drawProfiles(px, py, profileFrameDraw); - if g_profile_collision and (profMapCollision <> nil) then begin px := px-drawProfiles(px, py, profMapCollision); py -= calcProfilesHeight(profMonsLOS); end; - if g_profile_los and (profMonsLOS <> nil) then begin px := px-drawProfiles(px, py, profMonsLOS); py -= calcProfilesHeight(profMonsLOS); end; -end; - -procedure g_Game_Draw(); -var - ID: DWORD; - w, h: Word; - ww, hh: Byte; - Time: Int64; - back: string; - plView1, plView2: TPlayer; - Split: Boolean; -begin - if gExit = EXIT_QUIT then Exit; - - Time := sys_GetTicks() {div 1000}; - FPSCounter := FPSCounter+1; - if Time - FPSTime >= 1000 then - begin - FPS := FPSCounter; - FPSCounter := 0; - FPSTime := Time; - end; - - if gGameOn or (gState = STATE_FOLD) then - begin - if (gPlayer1 <> nil) and (gPlayer2 <> nil) then - begin - gSpectMode := SPECT_NONE; - if not gRevertPlayers then - begin - plView1 := gPlayer1; - plView2 := gPlayer2; - end - else - begin - plView1 := gPlayer2; - plView2 := gPlayer1; - end; - end - else - if (gPlayer1 <> nil) or (gPlayer2 <> nil) then - begin - gSpectMode := SPECT_NONE; - if gPlayer2 = nil then - plView1 := gPlayer1 - else - plView1 := gPlayer2; - plView2 := nil; - end - else - begin - plView1 := nil; - plView2 := nil; - end; - - if (plView1 = nil) and (plView2 = nil) and (gSpectMode = SPECT_NONE) then - gSpectMode := SPECT_STATS; - - if gSpectMode = SPECT_PLAYERS then - if gPlayers <> nil then - begin - plView1 := GetActivePlayer_ByID(gSpectPID1); - if plView1 = nil then - begin - gSpectPID1 := GetActivePlayerID_Next(); - plView1 := GetActivePlayer_ByID(gSpectPID1); - end; - if gSpectViewTwo then - begin - plView2 := GetActivePlayer_ByID(gSpectPID2); - if plView2 = nil then - begin - gSpectPID2 := GetActivePlayerID_Next(); - plView2 := GetActivePlayer_ByID(gSpectPID2); - end; - end; - end; - - if gSpectMode = SPECT_MAPVIEW then - begin - // Ðåæèì ïðîñìîòðà êàðòû - Split := False; - e_SetViewPort(0, 0, gScreenWidth, gScreenHeight); - DrawMapView(gSpectX, gSpectY, gScreenWidth, gScreenHeight); - gHearPoint1.Active := True; - gHearPoint1.Coords.X := gScreenWidth div 2 + gSpectX; - gHearPoint1.Coords.Y := gScreenHeight div 2 + gSpectY; - gHearPoint2.Active := False; - end - else - begin - Split := (plView1 <> nil) and (plView2 <> nil); - - // Òî÷êè ñëóõà èãðîêîâ - if plView1 <> nil then - begin - gHearPoint1.Active := True; - gHearPoint1.Coords.X := plView1.GameX + PLAYER_RECT.Width; - gHearPoint1.Coords.Y := plView1.GameY + PLAYER_RECT.Height DIV 2; - end else - gHearPoint1.Active := False; - if plView2 <> nil then - begin - gHearPoint2.Active := True; - gHearPoint2.Coords.X := plView2.GameX + PLAYER_RECT.Width; - gHearPoint2.Coords.Y := plView2.GameY + PLAYER_RECT.Height DIV 2; - end else - gHearPoint2.Active := False; - - // Ðàçìåð ýêðàíîâ èãðîêîâ: - gPlayerScreenSize.X := gScreenWidth-196; - if Split then - begin - gPlayerScreenSize.Y := gScreenHeight div 2; - if gScreenHeight mod 2 = 0 then - Dec(gPlayerScreenSize.Y); - end - else - gPlayerScreenSize.Y := gScreenHeight; - - if Split then - if gScreenHeight mod 2 = 0 then - e_SetViewPort(0, gPlayerScreenSize.Y+2, gPlayerScreenSize.X+196, gPlayerScreenSize.Y) - else - e_SetViewPort(0, gPlayerScreenSize.Y+1, gPlayerScreenSize.X+196, gPlayerScreenSize.Y); - - DrawPlayer(plView1); - gPlayer1ScreenCoord.X := sX; - gPlayer1ScreenCoord.Y := sY; - - if Split then - begin - e_SetViewPort(0, 0, gPlayerScreenSize.X+196, gPlayerScreenSize.Y); - - DrawPlayer(plView2); - gPlayer2ScreenCoord.X := sX; - gPlayer2ScreenCoord.Y := sY; - end; - - e_SetViewPort(0, 0, gScreenWidth, gScreenHeight); - - if Split then - e_DrawLine(2, 0, gScreenHeight div 2, gScreenWidth, gScreenHeight div 2, 0, 0, 0); - end; - -{$IFDEF ENABLE_HOLMES} - // draw inspector - if (g_holmes_enabled) then g_Holmes_Draw(); -{$ENDIF} - - if MessageText <> '' then - begin - w := 0; - h := 0; - e_CharFont_GetSizeFmt(gMenuFont, MessageText, w, h); - if Split then - e_CharFont_PrintFmt(gMenuFont, (gScreenWidth div 2)-(w div 2), - (gScreenHeight div 2)-(h div 2), MessageText) - else - e_CharFont_PrintFmt(gMenuFont, (gScreenWidth div 2)-(w div 2), - Round(gScreenHeight / 2.75)-(h div 2), MessageText); - end; - - if IsDrawStat or (gSpectMode = 1) then DrawStat(); - - if gSpectHUD and (not gChatShow) and (gSpectMode <> SPECT_NONE) and (not gSpectAuto) then - begin - // Draw spectator GUI - ww := 0; - hh := 0; - e_TextureFontGetSize(gStdFont, ww, hh); - case gSpectMode of - SPECT_STATS: - e_TextureFontPrintEx(0, gScreenHeight - (hh+2)*2, 'MODE: Stats', gStdFont, 255, 255, 255, 1); - SPECT_MAPVIEW: - e_TextureFontPrintEx(0, gScreenHeight - (hh+2)*2, 'MODE: Observe Map', gStdFont, 255, 255, 255, 1); - SPECT_PLAYERS: - e_TextureFontPrintEx(0, gScreenHeight - (hh+2)*2, 'MODE: Watch Players', gStdFont, 255, 255, 255, 1); - end; - e_TextureFontPrintEx(2*ww, gScreenHeight - (hh+2), '< jump >', gStdFont, 255, 255, 255, 1); - if gSpectMode = SPECT_STATS then - begin - e_TextureFontPrintEx(16*ww, gScreenHeight - (hh+2)*2, 'Autoview', gStdFont, 255, 255, 255, 1); - e_TextureFontPrintEx(16*ww, gScreenHeight - (hh+2), '< fire >', gStdFont, 255, 255, 255, 1); - end; - if gSpectMode = SPECT_MAPVIEW then - begin - e_TextureFontPrintEx(22*ww, gScreenHeight - (hh+2)*2, '[-]', gStdFont, 255, 255, 255, 1); - e_TextureFontPrintEx(26*ww, gScreenHeight - (hh+2)*2, 'Step ' + IntToStr(gSpectStep), gStdFont, 255, 255, 255, 1); - e_TextureFontPrintEx(34*ww, gScreenHeight - (hh+2)*2, '[+]', gStdFont, 255, 255, 255, 1); - e_TextureFontPrintEx(18*ww, gScreenHeight - (hh+2), '', gStdFont, 255, 255, 255, 1); - e_TextureFontPrintEx(30*ww, gScreenHeight - (hh+2), '', gStdFont, 255, 255, 255, 1); - end; - if gSpectMode = SPECT_PLAYERS then - begin - e_TextureFontPrintEx(22*ww, gScreenHeight - (hh+2)*2, 'Player 1', gStdFont, 255, 255, 255, 1); - e_TextureFontPrintEx(20*ww, gScreenHeight - (hh+2), '', gStdFont, 255, 255, 255, 1); - if gSpectViewTwo then - begin - e_TextureFontPrintEx(37*ww, gScreenHeight - (hh+2)*2, 'Player 2', gStdFont, 255, 255, 255, 1); - e_TextureFontPrintEx(34*ww, gScreenHeight - (hh+2), '', gStdFont, 255, 255, 255, 1); - e_TextureFontPrintEx(52*ww, gScreenHeight - (hh+2)*2, '2x View', gStdFont, 255, 255, 255, 1); - e_TextureFontPrintEx(51*ww, gScreenHeight - (hh+2), '', gStdFont, 255, 255, 255, 1); - end - else - begin - e_TextureFontPrintEx(35*ww, gScreenHeight - (hh+2)*2, '2x View', gStdFont, 255, 255, 255, 1); - e_TextureFontPrintEx(34*ww, gScreenHeight - (hh+2), '', gStdFont, 255, 255, 255, 1); - end; - end; - end; - end; - - if gPauseMain and gGameOn and (g_ActiveWindow = nil) then - begin - //e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180); - e_DarkenQuadWH(0, 0, gScreenWidth, gScreenHeight, 150); - - e_CharFont_GetSize(gMenuFont, _lc[I_MENU_PAUSE], w, h); - e_CharFont_Print(gMenuFont, (gScreenWidth div 2)-(w div 2), - (gScreenHeight div 2)-(h div 2), _lc[I_MENU_PAUSE]); - end; - - if not gGameOn then - begin - if (gState = STATE_MENU) then - begin - if (g_ActiveWindow = nil) or (g_ActiveWindow.BackTexture = '') then DrawMenuBackground('MENU_BACKGROUND'); - // F3 at menu will show game loading dialog - if e_KeyPressed(IK_F3) then g_Menu_Show_LoadMenu(true); - if (g_ActiveWindow <> nil) then - begin - //e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180); - e_DarkenQuadWH(0, 0, gScreenWidth, gScreenHeight, 150); - end - else - begin - // F3 at titlepic will show game loading dialog - if e_KeyPressed(IK_F3) then - begin - g_Menu_Show_LoadMenu(true); - if (g_ActiveWindow <> nil) then e_DarkenQuadWH(0, 0, gScreenWidth, gScreenHeight, 150); - end; - end; - end; - - if gState = STATE_FOLD then - begin - e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 0, 0, 0, EndingGameCounter); - end; - - if gState = STATE_INTERCUSTOM then - begin - if gLastMap and (gGameSettings.GameMode = GM_COOP) then - begin - back := 'TEXTURE_endpic'; - if not g_Texture_Get(back, ID) then - back := _lc[I_TEXTURE_ENDPIC]; - end - else - back := 'INTER'; - - DrawMenuBackground(back); - - DrawCustomStat(); - - if g_ActiveWindow <> nil then - begin - //e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180); - e_DarkenQuadWH(0, 0, gScreenWidth, gScreenHeight, 150); - end; - end; - - if gState = STATE_INTERSINGLE then - begin - if EndingGameCounter > 0 then - begin - e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 0, 0, 0, EndingGameCounter); - end - else - begin - back := 'INTER'; - - DrawMenuBackground(back); - - DrawSingleStat(); - - if g_ActiveWindow <> nil then - begin - //e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180); - e_DarkenQuadWH(0, 0, gScreenWidth, gScreenHeight, 150); - end; - end; - end; - - if gState = STATE_ENDPIC then - begin - ID := DWORD(-1); - if g_Texture_Get('TEXTURE_endpic', ID) then DrawMenuBackground('TEXTURE_endpic') - else DrawMenuBackground(_lc[I_TEXTURE_ENDPIC]); - - if g_ActiveWindow <> nil then - begin - //e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180); - e_DarkenQuadWH(0, 0, gScreenWidth, gScreenHeight, 150); - end; - end; - - if gState = STATE_SLIST then - begin -// if g_Texture_Get('MENU_BACKGROUND', ID) then -// begin -// e_DrawSize(ID, 0, 0, 0, False, False, gScreenWidth, gScreenHeight); -// //e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180); -// end; - DrawMenuBackground('MENU_BACKGROUND'); - e_DarkenQuadWH(0, 0, gScreenWidth, gScreenHeight, 150); - g_Serverlist_Draw(slCurrent, slTable); - end; - end; - - if g_ActiveWindow <> nil then - begin - if gGameOn then - begin - //e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180); - e_DarkenQuadWH(0, 0, gScreenWidth, gScreenHeight, 150); - end; - g_ActiveWindow.Draw(); - end; - -{$IFNDEF HEADLESS} - g_Console_Draw(); -{$ENDIF} - - if g_debug_Sounds and gGameOn then - begin - for w := 0 to High(e_SoundsArray) do - for h := 0 to e_SoundsArray[w].nRefs do - e_DrawPoint(1, w+100, h+100, 255, 0, 0); - end; - - if gShowFPS then - begin - e_TextureFontPrint(0, 0, Format('FPS: %d', [FPS]), gStdFont); - e_TextureFontPrint(0, 16, Format('UPS: %d', [UPS]), gStdFont); - end; - - if gGameOn and gShowTime then - drawTime(gScreenWidth-72, gScreenHeight-16); - - if gGameOn then drawProfilers(); + g_Sound_Delete('SOUND_ANNOUNCER_KILL2X'); + g_Sound_Delete('SOUND_ANNOUNCER_KILL3X'); + g_Sound_Delete('SOUND_ANNOUNCER_KILL4X'); + g_Sound_Delete('SOUND_ANNOUNCER_KILLMX'); -{$IFDEF ENABLE_HOLMES} - g_Holmes_DrawUI(); -{$ENDIF} + hahasnd[0].Free(); + hahasnd[1].Free(); + hahasnd[2].Free(); - g_Touch_Draw; -end; + g_Sound_Delete('SOUND_ANNOUNCER_MUHAHA1'); + g_Sound_Delete('SOUND_ANNOUNCER_MUHAHA2'); + g_Sound_Delete('SOUND_ANNOUNCER_MUHAHA3'); -procedure g_Game_Quit(); -begin - g_Game_StopAllSounds(True); - gMusic.Free(); - g_Game_FreeData(); - g_PlayerModel_FreeData(); - g_Texture_DeleteAll(); - g_Frames_DeleteAll(); -{$IFNDEF HEADLESS} - //g_Menu_Free(); //k8: this segfaults after resolution change; who cares? -{$ENDIF} + sound_get_flag[0].Free(); + sound_get_flag[1].Free(); + sound_lost_flag[0].Free(); + sound_lost_flag[1].Free(); + sound_ret_flag[0].Free(); + sound_ret_flag[1].Free(); + sound_cap_flag[0].Free(); + sound_cap_flag[1].Free(); - if NetInitDone then g_Net_Free; + g_Sound_Delete('SOUND_CTF_GET1'); + g_Sound_Delete('SOUND_CTF_GET2'); + g_Sound_Delete('SOUND_CTF_LOST1'); + g_Sound_Delete('SOUND_CTF_LOST2'); + g_Sound_Delete('SOUND_CTF_RETURN1'); + g_Sound_Delete('SOUND_CTF_RETURN2'); + g_Sound_Delete('SOUND_CTF_CAPTURE1'); + g_Sound_Delete('SOUND_CTF_CAPTURE2'); -// Íàäî óäàëèòü êàðòó ïîñëå òåñòà: - if gMapToDelete <> '' then - g_Game_DeleteTestMap(); + g_Game_FreeChatSounds(); - gExit := EXIT_QUIT; - sys_RequestQuit; + DataLoaded := False; end; procedure g_FatalError(Text: String); @@ -4198,6 +2616,7 @@ begin e_WriteLog(Format(_lc[I_FATAL_ERROR], [Text]), TMsgType.Warning); gExit := EXIT_SIMPLE; + if gGameOn then EndGame; end; procedure g_SimpleError(Text: String); @@ -4206,71 +2625,28 @@ begin e_WriteLog(Format(_lc[I_SIMPLE_ERROR], [Text]), TMsgType.Warning); end; -procedure g_Game_SetupScreenSize(); -const - RES_FACTOR = 4.0 / 3.0; -var - s: Single; - rf: Single; - bw, bh: Word; -begin -// Ðàçìåð ýêðàíîâ èãðîêîâ: - gPlayerScreenSize.X := gScreenWidth-196; - if (gPlayer1 <> nil) and (gPlayer2 <> nil) then - gPlayerScreenSize.Y := gScreenHeight div 2 - else - gPlayerScreenSize.Y := gScreenHeight; - -// Ðàçìåð çàäíåãî ïëàíà: - if BackID <> DWORD(-1) then - begin - s := SKY_STRETCH; - if (gScreenWidth*s > gMapInfo.Width) or - (gScreenHeight*s > gMapInfo.Height) then - begin - gBackSize.X := gScreenWidth; - gBackSize.Y := gScreenHeight; - end - else - begin - e_GetTextureSize(BackID, @bw, @bh); - rf := Single(bw) / Single(bh); - if (rf > RES_FACTOR) then bw := Round(Single(bh) * RES_FACTOR) - else if (rf < RES_FACTOR) then bh := Round(Single(bw) / RES_FACTOR); - s := Max(gScreenWidth / bw, gScreenHeight / bh); - if (s < 1.0) then s := 1.0; - gBackSize.X := Round(bw*s); - gBackSize.Y := Round(bh*s); - end; - end; -end; - -procedure g_Game_ChangeResolution(newWidth, newHeight: Word; nowFull, nowMax: Boolean); -begin - sys_SetDisplayMode(newWidth, newHeight, gBPP, nowFull, nowMax); -end; - procedure g_Game_AddPlayer(Team: Byte = TEAM_NONE); begin if ((not gGameOn) and (gState <> STATE_INTERCUSTOM)) or (not (gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT])) then Exit; + + if (gGameSettings.MaxLives > 0) and (gLMSRespawn = LMS_RESPAWN_NONE) then + Exit; + if gPlayer1 = nil then begin if g_Game_IsClient then begin if NetPlrUID1 > -1 then - begin MC_SEND_CheatRequest(NET_CHEAT_SPECTATE); - gPlayer1 := g_Player_Get(NetPlrUID1); - end; Exit; end; if not (Team in [TEAM_RED, TEAM_BLUE]) then Team := gPlayer1Settings.Team; - // Ñîçäàíèå ïåðâîãî èãðîêà: + // Создание первого игрока: gPlayer1 := g_Player_Get(g_Player_Create(gPlayer1Settings.Model, gPlayer1Settings.Color, Team, False)); @@ -4300,7 +2676,7 @@ begin if not (Team in [TEAM_RED, TEAM_BLUE]) then Team := gPlayer2Settings.Team; - // Ñîçäàíèå âòîðîãî èãðîêà: + // Создание второго игрока: gPlayer2 := g_Player_Get(g_Player_Create(gPlayer2Settings.Model, gPlayer2Settings.Color, Team, False)); @@ -4337,8 +2713,12 @@ begin g_Console_Add(Format(_lc[I_PLAYER_LEAVE], [Pl.Name]), True); g_Player_Remove(Pl.UID); g_Net_Slist_ServerPlayerLeaves(); - end else + end + else + begin + gSpectLatchPID2 := Pl.UID; gPlayer2 := nil; + end; Exit; end; Pl := gPlayer1; @@ -4353,6 +2733,7 @@ begin g_Net_Slist_ServerPlayerLeaves(); end else begin + gSpectLatchPID1 := Pl.UID; gPlayer1 := nil; MC_SEND_CheatRequest(NET_CHEAT_SPECTATE); end; @@ -4385,7 +2766,7 @@ begin g_Game_ClearLoading(); -// Íàñòðîéêè èãðû: +// Настройки игры: FillByte(gGameSettings, SizeOf(TGameSettings), 0); gAimLine := False; gShowMap := False; @@ -4394,14 +2775,18 @@ begin gGameSettings.Options := gGameSettings.Options + GAME_OPTION_ALLOWEXIT; gGameSettings.Options := gGameSettings.Options + GAME_OPTION_MONSTERS; gGameSettings.Options := gGameSettings.Options + GAME_OPTION_BOTVSMONSTER; + gGameSettings.Options := gGameSettings.Options + GAME_OPTION_TEAMHITPROJECTILE; + gGameSettings.Options := gGameSettings.Options + GAME_OPTION_TEAMHITTRACE; gSwitchGameMode := GM_SINGLE; - g_Game_ExecuteEvent('ongamestart'); + gLMSRespawn := LMS_RESPAWN_NONE; + gLMSRespawnTime := 0; + gSpectLatchPID1 := 0; + gSpectLatchPID2 := 0; -// Óñòàíîâêà ðàçìåðîâ îêîí èãðîêîâ: - g_Game_SetupScreenSize(); + g_Game_ExecuteEvent('ongamestart'); -// Ñîçäàíèå ïåðâîãî èãðîêà: +// Создание первого игрока: gPlayer1 := g_Player_Get(g_Player_Create(gPlayer1Settings.Model, gPlayer1Settings.Color, gPlayer1Settings.Team, False)); @@ -4414,7 +2799,7 @@ begin gPlayer1.Name := gPlayer1Settings.Name; nPl := 1; -// Ñîçäàíèå âòîðîãî èãðîêà, åñëè åñòü: +// Создание второго игрока, если есть: if TwoPlayers then begin gPlayer2 := g_Player_Get(g_Player_Create(gPlayer2Settings.Model, @@ -4430,7 +2815,7 @@ begin Inc(nPl); end; -// Çàãðóçêà è çàïóñê êàðòû: +// Загрузка и запуск карты: if not g_Game_StartMap(false{asMegawad}, MAP, True) then begin if (Pos(':\', Map) > 0) or (Pos(':/', Map) > 0) then tmps := Map else tmps := gGameSettings.WAD + ':\' + MAP; @@ -4438,10 +2823,10 @@ begin Exit; end; -// Íàñòðîéêè èãðîêîâ è áîòîâ: +// Настройки игроков и ботов: g_Player_Init(); -// Ñîçäàåì áîòîâ: +// Создаем ботов: for i := nPl+1 to nPlayers do g_Player_Create(STD_PLAYER_MODEL, _RGB(0, 0, 0), 0, True); end; @@ -4459,7 +2844,7 @@ begin g_Game_ClearLoading(); -// Íàñòðîéêè èãðû: +// Настройки игры: gGameSettings.GameType := GT_CUSTOM; gGameSettings.GameMode := GameMode; gSwitchGameMode := GameMode; @@ -4475,12 +2860,14 @@ begin gAimLine := False; gShowMap := False; - g_Game_ExecuteEvent('ongamestart'); + gLMSRespawn := LMS_RESPAWN_NONE; + gLMSRespawnTime := 0; + gSpectLatchPID1 := 0; + gSpectLatchPID2 := 0; -// Óñòàíîâêà ðàçìåðîâ îêîí èãðîêîâ: - g_Game_SetupScreenSize(); + g_Game_ExecuteEvent('ongamestart'); -// Ðåæèì íàáëþäàòåëÿ: +// Режим наблюдателя: if nPlayers = 0 then begin gPlayer1 := nil; @@ -4490,7 +2877,7 @@ begin nPl := 0; if nPlayers >= 1 then begin - // Ñîçäàíèå ïåðâîãî èãðîêà: + // Создание первого игрока: gPlayer1 := g_Player_Get(g_Player_Create(gPlayer1Settings.Model, gPlayer1Settings.Color, gPlayer1Settings.Team, False)); @@ -4506,7 +2893,7 @@ begin if nPlayers >= 2 then begin - // Ñîçäàíèå âòîðîãî èãðîêà: + // Создание второго игрока: gPlayer2 := g_Player_Get(g_Player_Create(gPlayer2Settings.Model, gPlayer2Settings.Color, gPlayer2Settings.Team, False)); @@ -4520,14 +2907,14 @@ begin Inc(nPl); end; -// Çàãðóçêà è çàïóñê êàðòû: +// Загрузка и запуск карты: if not g_Game_StartMap(true{asMegawad}, Map, True) then begin g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Map])); Exit; end; -// Íåò òî÷åê ïîÿâëåíèÿ: +// Нет точек появления: if (g_Map_GetPointCount(RESPAWNPOINT_PLAYER1) + g_Map_GetPointCount(RESPAWNPOINT_PLAYER2) + g_Map_GetPointCount(RESPAWNPOINT_DM) + @@ -4538,10 +2925,10 @@ begin Exit; end; -// Íàñòðîéêè èãðîêîâ è áîòîâ: +// Настройки игроков и ботов: g_Player_Init(); -// Ñîçäàåì áîòîâ: +// Создаем ботов: for i := nPl+1 to nPlayers do g_Player_Create(STD_PLAYER_MODEL, _RGB(0, 0, 0), 0, True); end; @@ -4558,7 +2945,7 @@ begin g_Game_ClearLoading(); -// Íàñòðîéêè èãðû: +// Настройки игры: gGameSettings.GameType := GT_SERVER; gGameSettings.GameMode := GameMode; gSwitchGameMode := GameMode; @@ -4574,12 +2961,14 @@ begin gAimLine := False; gShowMap := False; - g_Game_ExecuteEvent('ongamestart'); + gLMSRespawn := LMS_RESPAWN_NONE; + gLMSRespawnTime := 0; + gSpectLatchPID1 := 0; + gSpectLatchPID2 := 0; -// Óñòàíîâêà ðàçìåðîâ îêíà èãðîêà - g_Game_SetupScreenSize(); + g_Game_ExecuteEvent('ongamestart'); -// Ðåæèì íàáëþäàòåëÿ: +// Режим наблюдателя: if nPlayers = 0 then begin gPlayer1 := nil; @@ -4588,7 +2977,7 @@ begin if nPlayers >= 1 then begin - // Ñîçäàíèå ïåðâîãî èãðîêà: + // Создание первого игрока: gPlayer1 := g_Player_Get(g_Player_Create(gPlayer1Settings.Model, gPlayer1Settings.Color, gPlayer1Settings.Team, False)); @@ -4603,7 +2992,7 @@ begin if nPlayers >= 2 then begin - // Ñîçäàíèå âòîðîãî èãðîêà: + // Создание второго игрока: gPlayer2 := g_Player_Get(g_Player_Create(gPlayer2Settings.Model, gPlayer2Settings.Color, gPlayer2Settings.Team, False)); @@ -4620,7 +3009,7 @@ begin if NetForwardPorts then g_Game_SetLoadingText(_lc[I_LOAD_PORTS], 0, False); -// Ñòàðòóåì ñåðâåð +// Стартуем сервер if not g_Net_Host(IPAddr, Port, NetMaxClients) then begin g_FatalError(_lc[I_NET_MSG] + Format(_lc[I_NET_ERR_HOST], [Port])); @@ -4631,7 +3020,7 @@ begin g_Net_Slist_ServerStarted(); -// Çàãðóçêà è çàïóñê êàðòû: +// Загрузка и запуск карты: if not g_Game_StartMap(false{asMegawad}, Map, True) then begin g_Net_Slist_ServerClosed(); @@ -4639,7 +3028,7 @@ begin Exit; end; -// Íåò òî÷åê ïîÿâëåíèÿ: +// Нет точек появления: if (g_Map_GetPointCount(RESPAWNPOINT_PLAYER1) + g_Map_GetPointCount(RESPAWNPOINT_PLAYER2) + g_Map_GetPointCount(RESPAWNPOINT_DM) + @@ -4651,7 +3040,7 @@ begin Exit; end; -// Íàñòðîéêè èãðîêîâ è áîòîâ: +// Настройки игроков и ботов: g_Player_Init(); g_Net_Slist_ServerMapStarted(); @@ -4678,7 +3067,7 @@ begin g_Game_ClearLoading(); -// Íàñòðîéêè èãðû: +// Настройки игры: gGameSettings.GameType := GT_CLIENT; gCoopTotalMonstersKilled := 0; @@ -4690,9 +3079,6 @@ begin g_Game_ExecuteEvent('ongamestart'); -// Óñòàíîâêà ðàçìåðîâ îêîí èãðîêîâ: - g_Game_SetupScreenSize(); - NetState := NET_STATE_AUTH; g_Game_SetLoadingText(_lc[I_LOAD_CONNECT], 0, False); @@ -4700,7 +3086,12 @@ begin // create (or update) map/resource databases g_Res_CreateDatabases(true); -// Ñòàðòóåì êëèåíò + gLMSRespawn := LMS_RESPAWN_NONE; + gLMSRespawnTime := 0; + gSpectLatchPID1 := 0; + gSpectLatchPID2 := 0; + +// Стартуем клиент if not g_Net_Connect(Addr, Port) then begin g_FatalError(_lc[I_NET_MSG] + _lc[I_NET_ERR_CONN]); @@ -4839,9 +3230,6 @@ begin Exit; end; - gLMSRespawn := LMS_RESPAWN_NONE; - gLMSRespawnTime := 0; - g_Player_Init(); NetState := NET_STATE_GAME; MC_SEND_FullStateRequest; @@ -4858,7 +3246,7 @@ begin g_Game_ClearLoading(); Force := gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF]; - // Åñëè óðîâåíü çàâåðøèëñÿ ïî òðèããåðó Âûõîä, íå î÷èùàòü èíâåíòàðü + // Если уровень завершился по триггеру Выход, не очищать инвентарь if gExitByTrigger then begin Force := False; @@ -4959,23 +3347,28 @@ begin begin //result := g_Map_Load(gGameSettings.WAD + ':\' + ResName); result := g_Map_Load(NewWAD+':\'+ResName); + {$IFNDEF HEADLESS} + r_Render_LoadTextures; + {$ENDIF} end; if Result then begin g_Player_ResetAll(Force or gLastMap, gGameSettings.GameType = GT_SINGLE); gState := STATE_NONE; - g_ActiveWindow := nil; + {$IFDEF ENABLE_MENU} + g_ActiveWindow := nil; + {$ENDIF} gGameOn := True; DisableCheats(); - ResetTimer(); + wNeedTimeReset := True; if gGameSettings.GameMode = GM_CTF then begin g_Map_ResetFlag(FLAG_RED); g_Map_ResetFlag(FLAG_BLUE); - // CTF, à ôëàãîâ íåò: + // CTF, а флагов нет: if not g_Map_HaveFlagPoints() then g_SimpleError(_lc[I_GAME_ERROR_CTF]); end; @@ -4992,8 +3385,8 @@ begin NetTimeToUpdate := 1; NetTimeToReliable := 0; NetTimeToMaster := NetMasterRate; - gLMSRespawn := LMS_RESPAWN_NONE; - gLMSRespawnTime := 0; + gSpectLatchPID1 := 0; + gSpectLatchPID2 := 0; gMissionFailed := False; gNextMap := ''; @@ -5011,22 +3404,28 @@ begin g_Game_SpectateCenterView(); - if (gGameSettings.MaxLives > 0) and (gGameSettings.WarmupTime > 0) then + if g_Game_IsServer then begin - gLMSRespawn := LMS_RESPAWN_WARMUP; - gLMSRespawnTime := gTime + gGameSettings.WarmupTime*1000; - gLMSSoftSpawn := True; - if NetMode = NET_SERVER then - MH_SEND_GameEvent(NET_EV_LMS_WARMUP, (gLMSRespawnTime - gTime) div 1000) + if (gGameSettings.MaxLives > 0) and (gGameSettings.WarmupTime > 0) then + begin + gLMSRespawn := LMS_RESPAWN_WARMUP; + gLMSRespawnTime := gTime + gGameSettings.WarmupTime*1000; + gLMSSoftSpawn := True; + if g_Game_IsNet then + MH_SEND_GameEvent(NET_EV_LMS_WARMUP, gLMSRespawnTime - gTime); + end else - g_Console_Add(Format(_lc[I_MSG_WARMUP_START], [(gLMSRespawnTime - gTime) div 1000]), True); + begin + gLMSRespawn := LMS_RESPAWN_NONE; + gLMSRespawnTime := 0; + end; end; if NetMode = NET_SERVER then begin MH_SEND_GameEvent(NET_EV_MAPSTART, gGameSettings.GameMode, Map); - // Ìàñòåðñåðâåð + // Мастерсервер g_Net_Slist_ServerMapStarted(); if NetClients <> nil then @@ -5079,10 +3478,10 @@ begin gCoopTotalMonsters := gCoopTotalMonsters + gTotalMonsters; gCoopTotalSecrets := gCoopTotalSecrets + gSecretsCount; -// Âûøëè â âûõîä â Îäèíî÷íîé èãðå: +// Вышли в выход в Одиночной игре: if gGameSettings.GameType = GT_SINGLE then gExit := EXIT_ENDLEVELSINGLE - else // Âûøëè â âûõîä â Ñâîåé èãðå + else // Вышли в выход в Своей игре begin gExit := EXIT_ENDLEVELCUSTOM; if gGameSettings.GameMode = GM_COOP then @@ -5168,13 +3567,6 @@ end; procedure g_Game_RestartRound(NoMapRestart: Boolean = False); var i, n, nb, nr: Integer; - - function monRespawn (mon: TMonster): Boolean; - begin - result := false; // don't stop - if not mon.FNoRespawn then mon.Respawn(); - end; - begin if not g_Game_IsServer then Exit; if gLMSRespawn = LMS_RESPAWN_NONE then Exit; @@ -5200,12 +3592,14 @@ begin else if gPlayers[i].Team = TEAM_BLUE then Inc(nb) end; - if (n < 2) or ((gGameSettings.GameMode = GM_TDM) and ((nr = 0) or (nb = 0))) then + if (n < 1) or ((gGameSettings.GameMode = GM_TDM) and ((nr = 0) or (nb = 0))) then begin // wait a second until the fuckers finally decide to join gLMSRespawn := LMS_RESPAWN_WARMUP; - gLMSRespawnTime := gTime + 1000; + gLMSRespawnTime := gTime + gGameSettings.WarmupTime*1000; gLMSSoftSpawn := NoMapRestart; + if g_Game_IsNet then + MH_SEND_GameEvent(NET_EV_LMS_WARMUP, gLMSRespawnTime - gTime); Exit; end; @@ -5235,17 +3629,14 @@ begin gPlayers[i].Frags := 0; gPlayers[i].RecallState; end; - if (gPlayer1 = nil) and (gLMSPID1 > 0) then - gPlayer1 := g_Player_Get(gLMSPID1); - if (gPlayer2 = nil) and (gLMSPID2 > 0) then - gPlayer2 := g_Player_Get(gLMSPID2); + if (gPlayer1 = nil) and (gSpectLatchPID1 > 0) then + gPlayer1 := g_Player_Get(gSpectLatchPID1); + if (gPlayer2 = nil) and (gSpectLatchPID2 > 0) then + gPlayer2 := g_Player_Get(gSpectLatchPID2); end; g_Items_RestartRound(); - - g_Mons_ForEach(monRespawn); - gLMSSoftSpawn := False; end; @@ -5335,7 +3726,7 @@ begin if (a = 0) then a := Pos('.wad:/', toLowerCase1251(gMapToDelete)); if (a = 0) then exit; - // Âûäåëÿåì èìÿ wad-ôàéëà è èìÿ êàðòû + // Выделяем имя wad-файла и имя карты WadName := Copy(gMapToDelete, 1, a+3); Delete(gMapToDelete, 1, a+5); gMapToDelete := UpperCase(gMapToDelete); @@ -5343,7 +3734,7 @@ begin //CopyMemory(@MapName[0], @gMapToDelete[1], Min(16, Length(gMapToDelete))); { -// Èìÿ êàðòû íå ñòàíäàðòíîå òåñòîâîå: +// Имя карты не стандартное тестовое: if MapName <> TEST_MAP_NAME then Exit; @@ -5352,14 +3743,14 @@ begin time := g_GetFileTime(WadName); WAD := TWADFile.Create(); - // ×èòàåì Wad-ôàéë: + // Читаем Wad-файл: if not WAD.ReadFile(WadName) then - begin // Íåò òàêîãî WAD-ôàéëà + begin // Нет такого WAD-файла WAD.Free(); Exit; end; - // Ñîñòàâëÿåì ñïèñîê êàðò è èùåì íóæíóþ: + // Составляем список карт и ищем нужную: WAD.CreateImage(); MapList := WAD.GetResourcesList(''); @@ -5367,7 +3758,7 @@ begin for a := 0 to High(MapList) do if MapList[a] = MapName then begin - // Óäàëÿåì è ñîõðàíÿåì: + // Удаляем и сохраняем: WAD.RemoveResource('', MapName); WAD.SaveTo(WadName); Break; @@ -5452,6 +3843,18 @@ begin begin ParseGameFlag(GAME_OPTION_TEAMDAMAGE, I_MSG_FRIENDLY_FIRE_OFF, I_MSG_FRIENDLY_FIRE_ON); end + else if cmd = 'g_friendly_absorb_damage' then + begin + ParseGameFlag(GAME_OPTION_TEAMABSORBDAMAGE, I_MSG_FRIENDLY_FIRE_OFF, I_MSG_FRIENDLY_FIRE_ON); + end + else if cmd = 'g_friendly_hit_trace' then + begin + ParseGameFlag(GAME_OPTION_TEAMHITTRACE, I_MSG_FRIENDLY_FIRE_OFF, I_MSG_FRIENDLY_FIRE_ON); + end + else if cmd = 'g_friendly_hit_projectile' then + begin + ParseGameFlag(GAME_OPTION_TEAMHITPROJECTILE, I_MSG_FRIENDLY_FIRE_OFF, I_MSG_FRIENDLY_FIRE_ON); + end else if cmd = 'g_weaponstay' then begin ParseGameFlag(GAME_OPTION_WEAPONSTAY, I_MSG_WEAPONSTAY_OFF, I_MSG_WEAPONSTAY_ON); @@ -5498,6 +3901,12 @@ begin if g_Game_IsServer then begin gGameSettings.WarmupTime := gsWarmupTime; + // extend warmup if it's already going + if gLMSRespawn = LMS_RESPAWN_WARMUP then + begin + gLMSRespawnTime := gTime + gsWarmupTime * 1000; + if g_Game_IsNet then MH_SEND_GameEvent(NET_EV_LMS_WARMUP, gLMSRespawnTime - gTime); + end; if g_Game_IsNet then MH_SEND_GameSettings; end; end; @@ -5545,12 +3954,18 @@ begin begin if Length(p) = 2 then begin - a := Max(0, StrToInt(p[1])); - g_GFX_SetMax(a) + {$IFDEF ENABLE_GFX} + a := Max(0, StrToInt(p[1])); + g_GFX_SetMax(a) + {$ENDIF} end else if Length(p) = 1 then begin - e_LogWritefln('%s', [g_GFX_GetMax()]) + {$IFDEF ENABLE_GFX} + e_LogWritefln('%s', [g_GFX_GetMax()]) + {$ELSE} + e_LogWritefln('%s', [0]) + {$ENDIF} end else begin @@ -5577,12 +3992,18 @@ begin begin if Length(p) = 2 then begin - a := Max(0, StrToInt(p[1])); - g_Gibs_SetMax(a) + {$IFDEF ENABLE_GIBS} + a := Max(0, StrToInt(p[1])); + g_Gibs_SetMax(a) + {$ENDIF} end else if Length(p) = 1 then begin - e_LogWritefln('%s', [g_Gibs_GetMax()]) + {$IFDEF ENABLE_GIBS} + e_LogWritefln('%s', [g_Gibs_GetMax()]) + {$ELSE} + e_LogWritefln('%s', [0]) + {$ENDIF} end else begin @@ -5670,6 +4091,17 @@ end; procedure PlayerSettingsCVars(P: SSArray); var cmd: string; + team: Byte; + + function ParseTeam(s: string): Byte; + begin + result := 0; + case s of + 'red', '1': result := TEAM_RED; + 'blue', '2': result := TEAM_BLUE; + else result := TEAM_NONE; + end; + end; begin cmd := LowerCase(P[0]); case cmd of @@ -5763,6 +4195,34 @@ begin end; end; end; + 'p1_team': + begin + // TODO: switch teams if in game or store this separately + if (Length(P) > 1) then + begin + team := ParseTeam(P[1]); + if team = TEAM_NONE then + g_Console_Add('expected ''red'', ''blue'', 1 or 2') + else if not gGameOn and not g_Game_IsNet then + gPlayer1Settings.Team := team + else + g_Console_Add(_lc[I_MSG_ONMAPCHANGE]); + end; + end; + 'p2_team': + begin + // TODO: switch teams if in game or store this separately + if (Length(P) > 1) then + begin + team := ParseTeam(P[1]); + if team = TEAM_NONE then + g_Console_Add('expected ''red'', ''blue'', 1 or 2') + else if not gGameOn and not g_Game_IsNet then + gPlayer2Settings.Team := team + else + g_Console_Add(_lc[I_MSG_ONMAPCHANGE]); + end; + end; end; end; @@ -5787,7 +4247,7 @@ var //pt: TDFPoint; mon: TMonster; begin -// Êîìàíäû îòëàäî÷íîãî ðåæèìà: +// Команды отладочного режима: if {gDebugMode}conIsCheatsEnabled then begin cmd := LowerCase(P[0]); @@ -6136,13 +4596,17 @@ var listen: LongWord; found: Boolean; begin -// Îáùèå êîìàíäû: +// Общие команды: cmd := LowerCase(P[0]); chstr := ''; if cmd = 'pause' then begin - if (g_ActiveWindow = nil) then + {$IFDEF ENABLE_MENU} + if (g_ActiveWindow = nil) then + g_Game_Pause(not gPauseMain); + {$ELSE} g_Game_Pause(not gPauseMain); + {$ENDIF} end else if cmd = 'endgame' then gExit := EXIT_SIMPLE @@ -6188,7 +4652,7 @@ begin if gPlayers[a] <> nil then if Copy(LowerCase(gPlayers[a].Name), 1, Length(P[1])) = LowerCase(P[1]) then begin - // Íå îòêëþ÷àòü îñíîâíûõ èãðîêîâ â ñèíãëå + // Не отключать основных игроков в сингле if not(gPlayers[a] is TBot) and (gGameSettings.GameType = GT_SINGLE) then continue; gPlayers[a].Lives := 0; @@ -6196,7 +4660,7 @@ begin g_Console_Add(Format(_lc[I_PLAYER_LEAVE], [gPlayers[a].Name]), True); g_Player_Remove(gPlayers[a].UID); g_Net_Slist_ServerPlayerLeaves(); - // Åñëè íå ïåðåìåøàòü, ïðè äîáàâëåíèè íîâûõ áîòîâ ïîÿâÿòñÿ ñòàðûå + // Если не перемешать, при добавлении новых ботов появятся старые g_Bot_MixNames(); end; end else @@ -6232,6 +4696,34 @@ begin end else g_Console_Add(_lc[I_MSG_SERVERONLY]); end + else if cmd = 'kick_pid' then + begin + if g_Game_IsServer and g_Game_IsNet then + begin + if Length(P) < 2 then + begin + g_Console_Add('kick_pid '); + Exit; + end; + if P[1] = '' then + begin + g_Console_Add('kick_pid '); + Exit; + end; + + a := StrToIntDef(P[1], 0); + pl := g_Net_Client_ByPlayer(a); + if (pl <> nil) and pl^.Used and (pl^.Peer <> nil) then + begin + s := g_Net_ClientName_ByID(pl^.ID); + enet_peer_disconnect(pl^.Peer, NET_DISC_KICK); + g_Console_Add(Format(_lc[I_PLAYER_KICK], [s])); + MH_SEND_GameEvent(NET_EV_PLAYER_KICK, 0, s); + g_Net_Slist_ServerPlayerLeaves(); + end; + end else + g_Console_Add(_lc[I_MSG_SERVERONLY]); + end else if cmd = 'ban' then begin if g_Game_IsServer and g_Game_IsNet then @@ -6290,6 +4782,35 @@ begin end else g_Console_Add(_lc[I_MSG_SERVERONLY]); end + else if cmd = 'ban_pid' then + begin + if g_Game_IsServer and g_Game_IsNet then + begin + if Length(P) < 2 then + begin + g_Console_Add('ban_pid '); + Exit; + end; + if P[1] = '' then + begin + g_Console_Add('ban_pid '); + Exit; + end; + + a := StrToIntDef(P[1], 0); + pl := g_Net_Client_ByPlayer(a); + if (pl <> nil) and pl^.Used and (pl^.Peer <> nil) then + begin + s := g_Net_ClientName_ByID(pl^.ID); + g_Net_BanHost(pl^.Peer^.address.host, False); + enet_peer_disconnect(pl^.Peer, NET_DISC_TEMPBAN); + g_Console_Add(Format(_lc[I_PLAYER_BAN], [s])); + MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s); + g_Net_Slist_ServerPlayerLeaves(); + end; + end else + g_Console_Add(_lc[I_MSG_SERVERONLY]); + end else if cmd = 'permban' then begin if g_Game_IsServer and g_Game_IsNet then @@ -6350,6 +4871,57 @@ begin end else g_Console_Add(_lc[I_MSG_SERVERONLY]); end + else if cmd = 'permban_pid' then + begin + if g_Game_IsServer and g_Game_IsNet then + begin + if Length(P) < 2 then + begin + g_Console_Add('permban_pid '); + Exit; + end; + if P[1] = '' then + begin + g_Console_Add('permban_pid '); + Exit; + end; + + a := StrToIntDef(P[1], 0); + pl := g_Net_Client_ByPlayer(a); + if (pl <> nil) and pl^.Used and (pl^.Peer <> nil) then + begin + s := g_Net_ClientName_ByID(pl^.ID); + g_Net_BanHost(pl^.Peer^.address.host); + enet_peer_disconnect(pl^.Peer, NET_DISC_BAN); + g_Net_SaveBanList(); + g_Console_Add(Format(_lc[I_PLAYER_BAN], [s])); + MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s); + g_Net_Slist_ServerPlayerLeaves(); + end; + end else + g_Console_Add(_lc[I_MSG_SERVERONLY]); + end + else if cmd = 'permban_ip' then + begin + if g_Game_IsServer and g_Game_IsNet then + begin + if Length(P) < 2 then + begin + g_Console_Add('permban_ip '); + Exit; + end; + if P[1] = '' then + begin + g_Console_Add('permban_ip '); + Exit; + end; + + g_Net_BanHost(P[1]); + g_Net_SaveBanList(); + g_Console_Add(Format(_lc[I_PLAYER_BAN], [P[1]])); + end else + g_Console_Add(_lc[I_MSG_SERVERONLY]); + end else if cmd = 'unban' then begin if g_Game_IsServer and g_Game_IsNet then @@ -6558,6 +5130,7 @@ begin g_Game_Free(); with gGameSettings do begin + Options := gsGameFlags; GameMode := g_Game_TextToMode(gsGameMode); if gSwitchGameMode <> GM_NONE then GameMode := gSwitchGameMode; @@ -6612,6 +5185,7 @@ begin g_Game_Free(); with gGameSettings do begin + Options := gsGameFlags; GameMode := g_Game_TextToMode(gsGameMode); if gSwitchGameMode <> GM_NONE then GameMode := gSwitchGameMode; if GameMode = GM_NONE then GameMode := GM_DM; @@ -6963,7 +5537,9 @@ begin end else if cmd = 'screenshot' then begin - g_TakeScreenShot() + {$IFNDEF HEADLESS} + g_TakeScreenShot() + {$ENDIF} end else if cmd = 'weapon' then begin @@ -6984,7 +5560,7 @@ begin gSelectWeapon[b, a] := True end end -// Êîìàíäû Ñâîåé èãðû: +// Команды Своей игры: else if gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT] then begin if cmd = 'bot_addred' then @@ -7088,7 +5664,7 @@ begin begin if (Length(P) = 1) or (StrToIntDef(P[1], -1) <= 0) then Exit; - // Äîïîëíèòåëüíîå âðåìÿ: + // Дополнительное время: gGameSettings.TimeLimit := (gTime - gGameStartTime) div 1000 + Word(StrToIntDef(P[1], 0)); g_Console_Add(Format(_lc[I_MSG_TIME_LIMIT], @@ -7200,16 +5776,21 @@ begin g_Game_Free(); g_Game_Quit(); end; +{$IFNDEF HEADLESS} 'r_reset': + r_Render_Apply; +{$ENDIF} + 'r_maxfps': begin - sys_EnableVSync(gVSync); - gRC_Width := Max(1, gRC_Width); - gRC_Height := Max(1, gRC_Height); - gBPP := Max(1, gBPP); - if sys_SetDisplayMode(gRC_Width, gRC_Height, gBPP, gRC_FullScreen, gRC_Maximized) = True then - e_LogWriteln('resolution changed') - else - e_LogWriteln('resolution not changed'); + if Length(p) = 2 then + begin + gMaxFPS := StrToIntDef(p[1], gMaxFPS); + if gMaxFPS > 0 then + gFrameTime := 1000 div gMaxFPS + else + gFrameTime := 0; + end; + e_LogWritefln('r_maxfps %d', [gMaxFPS]); end; 'g_language': begin @@ -7244,36 +5825,30 @@ begin end; end; +{$IFNDEF HEADLESS} procedure g_TakeScreenShot(Filename: string = ''); - var s: TStream; t: TDateTime; dir, date, name: String; + var t: TDateTime; dir, date, name: String; begin - if e_NoGraphics then Exit; - try - dir := e_GetWriteableDir(ScreenshotDirs); + if e_NoGraphics then + Exit; - if Filename = '' then - begin - t := Now; - DateTimeToString(date, 'yyyy-mm-dd-hh-nn-ss', t); - Filename := 'screenshot-' + date; - end; - - name := e_CatPath(dir, Filename + '.png'); - s := createDiskFile(name); - try - e_MakeScreenshot(s, gScreenWidth, gScreenHeight); - s.Free; - g_Console_Add(Format(_lc[I_CONSOLE_SCREENSHOT], [name])) - except - g_Console_Add(Format(_lc[I_CONSOLE_ERROR_WRITE], [name])); - s.Free; - DeleteFile(name) - end - except - g_Console_Add('oh shit, i can''t create screenshot!') - end + dir := e_GetWriteableDir(ScreenshotDirs); + if Filename = '' then + begin + t := Now; + DateTimeToString(date, 'yyyy-mm-dd-hh-nn-ss', t); + Filename := 'screenshot-' + date; + end; + + name := e_CatPath(dir, Filename + '.png'); + if r_Render_WriteScreenShot(name) then + g_Console_Add(Format(_lc[I_CONSOLE_SCREENSHOT], [name])) + else + g_Console_Add(Format(_lc[I_CONSOLE_ERROR_WRITE], [name])); end; +{$ENDIF} +{$IFDEF ENABLE_MENU} procedure g_Game_InGameMenu(Show: Boolean); begin if (g_ActiveWindow = nil) and Show then @@ -7292,18 +5867,19 @@ begin end; g_Sound_PlayEx('MENU_OPEN'); - // Ïàóçà ïðè ìåíþ òîëüêî â îäèíî÷íîé èãðå: + // Пауза при меню только в одиночной игре: if (not g_Game_IsNet) then g_Game_Pause(True); end else if (g_ActiveWindow <> nil) and (not Show) then begin - // Ïàóçà ïðè ìåíþ òîëüêî â îäèíî÷íîé èãðå: + // Пауза при меню только в одиночной игре: if (not g_Game_IsNet) then g_Game_Pause(False); end; end; +{$ENDIF} procedure g_Game_Pause (Enable: Boolean); var @@ -7336,7 +5912,7 @@ procedure g_Game_PauseAllSounds(Enable: Boolean); var i: Integer; begin -// Òðèããåðû: +// Триггеры: if gTriggers <> nil then for i := 0 to High(gTriggers) do with gTriggers[i] do @@ -7347,13 +5923,13 @@ begin Sound.Pause(Enable); end; -// Çâóêè èãðîêîâ: +// Звуки игроков: if gPlayers <> nil then for i := 0 to High(gPlayers) do if gPlayers[i] <> nil then gPlayers[i].PauseSounds(Enable); -// Ìóçûêà: +// Музыка: if gMusic <> nil then gMusic.Pause(Enable); end; @@ -7447,12 +6023,11 @@ begin end; end; -procedure g_Game_Message(Msg: string; Time: Word); -begin - MessageLineLength := (gScreenWidth - 204) div e_CharFont_GetMaxWidth(gMenuFont); - MessageText := b_Text_Wrap(b_Text_Format(Msg), MessageLineLength); - MessageTime := Time; -end; + procedure g_Game_Message (Msg: string; Time: Word); + begin + MessageText := Msg; + MessageTime := Time; + end; procedure g_Game_ChatSound(Text: String; Taunt: Boolean = True); const @@ -7598,8 +6173,7 @@ begin case gAnnouncer of ANNOUNCE_NONE: Exit; - ANNOUNCE_ME, - ANNOUNCE_MEPLUS: + ANNOUNCE_ME: if not g_Game_IsWatchedPlayer(SpawnerUID) then Exit; end; @@ -7721,7 +6295,7 @@ end; procedure g_Game_SetDebugMode(); begin gDebugMode := True; -// ×èòû (äàæå â ñâîåé èãðå): +// Читы (даже в своей игре): gCheats := True; end; @@ -7735,7 +6309,7 @@ begin with LoadingStat do begin if not reWrite then - begin // Ïåðåõîäèì íà ñëåäóþùóþ ñòðîêó èëè ñêðîëëèðóåì: + begin // Переходим на следующую строку или скроллируем: if NextMsg = Length(Msgs) then begin // scroll for i := 0 to High(Msgs)-1 do @@ -7754,7 +6328,9 @@ begin PBarWasHere := false; end; - g_ActiveWindow := nil; + {$IFDEF ENABLE_MENU} + g_ActiveWindow := nil; + {$ENDIF} ProcessLoading(true); end; @@ -7810,7 +6386,7 @@ begin if (s[1] = '-') and (Length(s) > 1) then begin if (s[2] = '-') and (Length(s) > 2) then - begin // Îäèíî÷íûé ïàðàìåòð + begin // Одиночный параметр SetLength(pars, Length(pars) + 1); with pars[High(pars)] do begin @@ -7820,7 +6396,7 @@ begin end else if (i < ParamCount) then - begin // Ïàðàìåòð ñî çíà÷åíèåì + begin // Параметр со значением Inc(i); SetLength(pars, Length(pars) + 1); with pars[High(pars)] do @@ -7934,8 +6510,7 @@ begin // Options: s := Find_Param_Value(pars, '-opt'); if (s = '') then - Opt := GAME_OPTION_ALLOWEXIT or GAME_OPTION_BOTVSPLAYER or - GAME_OPTION_BOTVSMONSTER or GAME_OPTION_DMKEYS + Opt := gsGameFlags else Opt := StrToIntDef(s, 0); @@ -8037,8 +6612,10 @@ begin conRegVar('mon_sq_enabled', @gmon_debug_use_sqaccel, 'accelerated spatial queries for monsters', 'accelerated monster coldet'); conRegVar('wtrace_sq_enabled', @gwep_debug_fast_trace, 'accelerated spatial queries for weapon hitscan trace', 'accelerated weapon hitscan'); +{$IFDEF ENABLE_GFX} conRegVar('pr_enabled', @gpart_dbg_enabled, 'enable/disable particles', 'particles'); conRegVar('pr_phys_enabled', @gpart_dbg_phys_enabled, 'enable/disable particle physics', 'particle physics'); +{$ENDIF} conRegVar('los_enabled', @gmon_dbg_los_enabled, 'enable/disable monster LOS calculations', 'monster LOS', true); conRegVar('mon_think', @gmon_debug_think, 'enable/disable monster thinking', 'monster thinking', true); @@ -8049,9 +6626,6 @@ begin conRegVar('dbg_ignore_level_bounds', @g_dbg_ignore_bounds, 'ignore level bounds', '', false); - conRegVar('r_scale', @g_dbg_scale, 0.01, 100.0, 'render scale', '', false); - conRegVar('r_resolution_scale', @r_pixel_scale, 0.01, 100.0, 'upscale factor', '', false); - conRegVar('light_enabled', @gwin_k8_enable_light_experiments, 'enable/disable dynamic lighting', 'lighting'); conRegVar('light_player_halo', @g_playerLight, 'enable/disable player halo', 'player light halo'); @@ -8066,4 +6640,5 @@ begin conRegVar('r_showlives', @gShowLives, 'show lives', 'show lives'); conRegVar('r_showspect', @gSpectHUD, 'show spectator hud', 'show spectator hud'); conRegVar('r_showstat', @gShowStat, 'show stats', 'show stats'); + conRegVar('r_showpids', @gShowPIDs, 'show PIDs', 'show PIDs'); end.