DEADSOFTWARE

remove scripts
[d2df-sdl.git] / src / game / g_game.pas
1 (* Copyright (C) DooM 2D:Forever Developers
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *)
16 {$MODE DELPHI}
17 unit g_game;
19 interface
21 uses
22 g_basic, g_player, e_graphics, Classes, g_res_downloader,
23 SysUtils, g_sound, g_gui, MAPSTRUCT, wadreader, md5;
25 type
26 TGameSettings = record
27 GameType: Byte;
28 GameMode: Byte;
29 TimeLimit: Word;
30 GoalLimit: Word;
31 WarmupTime: Word;
32 MaxLives: Byte;
33 Options: LongWord;
34 WAD: String;
35 end;
37 TGameEvent = record
38 Name: String;
39 Command: String;
40 end;
42 TDelayedEvent = record
43 Pending: Boolean;
44 Time: LongWord;
45 DEType: Byte;
46 DENum: Integer;
47 DEStr: String;
48 end;
50 TPlayerSettings = record
51 Name: String;
52 Model: String;
53 Color: TRGB;
54 Team: Byte;
55 end;
57 TMegaWADInfo = record
58 Name: String;
59 Description: String;
60 Author: String;
61 Pic: String;
62 end;
64 THearPoint = record
65 Active: Boolean;
66 Coords: TPoint;
67 end;
69 function g_Game_IsNet(): Boolean;
70 function g_Game_IsServer(): Boolean;
71 function g_Game_IsClient(): Boolean;
72 procedure g_Game_Init();
73 procedure g_Game_Free();
74 procedure g_Game_LoadData();
75 procedure g_Game_FreeData();
76 procedure g_Game_Update();
77 procedure g_Game_Draw();
78 procedure g_Game_Quit();
79 procedure g_Game_SetupScreenSize();
80 procedure g_Game_ChangeResolution(newWidth, newHeight: Word; nowFull, nowMax: Boolean);
81 function g_Game_ModeToText(Mode: Byte): string;
82 function g_Game_TextToMode(Mode: string): Byte;
83 procedure g_Game_ExecuteEvent(Name: String);
84 function g_Game_DelayEvent(DEType: Byte; Time: LongWord; Num: Integer = 0; Str: String = ''): Integer;
85 procedure g_Game_AddPlayer(Team: Byte = TEAM_NONE);
86 procedure g_Game_RemovePlayer();
87 procedure g_Game_Spectate();
88 procedure g_Game_SpectateCenterView();
89 procedure g_Game_StartSingle(Map: String; TwoPlayers: Boolean; nPlayers: Byte);
90 procedure g_Game_StartCustom(Map: String; GameMode: Byte; TimeLimit, GoalLimit: Word; MaxLives: Byte; Options: LongWord; nPlayers: Byte);
91 procedure g_Game_StartServer(Map: String; GameMode: Byte; TimeLimit, GoalLimit: Word; MaxLives: Byte; Options: LongWord; nPlayers: Byte; IPAddr: LongWord; Port: Word);
92 procedure g_Game_StartClient(Addr: String; Port: Word; PW: String);
93 procedure g_Game_Restart();
94 procedure g_Game_RestartLevel();
95 procedure g_Game_RestartRound(NoMapRestart: Boolean = False);
96 procedure g_Game_ClientWAD(NewWAD: String; WHash: TMD5Digest);
97 procedure g_Game_SaveOptions();
98 function g_Game_StartMap(Map: String; Force: Boolean = False): Boolean;
99 procedure g_Game_ChangeMap(MapPath: String);
100 procedure g_Game_ExitLevel(Map: Char16);
101 function g_Game_GetFirstMap(WAD: String): String;
102 function g_Game_GetNextMap(): String;
103 procedure g_Game_NextLevel();
104 procedure g_Game_Pause(Enable: Boolean);
105 procedure g_Game_InGameMenu(Show: Boolean);
106 function g_Game_IsWatchedPlayer(UID: Word): Boolean;
107 function g_Game_IsWatchedTeam(Team: Byte): Boolean;
108 procedure g_Game_Message(Msg: String; Time: Word);
109 procedure g_Game_LoadMapList(FileName: String);
110 procedure g_Game_PauseAllSounds(Enable: Boolean);
111 procedure g_Game_StopAllSounds(all: Boolean);
112 procedure g_Game_UpdateTriggerSounds();
113 function g_Game_GetMegaWADInfo(WAD: String): TMegaWADInfo;
114 procedure g_Game_Announce_GoodShot(SpawnerUID: Word);
115 procedure g_Game_Announce_KillCombo(Param: Integer);
116 procedure g_Game_StartVote(Command, Initiator: string);
117 procedure g_Game_CheckVote;
118 procedure g_TakeScreenShot();
119 procedure g_FatalError(Text: String);
120 procedure g_SimpleError(Text: String);
121 function g_Game_IsTestMap(): Boolean;
122 procedure g_Game_DeleteTestMap();
123 procedure GameCVars(P: SArray);
124 procedure GameCommands(P: SArray);
125 procedure GameCheats(P: SArray);
126 procedure DebugCommands(P: SArray);
127 procedure g_Game_Process_Params;
128 procedure g_Game_SetLoadingText(Text: String; Max: Integer; reWrite: Boolean);
129 procedure g_Game_StepLoading();
130 procedure g_Game_ClearLoading();
131 procedure g_Game_SetDebugMode();
132 procedure DrawLoadingStat();
134 { procedure SetWinPause(Enable: Boolean); }
136 const
137 GAME_TICK = 28;
139 LOADING_SHOW_STEP = 100;
140 LOADING_INTERLINE = 20;
142 GT_NONE = 0;
143 GT_SINGLE = 1;
144 GT_CUSTOM = 2;
145 GT_SERVER = 3;
146 GT_CLIENT = 4;
148 GM_NONE = 0;
149 GM_DM = 1;
150 GM_TDM = 2;
151 GM_CTF = 3;
152 GM_COOP = 4;
153 GM_SINGLE = 5;
155 MESSAGE_DIKEY = WM_USER + 1;
157 EXIT_QUIT = 1;
158 EXIT_SIMPLE = 2;
159 EXIT_RESTART = 3;
160 EXIT_ENDLEVELSINGLE = 4;
161 EXIT_ENDLEVELCUSTOM = 5;
163 GAME_OPTION_RESERVED = 1;
164 GAME_OPTION_TEAMDAMAGE = 2;
165 GAME_OPTION_ALLOWEXIT = 4;
166 GAME_OPTION_WEAPONSTAY = 8;
167 GAME_OPTION_MONSTERS = 16;
168 GAME_OPTION_BOTVSPLAYER = 32;
169 GAME_OPTION_BOTVSMONSTER = 64;
171 STATE_NONE = 0;
172 STATE_MENU = 1;
173 STATE_FOLD = 2;
174 STATE_INTERCUSTOM = 3;
175 STATE_INTERSINGLE = 4;
176 STATE_INTERTEXT = 5;
177 STATE_INTERPIC = 6;
178 STATE_ENDPIC = 7;
179 STATE_SLIST = 8;
181 LMS_RESPAWN_NONE = 0;
182 LMS_RESPAWN_WARMUP = 1;
183 LMS_RESPAWN_FINAL = 2;
185 SPECT_NONE = 0;
186 SPECT_STATS = 1;
187 SPECT_MAPVIEW = 2;
188 SPECT_PLAYERS = 3;
190 DE_GLOBEVENT = 0;
191 DE_BFGHIT = 1;
192 DE_KILLCOMBO = 2;
194 ANNOUNCE_NONE = 0;
195 ANNOUNCE_ME = 1;
196 ANNOUNCE_MEPLUS = 2;
197 ANNOUNCE_ALL = 3;
199 CONFIG_FILENAME = 'Doom2DF.cfg';
200 LOG_FILENAME = 'Doom2DF.log';
202 TEST_MAP_NAME = '$$$_TEST_$$$';
204 STD_PLAYER_MODEL = 'Doomer';
206 var
207 gStdFont: DWORD;
208 gGameSettings: TGameSettings;
209 gPlayer1Settings: TPlayerSettings;
210 gPlayer2Settings: TPlayerSettings;
211 gGameOn: Boolean;
212 gPlayerScreenSize: TPoint;
213 gPlayer1ScreenCoord: TPoint;
214 gPlayer2ScreenCoord: TPoint;
215 gPlayer1: TPlayer = nil;
216 gPlayer2: TPlayer = nil;
217 gPlayerDrawn: TPlayer = nil;
218 gTime: LongWord;
219 gSwitchGameMode: Byte = GM_DM;
220 gHearPoint1, gHearPoint2: THearPoint;
221 gSoundEffectsDF: Boolean = False;
222 gSoundTriggerTime: Word = 0;
223 gAnnouncer: Byte = ANNOUNCE_NONE;
224 goodsnd: array[0..3] of TPlayableSound;
225 killsnd: array[0..3] of TPlayableSound;
226 gDefInterTime: ShortInt = -1;
227 gInterEndTime: LongWord = 0;
228 gInterTime: LongWord = 0;
229 gServInterTime: Byte = 0;
230 gGameStartTime: LongWord = 0;
231 gTotalMonsters: Integer = 0;
232 gPause: Boolean;
233 gShowTime: Boolean = True;
234 gShowFPS: Boolean = False;
235 gShowGoals: Boolean = True;
236 gShowStat: Boolean = True;
237 gShowKillMsg: Boolean = True;
238 gShowLives: Boolean = True;
239 gShowPing: Boolean = False;
240 gShowMap: Boolean = False;
241 gExit: Byte = 0;
242 gState: Byte = STATE_NONE;
243 sX, sY: Integer;
244 sWidth, sHeight: Word;
245 gSpectMode: Byte = SPECT_NONE;
246 gSpectHUD: Boolean = True;
247 gSpectKeyPress: Boolean = False;
248 gSpectX: Integer = 0;
249 gSpectY: Integer = 0;
250 gSpectStep: Byte = 8;
251 gSpectViewTwo: Boolean = False;
252 gSpectPID1: Integer = -1;
253 gSpectPID2: Integer = -1;
254 gMusic: TMusic = nil;
255 gLoadGameMode: Boolean;
256 gCheats: Boolean = False;
257 gMapOnce: Boolean = False;
258 gMapToDelete: String;
259 gTempDelete: Boolean = False;
260 gLastMap: Boolean = False;
261 gWinPosX, gWinPosY: Integer;
262 gWinSizeX, gWinSizeY: Integer;
263 gWinFrameX, gWinFrameY, gWinCaption: Integer;
264 gWinActive: Boolean = True; // by default window is active, lol
265 gResolutionChange: Boolean = False;
266 gRC_Width, gRC_Height: Word;
267 gRC_FullScreen, gRC_Maximized: Boolean;
268 gLanguageChange: Boolean = False;
269 gDebugMode: Boolean = False;
270 g_debug_Sounds: Boolean = False;
271 g_debug_Frames: Boolean = False;
272 g_debug_WinMsgs: Boolean = False;
273 g_debug_MonsterOff: Boolean = False;
274 g_debug_BotAIOff: Byte = 0;
275 g_debug_HealthBar: Boolean = False;
276 g_Debug_Player: Boolean = False;
277 gCoopMonstersKilled: Word = 0;
278 gCoopSecretsFound: Word = 0;
279 gCoopTotalMonstersKilled: Word = 0;
280 gCoopTotalSecretsFound: Word = 0;
281 gCoopTotalMonsters: Word = 0;
282 gCoopTotalSecrets: Word = 0;
283 gStatsOff: Boolean = False;
284 gStatsPressed: Boolean = False;
285 gExitByTrigger: Boolean = False;
286 gNextMap: String = '';
287 gLMSRespawn: Byte = LMS_RESPAWN_NONE;
288 gLMSRespawnTime: Cardinal = 0;
289 gLMSSoftSpawn: Boolean = False;
290 gMissionFailed: Boolean = False;
291 gVoteInProgress: Boolean = False;
292 gVotePassed: Boolean = False;
293 gVoteCommand: string = '';
294 gVoteTimer: Cardinal = 0;
295 gVoteCmdTimer: Cardinal = 0;
296 gVoteCount: Integer = 0;
297 gVoteTimeout: Cardinal = 30;
298 gVoted: Boolean = False;
299 gVotesEnabled: Boolean = True;
300 gEvents: Array of TGameEvent;
301 gDelayedEvents: Array of TDelayedEvent;
303 // move button values:
304 // bits 0-1: l/r state:
305 // 0: neither left, nor right pressed
306 // 1: left pressed
307 // 2: right pressed
308 // bits 4-5: l/r state when strafe was pressed
309 P1MoveButton: Byte = 0;
310 P2MoveButton: Byte = 0;
312 implementation
314 uses
315 g_textures, g_main, g_window, g_menu,
316 e_input, e_log, g_console, g_items, g_map,
317 g_playermodel, g_gfx, g_options, g_weapons, Math,
318 g_triggers, MAPDEF, g_monsters, e_sound, CONFIG,
319 BinEditor, g_language, g_net, SDL,
320 ENet, e_fixedbuffer, g_netmsg, g_netmaster, GL, GLExt,
321 utils, sfs;
323 type
324 TEndCustomGameStat = record
325 PlayerStat: TPlayerStatArray;
326 TeamStat: TTeamStat;
327 GameTime: LongWord;
328 GameMode: Byte;
329 Map, MapName: String;
330 end;
332 TEndSingleGameStat = record
333 PlayerStat: Array [0..1] of record
334 Kills: Integer;
335 Secrets: Integer;
336 end;
337 GameTime: LongWord;
338 TwoPlayers: Boolean;
339 TotalSecrets: Integer;
340 end;
342 TLoadingStat = record
343 CurValue: Integer;
344 MaxValue: Integer;
345 ShowCount: Integer;
346 Msgs: Array of String;
347 NextMsg: Word;
348 end;
350 TParamStrValue = record
351 Name: String;
352 Value: String;
353 end;
355 TParamStrValues = Array of TParamStrValue;
357 const
358 INTER_ACTION_TEXT = 1;
359 INTER_ACTION_PIC = 2;
360 INTER_ACTION_MUSIC = 3;
362 var
363 FPS, UPS: Word;
364 FPSCounter, UPSCounter: Word;
365 FPSTime, UPSTime: LongWord;
366 DataLoaded: Boolean = False;
367 LastScreenShot: Int64;
368 IsDrawStat: Boolean = False;
369 CustomStat: TEndCustomGameStat;
370 SingleStat: TEndSingleGameStat;
371 LoadingStat: TLoadingStat;
372 EndingGameCounter: Byte = 0;
373 MessageText: String;
374 MessageTime: Word;
375 MapList: SArray = nil;
376 MapIndex: Integer = -1;
377 MegaWAD: record
378 info: TMegaWADInfo;
379 endpic: String;
380 endmus: String;
381 res: record
382 text: Array of ShortString;
383 anim: Array of ShortString;
384 pic: Array of ShortString;
385 mus: Array of ShortString;
386 end;
387 triggers: Array of record
388 event: ShortString;
389 actions: Array of record
390 action, p1, p2: Integer;
391 end;
392 end;
393 cur_trigger: Integer;
394 cur_action: Integer;
395 end;
396 //InterPic: String;
397 InterText: record
398 lines: SArray;
399 img: String;
400 cur_line: Integer;
401 cur_char: Integer;
402 counter: Integer;
403 endtext: Boolean;
404 end;
406 function Compare(a, b: TPlayerStat): Integer;
407 begin
408 if a.Spectator then Result := 1
409 else if b.Spectator then Result := -1
410 else if a.Frags < b.Frags then Result := 1
411 else if a.Frags > b.Frags then Result := -1
412 else if a.Deaths < b.Deaths then Result := -1
413 else if a.Deaths > b.Deaths then Result := 1
414 else if a.Kills < b.Kills then Result := -1
415 else Result := 1;
416 end;
418 procedure SortGameStat(var stat: TPlayerStatArray);
419 var
420 I, J: Integer;
421 T: TPlayerStat;
422 begin
423 if stat = nil then Exit;
425 for I := High(stat) downto Low(stat) do
426 for J := Low(stat) to High(stat) - 1 do
427 if Compare(stat[J], stat[J + 1]) = 1 then
428 begin
429 T := stat[J];
430 stat[J] := stat[J + 1];
431 stat[J + 1] := T;
432 end;
433 end;
435 function g_Game_ModeToText(Mode: Byte): string;
436 begin
437 Result := '';
438 case Mode of
439 GM_DM: Result := _lc[I_MENU_GAME_TYPE_DM];
440 GM_TDM: Result := _lc[I_MENU_GAME_TYPE_TDM];
441 GM_CTF: Result := _lc[I_MENU_GAME_TYPE_CTF];
442 GM_COOP: Result := _lc[I_MENU_GAME_TYPE_COOP];
443 GM_SINGLE: Result := _lc[I_MENU_GAME_TYPE_SINGLE];
444 end;
445 end;
447 function g_Game_TextToMode(Mode: string): Byte;
448 begin
449 Result := GM_NONE;
450 Mode := UpperCase(Mode);
451 if Mode = _lc[I_MENU_GAME_TYPE_DM] then
452 begin
453 Result := GM_DM;
454 Exit;
455 end;
456 if Mode = _lc[I_MENU_GAME_TYPE_TDM] then
457 begin
458 Result := GM_TDM;
459 Exit;
460 end;
461 if Mode = _lc[I_MENU_GAME_TYPE_CTF] then
462 begin
463 Result := GM_CTF;
464 Exit;
465 end;
466 if Mode = _lc[I_MENU_GAME_TYPE_COOP] then
467 begin
468 Result := GM_COOP;
469 Exit;
470 end;
471 if Mode = _lc[I_MENU_GAME_TYPE_SINGLE] then
472 begin
473 Result := GM_SINGLE;
474 Exit;
475 end;
476 end;
478 function g_Game_IsNet(): Boolean;
479 begin
480 Result := (gGameSettings.GameType in [GT_SERVER, GT_CLIENT]);
481 end;
483 function g_Game_IsServer(): Boolean;
484 begin
485 Result := (gGameSettings.GameType in [GT_SINGLE, GT_CUSTOM, GT_SERVER]);
486 end;
488 function g_Game_IsClient(): Boolean;
489 begin
490 Result := (gGameSettings.GameType = GT_CLIENT);
491 end;
493 function g_Game_GetMegaWADInfo(WAD: String): TMegaWADInfo;
494 var
495 w: TWADFile;
496 cfg: TConfig;
497 p: Pointer;
498 len: Integer;
499 begin
500 Result.name := ExtractFileName(WAD);
501 Result.description := '';
502 Result.author := '';
504 w := TWADFile.Create();
505 w.ReadFile(WAD);
507 if not w.GetResource('INTERSCRIPT', p, len) then
508 begin
509 w.Free();
510 Exit;
511 end;
513 cfg := TConfig.CreateMem(p, len);
514 Result.name := cfg.ReadStr('megawad', 'name', ExtractFileName(WAD));
515 Result.description := cfg.ReadStr('megawad', 'description', '');
516 Result.author := cfg.ReadStr('megawad', 'author', '');
517 Result.pic := cfg.ReadStr('megawad', 'pic', '');
518 cfg.Free();
520 FreeMem(p);
521 end;
523 procedure g_Game_FreeWAD();
524 var
525 a: Integer;
526 begin
527 for a := 0 to High(MegaWAD.res.pic) do
528 if MegaWAD.res.pic[a] <> '' then
529 g_Texture_Delete(MegaWAD.res.pic[a]);
531 for a := 0 to High(MegaWAD.res.mus) do
532 if MegaWAD.res.mus[a] <> '' then
533 g_Sound_Delete(MegaWAD.res.mus[a]);
535 MegaWAD.res.pic := nil;
536 MegaWAD.res.text := nil;
537 MegaWAD.res.anim := nil;
538 MegaWAD.res.mus := nil;
539 MegaWAD.triggers := nil;
541 g_Texture_Delete('TEXTURE_endpic');
542 g_Sound_Delete('MUSIC_endmus');
544 ZeroMemory(@MegaWAD, SizeOf(MegaWAD));
545 gGameSettings.WAD := '';
546 end;
548 procedure g_Game_LoadWAD(WAD: string);
549 var
550 w: TWADFile;
551 cfg: TConfig;
552 p: Pointer;
553 {b, }len: Integer;
554 s: string;
555 begin
556 g_Game_FreeWAD();
557 gGameSettings.WAD := WAD;
558 if not (gGameSettings.GameMode in [GM_COOP, GM_SINGLE]) then
559 Exit;
561 MegaWAD.info := g_Game_GetMegaWADInfo(MapsDir + WAD);
563 w := TWADFile.Create();
564 w.ReadFile(MapsDir + WAD);
566 if not w.GetResource('INTERSCRIPT', p, len) then
567 begin
568 w.Free();
569 Exit;
570 end;
572 cfg := TConfig.CreateMem(p, len);
574 {b := 1;
575 while True do
576 begin
577 s := cfg.ReadStr('pic', 'pic'+IntToStr(b), '');
578 if s = '' then Break;
579 b := b+1;
581 SetLength(MegaWAD.res.pic, Length(MegaWAD.res.pic)+1);
582 MegaWAD.res.pic[High(MegaWAD.res.pic)] := s;
584 g_Texture_CreateWADEx(s, s);
585 end;
587 b := 1;
588 while True do
589 begin
590 s := cfg.ReadStr('mus', 'mus'+IntToStr(b), '');
591 if s = '' then Break;
592 b := b+1;
594 SetLength(MegaWAD.res.mus, Length(MegaWAD.res.mus)+1);
595 MegaWAD.res.mus[High(MegaWAD.res.mus)] := s;
597 g_Music_CreateWADEx(s, s);
598 end;}
600 MegaWAD.endpic := cfg.ReadStr('megawad', 'endpic', '');
601 if MegaWAD.endpic <> '' then
602 begin
603 s := g_ExtractWadName(MegaWAD.endpic);
604 if s = '' then s := MapsDir+WAD else s := GameDir+'/wads/';
605 g_Texture_CreateWADEx('TEXTURE_endpic', s+MegaWAD.endpic);
606 end;
607 MegaWAD.endmus := cfg.ReadStr('megawad', 'endmus', 'Standart.wad:D2DMUS\ÊÎÍÅÖ');
608 if MegaWAD.endmus <> '' then
609 begin
610 s := g_ExtractWadName(MegaWAD.endmus);
611 if s = '' then s := MapsDir+WAD else s := GameDir+'/wads/';
612 g_Sound_CreateWADEx('MUSIC_endmus', s+MegaWAD.endmus, True);
613 end;
615 cfg.Free();
616 FreeMem(p);
617 w.Free();
618 end;
620 {procedure start_trigger(t: string);
621 begin
622 end;
624 function next_trigger(): Boolean;
625 begin
626 end;}
628 procedure DisableCheats();
629 begin
630 MAX_RUNVEL := 8;
631 VEL_JUMP := 10;
632 gFly := False;
634 if gPlayer1 <> nil then gPlayer1.GodMode := False;
635 if gPlayer2 <> nil then gPlayer2.GodMode := False;
636 if gPlayer1 <> nil then gPlayer1.NoTarget := False;
637 if gPlayer2 <> nil then gPlayer2.NoTarget := False;
638 end;
640 procedure g_Game_ExecuteEvent(Name: String);
641 var
642 a: Integer;
643 begin
644 if Name = '' then
645 Exit;
646 if gEvents = nil then
647 Exit;
648 for a := 0 to High(gEvents) do
649 if gEvents[a].Name = Name then
650 begin
651 if gEvents[a].Command <> '' then
652 g_Console_Process(gEvents[a].Command, True);
653 break;
654 end;
655 end;
657 function g_Game_DelayEvent(DEType: Byte; Time: LongWord; Num: Integer = 0; Str: String = ''): Integer;
658 var
659 a, n: Integer;
660 begin
661 n := -1;
662 if gDelayedEvents <> nil then
663 for a := 0 to High(gDelayedEvents) do
664 if not gDelayedEvents[a].Pending then
665 begin
666 n := a;
667 break;
668 end;
669 if n = -1 then
670 begin
671 SetLength(gDelayedEvents, Length(gDelayedEvents) + 1);
672 n := High(gDelayedEvents);
673 end;
674 gDelayedEvents[n].Pending := True;
675 gDelayedEvents[n].DEType := DEType;
676 gDelayedEvents[n].DENum := Num;
677 gDelayedEvents[n].DEStr := Str;
678 if DEType = DE_GLOBEVENT then
679 gDelayedEvents[n].Time := (GetTimer() {div 1000}) + Time
680 else
681 gDelayedEvents[n].Time := gTime + Time;
682 Result := n;
683 end;
685 procedure EndGame();
686 var
687 a: Integer;
688 FileName: string;
689 begin
690 if g_Game_IsNet and g_Game_IsServer then
691 MH_SEND_GameEvent(NET_EV_MAPEND, Byte(gMissionFailed));
693 // Ñòîï èãðà:
694 gPause := False;
695 gGameOn := False;
697 g_Game_StopAllSounds(False);
699 MessageTime := 0;
700 MessageText := '';
702 EndingGameCounter := 0;
703 g_ActiveWindow := nil;
705 gLMSRespawn := LMS_RESPAWN_NONE;
706 gLMSRespawnTime := 0;
708 case gExit of
709 EXIT_SIMPLE: // Âûõîä ÷åðåç ìåíþ èëè êîíåö òåñòà
710 begin
711 g_Game_Free();
713 if gMapOnce then
714 begin // Ýòî áûë òåñò
715 g_Game_Quit();
716 end
717 else
718 begin // Âûõîä â ãëàâíîå ìåíþ
719 gMusic.SetByName('MUSIC_MENU');
720 gMusic.Play();
721 if gState <> STATE_SLIST then
722 begin
723 g_GUI_ShowWindow('MainMenu');
724 gState := STATE_MENU;
725 end else
726 begin
727 // Îáíîâëÿåì ñïèñîê ñåðâåðîâ
728 slReturnPressed := True;
729 if g_Net_Slist_Fetch(slCurrent) then
730 begin
731 if slCurrent = nil then
732 slWaitStr := _lc[I_NET_SLIST_NOSERVERS];
733 end
734 else
735 slWaitStr := _lc[I_NET_SLIST_ERROR];
736 end;
738 g_Game_ExecuteEvent('ongameend');
739 end;
740 end;
742 EXIT_RESTART: // Íà÷àòü óðîâåíü ñíà÷àëà
743 begin
744 if not g_Game_IsClient then g_Game_Restart();
745 end;
747 EXIT_ENDLEVELCUSTOM: // Çàêîí÷èëñÿ óðîâåíü â Ñâîåé èãðå
748 begin
749 // Ñòàòèñòèêà Ñâîåé èãðû:
750 FileName := g_ExtractWadName(gMapInfo.Map);
752 CustomStat.GameTime := gTime;
753 CustomStat.Map := ExtractFileName(FileName)+':'+g_ExtractFileName(gMapInfo.Map); //ResName;
754 CustomStat.MapName := gMapInfo.Name;
755 CustomStat.GameMode := gGameSettings.GameMode;
756 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
757 CustomStat.TeamStat := gTeamStat;
759 CustomStat.PlayerStat := nil;
761 // Ñòàòèñòèêà èãðîêîâ:
762 if gPlayers <> nil then
763 begin
764 for a := 0 to High(gPlayers) do
765 if gPlayers[a] <> nil then
766 begin
767 SetLength(CustomStat.PlayerStat, Length(CustomStat.PlayerStat)+1);
768 with CustomStat.PlayerStat[High(CustomStat.PlayerStat)] do
769 begin
770 Name := gPlayers[a].Name;
771 Frags := gPlayers[a].Frags;
772 Deaths := gPlayers[a].Death;
773 Kills := gPlayers[a].Kills;
774 Team := gPlayers[a].Team;
775 Color := gPlayers[a].Model.Color;
776 Spectator := gPlayers[a].FSpectator;
777 end;
778 end;
780 SortGameStat(CustomStat.PlayerStat);
781 end;
783 g_Game_ExecuteEvent('onmapend');
785 // Çàòóõàþùèé ýêðàí:
786 EndingGameCounter := 255;
787 gState := STATE_FOLD;
788 gInterTime := 0;
789 if gDefInterTime < 0 then
790 gInterEndTime := IfThen((gGameSettings.GameType = GT_SERVER) and (gPlayer1 = nil), 15000, 25000)
791 else
792 gInterEndTime := gDefInterTime * 1000;
793 end;
795 EXIT_ENDLEVELSINGLE: // Çàêîí÷èëñÿ óðîâåíü â Îäèíî÷íîé èãðå
796 begin
797 // Ñòàòèñòèêà Îäèíî÷íîé èãðû:
798 SingleStat.GameTime := gTime;
799 SingleStat.TwoPlayers := gPlayer2 <> nil;
800 SingleStat.TotalSecrets := gSecretsCount;
801 // Ñòàòèñòèêà ïåðâîãî èãðîêà:
802 SingleStat.PlayerStat[0].Kills := gPlayer1.MonsterKills;
803 SingleStat.PlayerStat[0].Secrets := gPlayer1.Secrets;
804 // Ñòàòèñòèêà âòîðîãî èãðîêà (åñëè åñòü):
805 if SingleStat.TwoPlayers then
806 begin
807 SingleStat.PlayerStat[1].Kills := gPlayer2.MonsterKills;
808 SingleStat.PlayerStat[1].Secrets := gPlayer2.Secrets;
809 end;
811 g_Game_ExecuteEvent('onmapend');
813 // Åñòü åùå êàðòû:
814 if gNextMap <> '' then
815 begin
816 gMusic.SetByName('MUSIC_INTERMUS');
817 gMusic.Play();
818 gState := STATE_INTERSINGLE;
820 g_Game_ExecuteEvent('oninter');
821 end
822 else // Áîëüøå íåò êàðò
823 begin
824 // Çàòóõàþùèé ýêðàí:
825 EndingGameCounter := 255;
826 gState := STATE_FOLD;
827 end;
828 end;
829 end;
831 // Îêîí÷àíèå îáðàáîòàíî:
832 if gExit <> EXIT_QUIT then
833 gExit := 0;
834 end;
836 procedure DrawStat();
837 var
838 pc, x, y, w, h: Integer;
839 w1, w2, w3, w4: Integer;
840 a, aa: Integer;
841 cw, ch, r, g, b, rr, gg, bb: Byte;
842 s1, s2, s3: String;
843 _y: Integer;
844 stat: TPlayerStatArray;
845 wad, map: string;
846 mapstr: string;
847 begin
848 s1 := '';
849 s2 := '';
850 s3 := '';
851 pc := g_Player_GetCount;
852 e_TextureFontGetSize(gStdFont, cw, ch);
854 w := gScreenWidth-(gScreenWidth div 5);
855 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
856 h := 32+ch*(11+pc)
857 else
858 h := 40+ch*5+(ch+8)*pc;
859 x := (gScreenWidth div 2)-(w div 2);
860 y := (gScreenHeight div 2)-(h div 2);
862 e_DrawFillQuad(x, y, x+w-1, y+h-1, 64, 64, 64, 32);
863 e_DrawQuad(x, y, x+w-1, y+h-1, 255, 127, 0);
865 wad := g_ExtractWadNameNoPath(gMapInfo.Map);
866 map := g_ExtractFileName(gMapInfo.Map);
867 mapstr := wad + ':\' + map + ' - ' + gMapInfo.Name;
869 case gGameSettings.GameMode of
870 GM_DM:
871 begin
872 if gGameSettings.MaxLives = 0 then
873 s1 := _lc[I_GAME_DM]
874 else
875 s1 := _lc[I_GAME_LMS];
876 s2 := Format(_lc[I_GAME_FRAG_LIMIT], [gGameSettings.GoalLimit]);
877 s3 := Format(_lc[I_GAME_TIME_LIMIT], [gGameSettings.TimeLimit div 3600, (gGameSettings.TimeLimit div 60) mod 60, gGameSettings.TimeLimit mod 60]);
878 end;
880 GM_TDM:
881 begin
882 if gGameSettings.MaxLives = 0 then
883 s1 := _lc[I_GAME_TDM]
884 else
885 s1 := _lc[I_GAME_TLMS];
886 s2 := Format(_lc[I_GAME_FRAG_LIMIT], [gGameSettings.GoalLimit]);
887 s3 := Format(_lc[I_GAME_TIME_LIMIT], [gGameSettings.TimeLimit div 3600, (gGameSettings.TimeLimit div 60) mod 60, gGameSettings.TimeLimit mod 60]);
888 end;
890 GM_CTF:
891 begin
892 s1 := _lc[I_GAME_CTF];
893 s2 := Format(_lc[I_GAME_SCORE_LIMIT], [gGameSettings.GoalLimit]);
894 s3 := Format(_lc[I_GAME_TIME_LIMIT], [gGameSettings.TimeLimit div 3600, (gGameSettings.TimeLimit div 60) mod 60, gGameSettings.TimeLimit mod 60]);
895 end;
897 GM_COOP:
898 begin
899 if gGameSettings.MaxLives = 0 then
900 s1 := _lc[I_GAME_COOP]
901 else
902 s1 := _lc[I_GAME_SURV];
903 s2 := _lc[I_GAME_MONSTERS] + ' ' + IntToStr(gCoopMonstersKilled) + '/' + IntToStr(gTotalMonsters);
904 s3 := _lc[I_GAME_SECRETS] + ' ' + IntToStr(gCoopSecretsFound) + '/' + IntToStr(gSecretsCount);
905 end;
907 else
908 begin
909 s1 := '';
910 s2 := '';
911 end;
912 end;
914 _y := y+8;
915 e_TextureFontPrintEx(x+(w div 2)-(Length(s1)*cw div 2), _y, s1, gStdFont, 255, 255, 255, 1);
916 _y := _y+ch+8;
917 e_TextureFontPrintEx(x+(w div 2)-(Length(mapstr)*cw div 2), _y, mapstr, gStdFont, 200, 200, 200, 1);
918 _y := _y+ch+8;
919 e_TextureFontPrintEx(x+16, _y, s2, gStdFont, 200, 200, 200, 1);
921 e_TextureFontPrintEx(x+w-16-(Length(s3))*cw, _y, s3,
922 gStdFont, 200, 200, 200, 1);
924 if NetMode = NET_SERVER then
925 e_TextureFontPrintEx(x+8, y + 8, _lc[I_NET_SERVER], gStdFont, 255, 255, 255, 1)
926 else
927 if NetMode = NET_CLIENT then
928 e_TextureFontPrintEx(x+8, y + 8,
929 NetClientIP + ':' + IntToStr(NetClientPort), gStdFont, 255, 255, 255, 1);
931 if pc = 0 then
932 Exit;
933 stat := g_Player_GetStats();
934 SortGameStat(stat);
936 w2 := (w-16) div 6 + 48; // øèðèíà 2 ñòîëáöà
937 w3 := (w-16) div 6; // øèðèíà 3 è 4 ñòîëáöîâ
938 w4 := w3;
939 w1 := w-16-w2-w3-w4; // îñòàâøååñÿ ïðîñòðàíñòâî - äëÿ öâåòà è èìåíè èãðîêà
941 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
942 begin
943 _y := _y+ch+ch;
945 for a := TEAM_RED to TEAM_BLUE do
946 begin
947 if a = TEAM_RED then
948 begin
949 s1 := _lc[I_GAME_TEAM_RED];
950 r := 255;
951 g := 0;
952 b := 0;
953 end
954 else
955 begin
956 s1 := _lc[I_GAME_TEAM_BLUE];
957 r := 0;
958 g := 0;
959 b := 255;
960 end;
962 e_TextureFontPrintEx(x+16, _y, s1, gStdFont, r, g, b, 1);
963 e_TextureFontPrintEx(x+w1+16, _y, IntToStr(gTeamStat[a].Goals),
964 gStdFont, r, g, b, 1);
966 _y := _y+ch+(ch div 4);
967 e_DrawLine(1, x+16, _y, x+w-16, _y, r, g, b);
968 _y := _y+(ch div 4);
970 for aa := 0 to High(stat) do
971 if stat[aa].Team = a then
972 with stat[aa] do
973 begin
974 if Spectator then
975 begin
976 rr := r div 2;
977 gg := g div 2;
978 bb := b div 2;
979 end
980 else
981 begin
982 rr := r;
983 gg := g;
984 bb := b;
985 end;
986 // Èìÿ
987 e_TextureFontPrintEx(x+16, _y, Name, gStdFont, rr, gg, bb, 1);
988 // Ïèíã/ïîòåðè
989 e_TextureFontPrintEx(x+w1+16, _y, Format(_lc[I_GAME_PING_MS], [Ping, Loss]), gStdFont, rr, gg, bb, 1);
990 // Ôðàãè
991 e_TextureFontPrintEx(x+w1+w2+16, _y, IntToStr(Frags), gStdFont, rr, gg, bb, 1);
992 // Ñìåðòè
993 e_TextureFontPrintEx(x+w1+w2+w3+16, _y, IntToStr(Deaths), gStdFont, rr, gg, bb, 1);
994 _y := _y+ch;
995 end;
997 _y := _y+ch;
998 end;
999 end
1000 else if gGameSettings.GameMode in [GM_DM, GM_COOP] then
1001 begin
1002 _y := _y+ch+ch;
1003 e_TextureFontPrintEx(x+16, _y, _lc[I_GAME_PLAYER_NAME], gStdFont, 255, 127, 0, 1);
1004 e_TextureFontPrintEx(x+16+w1, _y, _lc[I_GAME_PING], gStdFont, 255, 127, 0, 1);
1005 e_TextureFontPrintEx(x+16+w1+w2, _y, _lc[I_GAME_FRAGS], gStdFont, 255, 127, 0, 1);
1006 e_TextureFontPrintEx(x+16+w1+w2+w3, _y, _lc[I_GAME_DEATHS], gStdFont, 255, 127, 0, 1);
1008 _y := _y+ch+8;
1009 for aa := 0 to High(stat) do
1010 with stat[aa] do
1011 begin
1012 if Spectator then
1013 begin
1014 r := 127;
1015 g := 64;
1016 end
1017 else
1018 begin
1019 r := 255;
1020 g := 127;
1021 end;
1022 // Öâåò èãðîêà
1023 e_DrawFillQuad(x+16, _y+4, x+32-1, _y+16+4-1, Color.R, Color.G, Color.B, 0);
1024 e_DrawQuad(x+16, _y+4, x+32-1, _y+16+4-1, 192, 192, 192);
1025 // Èìÿ
1026 e_TextureFontPrintEx(x+16+16+8, _y+4, Name, gStdFont, r, g, 0, 1);
1027 // Ïèíã/ïîòåðè
1028 e_TextureFontPrintEx(x+w1+16, _y+4, Format(_lc[I_GAME_PING_MS], [Ping, Loss]), gStdFont, r, g, 0, 1);
1029 // Ôðàãè
1030 e_TextureFontPrintEx(x+w1+w2+16, _y+4, IntToStr(Frags), gStdFont, r, g, 0, 1);
1031 // Ñìåðòè
1032 e_TextureFontPrintEx(x+w1+w2+w3+16, _y+4, IntToStr(Deaths), gStdFont, r, g, 0, 1);
1033 _y := _y+ch+8;
1034 end;
1035 end
1036 end;
1038 procedure g_Game_Init();
1039 var
1040 SR: TSearchRec;
1041 begin
1042 gExit := 0;
1043 gMapToDelete := '';
1044 gTempDelete := False;
1046 sfsGCDisable(); // temporary disable removing of temporary volumes
1048 try
1049 g_Texture_CreateWADEx('MENU_BACKGROUND', GameWAD+':TEXTURES\TITLE');
1050 g_Texture_CreateWADEx('INTER', GameWAD+':TEXTURES\INTER');
1051 g_Texture_CreateWADEx('ENDGAME_EN', GameWAD+':TEXTURES\ENDGAME_EN');
1052 g_Texture_CreateWADEx('ENDGAME_RU', GameWAD+':TEXTURES\ENDGAME_RU');
1054 LoadStdFont('STDTXT', 'STDFONT', gStdFont);
1055 LoadFont('MENUTXT', 'MENUFONT', gMenuFont);
1056 LoadFont('SMALLTXT', 'SMALLFONT', gMenuSmallFont);
1058 g_Game_ClearLoading();
1059 g_Game_SetLoadingText(Format('Doom 2D: Forever %s', [GAME_VERSION]), 0, False);
1060 g_Game_SetLoadingText('', 0, False);
1062 g_Game_SetLoadingText(_lc[I_LOAD_CONSOLE], 0, False);
1063 g_Console_Init();
1065 g_Game_SetLoadingText(_lc[I_LOAD_MODELS], 0, False);
1066 g_PlayerModel_LoadData();
1068 if FindFirst(ModelsDir+'*.wad', faAnyFile, SR) = 0 then
1069 repeat
1070 if not g_PlayerModel_Load(ModelsDir+SR.Name) then
1071 e_WriteLog(Format('Error loading model %s', [SR.Name]), MSG_WARNING);
1072 until FindNext(SR) <> 0;
1073 FindClose(SR);
1075 if FindFirst(ModelsDir+'*.pk3', faAnyFile, SR) = 0 then
1076 repeat
1077 if not g_PlayerModel_Load(ModelsDir+SR.Name) then
1078 e_WriteLog(Format('Error loading model %s', [SR.Name]), MSG_WARNING);
1079 until FindNext(SR) <> 0;
1080 FindClose(SR);
1082 if FindFirst(ModelsDir+'*.zip', faAnyFile, SR) = 0 then
1083 repeat
1084 if not g_PlayerModel_Load(ModelsDir+SR.Name) then
1085 e_WriteLog(Format('Error loading model %s', [SR.Name]), MSG_WARNING);
1086 until FindNext(SR) <> 0;
1087 FindClose(SR);
1089 gGameOn := False;
1090 gPause := False;
1091 gTime := 0;
1092 LastScreenShot := 0;
1094 {e_MouseInfo.Accel := 1.0;}
1096 g_Game_SetLoadingText(_lc[I_LOAD_GAME_DATA], 0, False);
1097 g_Game_LoadData();
1099 g_Game_SetLoadingText(_lc[I_LOAD_MUSIC], 0, False);
1100 g_Sound_CreateWADEx('MUSIC_INTERMUS', GameWAD+':MUSIC\INTERMUS', True);
1101 g_Sound_CreateWADEx('MUSIC_MENU', GameWAD+':MUSIC\MENU', True);
1102 g_Sound_CreateWADEx('MUSIC_ROUNDMUS', GameWAD+':MUSIC\ROUNDMUS', True);
1103 g_Sound_CreateWADEx('MUSIC_STDENDMUS', GameWAD+':MUSIC\ENDMUS', True);
1105 g_Game_SetLoadingText(_lc[I_LOAD_MENUS], 0, False);
1106 g_Menu_Init();
1108 gMusic := TMusic.Create();
1109 gMusic.SetByName('MUSIC_MENU');
1110 gMusic.Play();
1112 gGameSettings.WarmupTime := 30;
1114 gState := STATE_MENU;
1116 SetLength(gEvents, 6);
1117 gEvents[0].Name := 'ongamestart';
1118 gEvents[1].Name := 'ongameend';
1119 gEvents[2].Name := 'onmapstart';
1120 gEvents[3].Name := 'onmapend';
1121 gEvents[4].Name := 'oninter';
1122 gEvents[5].Name := 'onwadend';
1123 finally
1124 sfsGCEnable(); // enable releasing unused volumes
1125 end;
1126 end;
1128 procedure g_Game_Free();
1129 begin
1130 if NetMode = NET_CLIENT then g_Net_Disconnect();
1131 if NetMode = NET_SERVER then g_Net_Host_Die();
1133 g_Map_Free();
1134 g_Player_Free();
1135 g_Player_RemoveAllCorpses();
1137 gGameSettings.GameType := GT_NONE;
1138 if gGameSettings.GameMode = GM_SINGLE then
1139 gGameSettings.GameMode := GM_DM;
1140 gSwitchGameMode := gGameSettings.GameMode;
1142 gChatShow := False;
1143 gExitByTrigger := False;
1144 end;
1146 function IsActivePlayer(p: TPlayer): Boolean;
1147 begin
1148 Result := False;
1149 if p = nil then
1150 Exit;
1151 Result := (not p.FDummy) and (not p.FSpectator);
1152 end;
1154 function GetActivePlayer_ByID(ID: Integer): TPlayer;
1155 var
1156 a: Integer;
1157 begin
1158 Result := nil;
1159 if ID < 0 then
1160 Exit;
1161 if gPlayers = nil then
1162 Exit;
1163 for a := Low(gPlayers) to High(gPlayers) do
1164 if IsActivePlayer(gPlayers[a]) then
1165 begin
1166 if gPlayers[a].UID <> ID then
1167 continue;
1168 Result := gPlayers[a];
1169 break;
1170 end;
1171 end;
1173 function GetActivePlayerID_Next(Skip: Integer = -1): Integer;
1174 var
1175 a, idx: Integer;
1176 ids: Array of Word;
1177 begin
1178 Result := -1;
1179 if gPlayers = nil then
1180 Exit;
1181 SetLength(ids, 0);
1182 idx := -1;
1183 for a := Low(gPlayers) to High(gPlayers) do
1184 if IsActivePlayer(gPlayers[a]) then
1185 begin
1186 SetLength(ids, Length(ids) + 1);
1187 ids[High(ids)] := gPlayers[a].UID;
1188 if gPlayers[a].UID = Skip then
1189 idx := High(ids);
1190 end;
1191 if Length(ids) = 0 then
1192 Exit;
1193 if idx = -1 then
1194 Result := ids[0]
1195 else
1196 Result := ids[(idx + 1) mod Length(ids)];
1197 end;
1199 function GetActivePlayerID_Prev(Skip: Integer = -1): Integer;
1200 var
1201 a, idx: Integer;
1202 ids: Array of Word;
1203 begin
1204 Result := -1;
1205 if gPlayers = nil then
1206 Exit;
1207 SetLength(ids, 0);
1208 idx := -1;
1209 for a := Low(gPlayers) to High(gPlayers) do
1210 if IsActivePlayer(gPlayers[a]) then
1211 begin
1212 SetLength(ids, Length(ids) + 1);
1213 ids[High(ids)] := gPlayers[a].UID;
1214 if gPlayers[a].UID = Skip then
1215 idx := High(ids);
1216 end;
1217 if Length(ids) = 0 then
1218 Exit;
1219 if idx = -1 then
1220 Result := ids[Length(ids) - 1]
1221 else
1222 Result := ids[(Length(ids) - 1 + idx) mod Length(ids)];
1223 end;
1225 function isKeyPressed (key1: Word; key2: Word): Boolean;
1226 begin
1227 if (key1 <> 0) and e_KeyPressed(key1) then begin result := true; exit; end;
1228 if (key2 <> 0) and e_KeyPressed(key2) then begin result := true; exit; end;
1229 result := false;
1230 end;
1232 procedure processPlayerControls (plr: TPlayer; var ctrl: TPlayerControl; var MoveButton: Byte; p2hack: Boolean=false);
1233 var
1234 time: Word;
1235 strafeDir: Byte;
1236 begin
1237 if (plr = nil) then exit;
1238 if (p2hack) then time := 1000 else time := 1;
1239 strafeDir := MoveButton shr 4;
1240 MoveButton := MoveButton and $0F;
1241 with ctrl do
1242 begin
1243 if isKeyPressed(KeyLeft, KeyLeft2) and (not isKeyPressed(KeyRight, KeyRight2)) then MoveButton := 1 // Íàæàòà òîëüêî "Âëåâî"
1244 else if (not isKeyPressed(KeyLeft, KeyLeft2)) and isKeyPressed(KeyRight, KeyRight2) then MoveButton := 2 // Íàæàòà òîëüêî "Âïðàâî"
1245 else if (not isKeyPressed(KeyLeft, KeyLeft2)) and (not isKeyPressed(KeyRight, KeyRight2)) then MoveButton := 0; // Íå íàæàòû íè "Âëåâî", íè "Âïðàâî"
1247 // Ñåé÷àñ èëè ðàíüøå áûëè íàæàòû "Âëåâî"/"Âïðàâî" => ïåðåäàåì èãðîêó:
1248 if MoveButton = 1 then plr.PressKey(KEY_LEFT, time)
1249 else if MoveButton = 2 then plr.PressKey(KEY_RIGHT, time);
1251 // if we have "strafe" key, turn off old strafe mechanics
1252 if isKeyPressed(KeyStrafe, KeyStrafe2) then
1253 begin
1254 // new strafe mechanics
1255 if (strafeDir = 0) then strafeDir := MoveButton; // start strafing
1256 // now set direction according to strafe (reversed)
1257 if (strafeDir = 2) then plr.SetDirection(D_LEFT)
1258 else if (strafeDir = 1) then plr.SetDirection(D_RIGHT);
1259 end
1260 else
1261 begin
1262 strafeDir := 0; // not strafing anymore
1263 // Ðàíüøå áûëà íàæàòà "Âïðàâî", à ñåé÷àñ "Âëåâî" => áåæèì âïðàâî, ñìîòðèì âëåâî:
1264 if (MoveButton = 2) and isKeyPressed(KeyLeft, KeyLeft2) then plr.SetDirection(D_LEFT)
1265 // Ðàíüøå áûëà íàæàòà "Âëåâî", à ñåé÷àñ "Âïðàâî" => áåæèì âëåâî, ñìîòðèì âïðàâî:
1266 else if (MoveButton = 1) and isKeyPressed(KeyRight, KeyRight2) then plr.SetDirection(D_RIGHT)
1267 // ×òî-òî áûëî íàæàòî è íå èçìåíèëîñü => êóäà áåæèì, òóäà è ñìîòðèì:
1268 else if MoveButton <> 0 then plr.SetDirection(TDirection(MoveButton-1));
1269 end;
1271 // fix movebutton state
1272 MoveButton := MoveButton or (strafeDir shl 4);
1274 // Îñòàëüíûå êëàâèøè:
1275 if isKeyPressed(KeyJump, KeyJump2) then plr.PressKey(KEY_JUMP, time);
1276 if isKeyPressed(KeyUp, KeyUp2) then plr.PressKey(KEY_UP, time);
1277 if isKeyPressed(KeyDown, KeyDown2) then plr.PressKey(KEY_DOWN, time);
1278 if isKeyPressed(KeyFire, KeyFire2) then plr.PressKey(KEY_FIRE);
1279 if isKeyPressed(KeyNextWeapon, KeyNextWeapon2) then plr.PressKey(KEY_NEXTWEAPON);
1280 if isKeyPressed(KeyPrevWeapon, KeyPrevWeapon2) then plr.PressKey(KEY_PREVWEAPON);
1281 if isKeyPressed(KeyOpen, KeyOpen2) then plr.PressKey(KEY_OPEN);
1282 end;
1283 end;
1285 procedure g_Game_Update();
1286 var
1287 Msg: g_gui.TMessage;
1288 Time: Int64;
1289 a: Byte;
1290 w: Word;
1291 i, b: Integer;
1292 begin
1293 // Ïîðà âûêëþ÷àòü èãðó:
1294 if gExit = EXIT_QUIT then
1295 Exit;
1296 // Èãðà çàêîí÷èëàñü - îáðàáàòûâàåì:
1297 if gExit <> 0 then
1298 begin
1299 EndGame();
1300 if gExit = EXIT_QUIT then
1301 Exit;
1302 end;
1304 // ×èòàåì êëàâèàòóðó è äæîéñòèê, åñëè îêíî àêòèâíî:
1305 e_PollInput();
1307 // Îáíîâëÿåì êîíñîëü (äâèæåíèå è ñîîáùåíèÿ):
1308 g_Console_Update();
1310 if (NetMode = NET_NONE) and (g_Game_IsNet) and (gGameOn or (gState in [STATE_FOLD, STATE_INTERCUSTOM])) then
1311 begin
1312 gExit := EXIT_SIMPLE;
1313 EndGame();
1314 Exit;
1315 end;
1317 case gState of
1318 STATE_INTERSINGLE, // Ñòàòèñòêà ïîñëå ïðîõîæäåíèÿ óðîâíÿ â Îäèíî÷íîé èãðå
1319 STATE_INTERCUSTOM, // Ñòàòèñòêà ïîñëå ïðîõîæäåíèÿ óðîâíÿ â Ñâîåé èãðå
1320 STATE_INTERTEXT, // Òåêñò ìåæäó óðîâíÿìè
1321 STATE_INTERPIC: // Êàðòèíêà ìåæäó óðîâíÿìè
1322 begin
1323 if g_Game_IsNet and g_Game_IsServer then
1324 begin
1325 gInterTime := gInterTime + GAME_TICK;
1326 a := Min((gInterEndTime - gInterTime) div 1000 + 1, 255);
1327 if a <> gServInterTime then
1328 begin
1329 gServInterTime := a;
1330 MH_SEND_TimeSync(gServInterTime);
1331 end;
1332 end;
1334 if (not g_Game_IsClient) and
1337 (e_KeyPressed(IK_RETURN) or e_KeyPressed(IK_KPRETURN) or e_KeyPressed(IK_SPACE))
1338 and (not gJustChatted) and (not gConsoleShow) and (not gChatShow)
1339 and (g_ActiveWindow = nil)
1341 or (g_Game_IsNet and (gInterTime > gInterEndTime))
1343 then
1344 begin // Íàæàëè <Enter>/<Ïðîáåë> èëè ïðîøëî äîñòàòî÷íî âðåìåíè:
1345 g_Game_StopAllSounds(True);
1347 if gMapOnce then // Ýòî áûë òåñò
1348 gExit := EXIT_SIMPLE
1349 else
1350 if gNextMap <> '' then // Ïåðåõîäèì íà ñëåäóþùóþ êàðòó
1351 g_Game_ChangeMap(gNextMap)
1352 else // Ñëåäóþùåé êàðòû íåò
1353 begin
1354 if gGameSettings.GameType in [GT_CUSTOM, GT_SERVER] then
1355 begin
1356 // Âûõîä â ãëàâíîå ìåíþ:
1357 g_Game_Free;
1358 g_GUI_ShowWindow('MainMenu');
1359 gMusic.SetByName('MUSIC_MENU');
1360 gMusic.Play();
1361 gState := STATE_MENU;
1362 end else
1363 begin
1364 // Ôèíàëüíàÿ êàðòèíêà:
1365 g_Game_ExecuteEvent('onwadend');
1366 g_Game_Free();
1367 if not gMusic.SetByName('MUSIC_endmus') then
1368 gMusic.SetByName('MUSIC_STDENDMUS');
1369 gMusic.Play();
1370 gState := STATE_ENDPIC;
1371 end;
1372 g_Game_ExecuteEvent('ongameend');
1373 end;
1375 Exit;
1376 end;
1378 if gState = STATE_INTERTEXT then
1379 if InterText.counter > 0 then
1380 InterText.counter := InterText.counter - 1;
1381 end;
1383 STATE_FOLD: // Çàòóõàíèå ýêðàíà
1384 begin
1385 if EndingGameCounter = 0 then
1386 begin
1387 // Çàêîí÷èëñÿ óðîâåíü â Ñâîåé èãðå:
1388 if gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT] then
1389 begin
1390 if gLastMap and (gGameSettings.GameMode = GM_COOP) then
1391 begin
1392 g_Game_ExecuteEvent('onwadend');
1393 if not gMusic.SetByName('MUSIC_endmus') then
1394 gMusic.SetByName('MUSIC_STDENDMUS');
1395 end
1396 else
1397 gMusic.SetByName('MUSIC_ROUNDMUS');
1399 gMusic.Play();
1400 gState := STATE_INTERCUSTOM;
1401 end
1402 else // Çàêîí÷èëàñü ïîñëåäíÿÿ êàðòà â Îäèíî÷íîé èãðå
1403 begin
1404 gMusic.SetByName('MUSIC_INTERMUS');
1405 gMusic.Play();
1406 gState := STATE_INTERSINGLE;
1407 end;
1408 g_Game_ExecuteEvent('oninter');
1409 end
1410 else
1411 DecMin(EndingGameCounter, 6, 0);
1412 end;
1414 STATE_ENDPIC: // Êàðòèíêà îêîí÷àíèÿ ìåãàÂàäà
1415 begin
1416 if gMapOnce then // Ýòî áûë òåñò
1417 begin
1418 gExit := EXIT_SIMPLE;
1419 Exit;
1420 end;
1421 end;
1423 STATE_SLIST:
1424 g_Serverlist_Control(slCurrent);
1425 end;
1427 if g_Game_IsNet then
1428 if not gConsoleShow then
1429 if not gChatShow then
1430 begin
1431 if g_ActiveWindow = nil then
1432 begin
1433 if e_KeyPressed(gGameControls.GameControls.Chat) then
1434 g_Console_Chat_Switch(False)
1435 else if (e_KeyPressed(gGameControls.GameControls.TeamChat)) and
1436 (gGameSettings.GameMode in [GM_TDM, GM_CTF]) then
1437 g_Console_Chat_Switch(True);
1438 end;
1439 end else
1440 if not gChatEnter then
1441 if (not e_KeyPressed(gGameControls.GameControls.Chat))
1442 and (not e_KeyPressed(gGameControls.GameControls.TeamChat)) then
1443 gChatEnter := True;
1445 // Ñòàòèñòèêà ïî Tab:
1446 if gGameOn then
1447 IsDrawStat := (not gConsoleShow) and (not gChatShow) and
1448 (gGameSettings.GameType <> GT_SINGLE) and
1449 e_KeyPressed(gGameControls.GameControls.Stat);
1451 // Èãðà èäåò:
1452 if gGameOn and not gPause and (gState <> STATE_FOLD) then
1453 begin
1454 // Âðåìÿ += 28 ìèëëèñåêóíä:
1455 gTime := gTime + GAME_TICK;
1457 // Ñîîáùåíèå ïîñåðåäèíå ýêðàíà:
1458 if MessageTime = 0 then
1459 MessageText := '';
1460 if MessageTime > 0 then
1461 MessageTime := MessageTime - 1;
1463 if (g_Game_IsServer) then
1464 begin
1465 // Áûë çàäàí ëèìèò âðåìåíè:
1466 if (gGameSettings.TimeLimit > 0) then
1467 if (gTime - gGameStartTime) div 1000 >= gGameSettings.TimeLimit then
1468 begin // Îí ïðîøåë => êîíåö óðîâíÿ
1469 g_Game_NextLevel();
1470 Exit;
1471 end;
1473 // Íàäî ðåñïàâíèòü èãðîêîâ â LMS:
1474 if (gLMSRespawn > LMS_RESPAWN_NONE) and (gLMSRespawnTime < gTime) then
1475 g_Game_RestartRound(gLMSSoftSpawn);
1477 // Ïðîâåðèì ðåçóëüòàò ãîëîñîâàíèÿ, åñëè âðåìÿ ïðîøëî
1478 if gVoteInProgress and (gVoteTimer < gTime) then
1479 g_Game_CheckVote
1480 else if gVotePassed and (gVoteCmdTimer < gTime) then
1481 begin
1482 g_Console_Process(gVoteCommand);
1483 gVoteCommand := '';
1484 gVotePassed := False;
1485 end;
1487 // Çàìåðÿåì âðåìÿ çàõâàòà ôëàãîâ
1488 if gFlags[FLAG_RED].State = FLAG_STATE_CAPTURED then
1489 gFlags[FLAG_RED].CaptureTime := gFlags[FLAG_RED].CaptureTime + GAME_TICK;
1490 if gFlags[FLAG_BLUE].State = FLAG_STATE_CAPTURED then
1491 gFlags[FLAG_BLUE].CaptureTime := gFlags[FLAG_BLUE].CaptureTime + GAME_TICK;
1493 // Áûë çàäàí ëèìèò ïîáåä:
1494 if (gGameSettings.GoalLimit > 0) then
1495 begin
1496 b := 0;
1498 if gGameSettings.GameMode = GM_DM then
1499 begin // Â DM èùåì èãðîêà ñ max ôðàãàìè
1500 for i := 0 to High(gPlayers) do
1501 if gPlayers[i] <> nil then
1502 if gPlayers[i].Frags > b then
1503 b := gPlayers[i].Frags;
1504 end
1505 else
1506 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
1507 begin //  CTF/TDM âûáèðàåì êîìàíäó ñ íàèáîëüøèì ñ÷åòîì
1508 b := Max(gTeamStat[TEAM_RED].Goals, gTeamStat[TEAM_BLUE].Goals);
1509 end;
1511 // Ëèìèò ïîáåä íàáðàí => êîíåö óðîâíÿ:
1512 if b >= gGameSettings.GoalLimit then
1513 begin
1514 g_Game_NextLevel();
1515 Exit;
1516 end;
1517 end;
1519 // Îáðàáàòûâàåì êëàâèøè èãðîêîâ:
1520 if gPlayer1 <> nil then gPlayer1.ReleaseKeys();
1521 if gPlayer2 <> nil then gPlayer2.ReleaseKeys();
1522 if (not gConsoleShow) and (not gChatShow) and (g_ActiveWindow = nil) then
1523 begin
1524 processPlayerControls(gPlayer1, gGameControls.P1Control, P1MoveButton);
1525 processPlayerControls(gPlayer2, gGameControls.P2Control, P2MoveButton, true);
1526 end // if not console
1527 else
1528 begin
1529 if g_Game_IsNet and (gPlayer1 <> nil) then gPlayer1.PressKey(KEY_CHAT, 10000);
1530 end;
1531 end; // if server
1533 // Íàáëþäàòåëü
1534 if (gPlayer1 = nil) and (gPlayer2 = nil) and
1535 (not gConsoleShow) and (not gChatShow) and (g_ActiveWindow = nil) then
1536 begin
1537 if not gSpectKeyPress then
1538 begin
1539 if isKeyPressed(gGameControls.P1Control.KeyJump, gGameControls.P1Control.KeyJump2) then
1540 begin
1541 // switch spect mode
1542 case gSpectMode of
1543 SPECT_NONE: ; // not spectator
1544 SPECT_STATS,
1545 SPECT_MAPVIEW: Inc(gSpectMode);
1546 SPECT_PLAYERS: gSpectMode := SPECT_STATS; // reset to 1
1547 end;
1548 gSpectKeyPress := True;
1549 end;
1550 if gSpectMode = SPECT_MAPVIEW then
1551 begin
1552 if isKeyPressed(gGameControls.P1Control.KeyLeft, gGameControls.P1Control.KeyLeft2) then
1553 gSpectX := Max(gSpectX - gSpectStep, 0);
1554 if isKeyPressed(gGameControls.P1Control.KeyRight, gGameControls.P1Control.KeyRight2) then
1555 gSpectX := Min(gSpectX + gSpectStep, gMapInfo.Width - gScreenWidth);
1556 if isKeyPressed(gGameControls.P1Control.KeyUp, gGameControls.P1Control.KeyUp2) then
1557 gSpectY := Max(gSpectY - gSpectStep, 0);
1558 if isKeyPressed(gGameControls.P1Control.KeyDown, gGameControls.P1Control.KeyDown2) then
1559 gSpectY := Min(gSpectY + gSpectStep, gMapInfo.Height - gScreenHeight);
1560 if isKeyPressed(gGameControls.P1Control.KeyPrevWeapon, gGameControls.P1Control.KeyPrevWeapon2) then
1561 begin
1562 // decrease step
1563 if gSpectStep > 4 then gSpectStep := gSpectStep shr 1;
1564 gSpectKeyPress := True;
1565 end;
1566 if isKeyPressed(gGameControls.P1Control.KeyNextWeapon, gGameControls.P1Control.KeyNextWeapon2) then
1567 begin
1568 // increase step
1569 if gSpectStep < 64 then gSpectStep := gSpectStep shl 1;
1570 gSpectKeyPress := True;
1571 end;
1572 end;
1573 if gSpectMode = SPECT_PLAYERS then
1574 begin
1575 if isKeyPressed(gGameControls.P1Control.KeyUp, gGameControls.P1Control.KeyUp2) then
1576 begin
1577 // add second view
1578 gSpectViewTwo := True;
1579 gSpectKeyPress := True;
1580 end;
1581 if isKeyPressed(gGameControls.P1Control.KeyDown, gGameControls.P1Control.KeyDown2) then
1582 begin
1583 // remove second view
1584 gSpectViewTwo := False;
1585 gSpectKeyPress := True;
1586 end;
1587 if isKeyPressed(gGameControls.P1Control.KeyLeft, gGameControls.P1Control.KeyLeft2) then
1588 begin
1589 // prev player (view 1)
1590 gSpectPID1 := GetActivePlayerID_Prev(gSpectPID1);
1591 gSpectKeyPress := True;
1592 end;
1593 if isKeyPressed(gGameControls.P1Control.KeyRight, gGameControls.P1Control.KeyRight2) then
1594 begin
1595 // next player (view 1)
1596 gSpectPID1 := GetActivePlayerID_Next(gSpectPID1);
1597 gSpectKeyPress := True;
1598 end;
1599 if isKeyPressed(gGameControls.P1Control.KeyPrevWeapon, gGameControls.P1Control.KeyPrevWeapon2) then
1600 begin
1601 // prev player (view 2)
1602 gSpectPID2 := GetActivePlayerID_Prev(gSpectPID2);
1603 gSpectKeyPress := True;
1604 end;
1605 if isKeyPressed(gGameControls.P1Control.KeyNextWeapon, gGameControls.P1Control.KeyNextWeapon2) then
1606 begin
1607 // next player (view 2)
1608 gSpectPID2 := GetActivePlayerID_Next(gSpectPID2);
1609 gSpectKeyPress := True;
1610 end;
1611 end;
1612 end
1613 else
1614 if (not isKeyPressed(gGameControls.P1Control.KeyJump, gGameControls.P1Control.KeyJump2)) and
1615 (not isKeyPressed(gGameControls.P1Control.KeyLeft, gGameControls.P1Control.KeyLeft2)) and
1616 (not isKeyPressed(gGameControls.P1Control.KeyRight, gGameControls.P1Control.KeyRight2)) and
1617 (not isKeyPressed(gGameControls.P1Control.KeyUp, gGameControls.P1Control.KeyUp2)) and
1618 (not isKeyPressed(gGameControls.P1Control.KeyDown, gGameControls.P1Control.KeyDown2)) and
1619 (not isKeyPressed(gGameControls.P1Control.KeyPrevWeapon, gGameControls.P1Control.KeyPrevWeapon2)) and
1620 (not isKeyPressed(gGameControls.P1Control.KeyNextWeapon, gGameControls.P1Control.KeyNextWeapon2)) then
1621 gSpectKeyPress := False;
1622 end;
1624 // Îáíîâëÿåì âñå îñòàëüíîå:
1625 g_Map_Update();
1626 g_Items_Update();
1627 g_Triggers_Update();
1628 g_Weapon_Update();
1629 g_Monsters_Update();
1630 g_GFX_Update();
1631 g_Player_UpdateAll();
1632 g_Player_UpdatePhysicalObjects();
1633 if gGameSettings.GameType = GT_SERVER then
1634 if Length(gMonstersSpawned) > 0 then
1635 begin
1636 for I := 0 to High(gMonstersSpawned) do
1637 MH_SEND_MonsterSpawn(gMonstersSpawned[I]);
1638 SetLength(gMonstersSpawned, 0);
1639 end;
1641 if (gSoundTriggerTime > 8) then
1642 begin
1643 g_Game_UpdateTriggerSounds();
1644 gSoundTriggerTime := 0;
1645 end
1646 else
1647 Inc(gSoundTriggerTime);
1649 if (NetMode = NET_SERVER) then
1650 begin
1651 Inc(NetTimeToUpdate);
1652 Inc(NetTimeToReliable);
1653 if NetTimeToReliable >= NetRelupdRate then
1654 begin
1655 for I := 0 to High(gPlayers) do
1656 if gPlayers[I] <> nil then
1657 MH_SEND_PlayerPos(True, gPlayers[I].UID);
1659 if gMonsters <> nil then
1660 for I := 0 to High(gMonsters) do
1661 if gMonsters[I] <> nil then
1662 begin
1663 if (gMonsters[I].MonsterType = MONSTER_BARREL) then
1664 begin
1665 if (gMonsters[I].GameVelX <> 0) or (gMonsters[I].GameVelY <> 0) then
1666 MH_SEND_MonsterPos(gMonsters[I].UID);
1667 end
1668 else
1669 if (gMonsters[I].MonsterState <> MONSTATE_SLEEP) then
1670 if (gMonsters[I].MonsterState <> MONSTATE_DEAD) or
1671 (gMonsters[I].GameVelX <> 0) or
1672 (gMonsters[I].GameVelY <> 0) then
1673 MH_SEND_MonsterPos(gMonsters[I].UID);
1674 end;
1676 NetTimeToReliable := 0;
1677 NetTimeToUpdate := NetUpdateRate;
1678 end
1679 else if NetTimeToUpdate >= NetUpdateRate then
1680 begin
1681 if gPlayers <> nil then
1682 for I := 0 to High(gPlayers) do
1683 if gPlayers[I] <> nil then
1684 MH_SEND_PlayerPos(False, gPlayers[I].UID);
1686 if gMonsters <> nil then
1687 for I := 0 to High(gMonsters) do
1688 if gMonsters[I] <> nil then
1689 begin
1690 if (gMonsters[I].MonsterType = MONSTER_BARREL) then
1691 begin
1692 if (gMonsters[I].GameVelX <> 0) or (gMonsters[I].GameVelY <> 0) then
1693 MH_SEND_MonsterPos(gMonsters[I].UID);
1694 end
1695 else
1696 if (gMonsters[I].MonsterState <> MONSTATE_SLEEP) then
1697 if (gMonsters[I].MonsterState <> MONSTATE_DEAD) or
1698 (gMonsters[I].GameVelX <> 0) or
1699 (gMonsters[I].GameVelY <> 0) then
1700 MH_SEND_MonsterPos(gMonsters[I].UID);
1701 end;
1703 NetTimeToUpdate := 0;
1704 end;
1706 if NetUseMaster then
1707 if gTime >= NetTimeToMaster then
1708 begin
1709 if (NetMHost = nil) or (NetMPeer = nil) then
1710 if not g_Net_Slist_Connect then
1711 g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_SLIST_ERROR]);
1713 g_Net_Slist_Update;
1714 NetTimeToMaster := gTime + NetMasterRate;
1715 end;
1716 end
1717 else
1718 if NetMode = NET_CLIENT then
1719 MC_SEND_PlayerPos();
1720 end; // if gameOn ...
1722 // Àêòèâíî îêíî èíòåðôåéñà - ïåðåäàåì êëàâèøè åìó:
1723 if g_ActiveWindow <> nil then
1724 begin
1725 w := e_GetFirstKeyPressed();
1727 if (w <> IK_INVALID) then
1728 begin
1729 Msg.Msg := MESSAGE_DIKEY;
1730 Msg.wParam := w;
1731 g_ActiveWindow.OnMessage(Msg);
1732 end;
1734 // Åñëè îíî îò ýòîãî íå çàêðûëîñü, òî îáíîâëÿåì:
1735 if g_ActiveWindow <> nil then
1736 g_ActiveWindow.Update();
1738 // Íóæíî ñìåíèòü ðàçðåøåíèå:
1739 if gResolutionChange then
1740 begin
1741 e_WriteLog('Changing resolution', MSG_NOTIFY);
1742 g_Game_ChangeResolution(gRC_Width, gRC_Height, gRC_FullScreen, gRC_Maximized);
1743 gResolutionChange := False;
1744 end;
1746 // Íóæíî ñìåíèòü ÿçûê:
1747 if gLanguageChange then
1748 begin
1749 //e_WriteLog('Read language file', MSG_NOTIFY);
1750 //g_Language_Load(DataDir + gLanguage + '.txt');
1751 g_Language_Set(gLanguage);
1752 g_Menu_Reset();
1753 gLanguageChange := False;
1754 end;
1755 end;
1757 // Äåëàåì ñêðèíøîò (íå ÷àùå 200 ìèëëèñåêóíä):
1758 if e_KeyPressed(gGameControls.GameControls.TakeScreenshot) then
1759 if (GetTimer()-LastScreenShot) > 200000 div 1000 then
1760 begin
1761 g_TakeScreenShot();
1762 LastScreenShot := GetTimer();
1763 end;
1765 // Ãîðÿ÷àÿ êëàâèøà äëÿ âûçîâà ìåíþ âûõîäà èç èãðû (F10):
1766 if e_KeyPressed(IK_F10) and
1767 gGameOn and
1768 (not gConsoleShow) and
1769 (g_ActiveWindow = nil) then
1770 begin
1771 KeyPress(IK_F10);
1772 end;
1774 Time := GetTimer() {div 1000};
1776 // Îáðàáîòêà îòëîæåííûõ ñîáûòèé:
1777 if gDelayedEvents <> nil then
1778 for a := 0 to High(gDelayedEvents) do
1779 if gDelayedEvents[a].Pending and
1781 ((gDelayedEvents[a].DEType = DE_GLOBEVENT) and (gDelayedEvents[a].Time <= Time)) or
1782 ((gDelayedEvents[a].DEType > DE_GLOBEVENT) and (gDelayedEvents[a].Time <= gTime))
1783 ) then
1784 begin
1785 case gDelayedEvents[a].DEType of
1786 DE_GLOBEVENT:
1787 g_Game_ExecuteEvent(gDelayedEvents[a].DEStr);
1788 DE_BFGHIT:
1789 if gGameOn then
1790 g_Game_Announce_GoodShot(gDelayedEvents[a].DENum);
1791 DE_KILLCOMBO:
1792 if gGameOn then
1793 begin
1794 g_Game_Announce_KillCombo(gDelayedEvents[a].DENum);
1795 if g_Game_IsNet and g_Game_IsServer then
1796 MH_SEND_GameEvent(NET_EV_KILLCOMBO, gDelayedEvents[a].DENum);
1797 end;
1798 end;
1799 gDelayedEvents[a].Pending := False;
1800 end;
1802 // Êàæäóþ ñåêóíäó îáíîâëÿåì ñ÷åò÷èê îáíîâëåíèé:
1803 UPSCounter := UPSCounter + 1;
1804 if Time - UPSTime >= 1000 then
1805 begin
1806 UPS := UPSCounter;
1807 UPSCounter := 0;
1808 UPSTime := Time;
1809 end;
1810 end;
1812 procedure g_Game_LoadData();
1813 begin
1814 if DataLoaded then Exit;
1816 e_WriteLog('Loading game data...', MSG_NOTIFY);
1818 g_Texture_CreateWADEx('NOTEXTURE', GameWAD+':TEXTURES\NOTEXTURE');
1819 g_Texture_CreateWADEx('TEXTURE_PLAYER_HUD', GameWAD+':TEXTURES\HUD');
1820 g_Texture_CreateWADEx('TEXTURE_PLAYER_HUDAIR', GameWAD+':TEXTURES\AIRBAR');
1821 g_Texture_CreateWADEx('TEXTURE_PLAYER_HUDJET', GameWAD+':TEXTURES\JETBAR');
1822 g_Texture_CreateWADEx('TEXTURE_PLAYER_HUDBG', GameWAD+':TEXTURES\HUDBG');
1823 g_Texture_CreateWADEx('TEXTURE_PLAYER_ARMORHUD', GameWAD+':TEXTURES\ARMORHUD');
1824 g_Texture_CreateWADEx('TEXTURE_PLAYER_REDFLAG', GameWAD+':TEXTURES\FLAGHUD_RB');
1825 g_Texture_CreateWADEx('TEXTURE_PLAYER_REDFLAG_S', GameWAD+':TEXTURES\FLAGHUD_RS');
1826 g_Texture_CreateWADEx('TEXTURE_PLAYER_REDFLAG_D', GameWAD+':TEXTURES\FLAGHUD_RD');
1827 g_Texture_CreateWADEx('TEXTURE_PLAYER_BLUEFLAG', GameWAD+':TEXTURES\FLAGHUD_BB');
1828 g_Texture_CreateWADEx('TEXTURE_PLAYER_BLUEFLAG_S', GameWAD+':TEXTURES\FLAGHUD_BS');
1829 g_Texture_CreateWADEx('TEXTURE_PLAYER_BLUEFLAG_D', GameWAD+':TEXTURES\FLAGHUD_BD');
1830 g_Texture_CreateWADEx('TEXTURE_PLAYER_TALKBUBBLE', GameWAD+':TEXTURES\TALKBUBBLE');
1831 g_Texture_CreateWADEx('TEXTURE_PLAYER_INVULPENTA', GameWAD+':TEXTURES\PENTA');
1832 g_Frames_CreateWAD(nil, 'FRAMES_TELEPORT', GameWAD+':TEXTURES\TELEPORT', 64, 64, 10, False);
1833 g_Sound_CreateWADEx('SOUND_GAME_TELEPORT', GameWAD+':SOUNDS\TELEPORT');
1834 g_Sound_CreateWADEx('SOUND_GAME_NOTELEPORT', GameWAD+':SOUNDS\NOTELEPORT');
1835 g_Sound_CreateWADEx('SOUND_GAME_DOOROPEN', GameWAD+':SOUNDS\DOOROPEN');
1836 g_Sound_CreateWADEx('SOUND_GAME_DOORCLOSE', GameWAD+':SOUNDS\DOORCLOSE');
1837 g_Sound_CreateWADEx('SOUND_GAME_BULK1', GameWAD+':SOUNDS\BULK1');
1838 g_Sound_CreateWADEx('SOUND_GAME_BULK2', GameWAD+':SOUNDS\BULK2');
1839 g_Sound_CreateWADEx('SOUND_GAME_BUBBLE1', GameWAD+':SOUNDS\BUBBLE1');
1840 g_Sound_CreateWADEx('SOUND_GAME_BUBBLE2', GameWAD+':SOUNDS\BUBBLE2');
1841 g_Sound_CreateWADEx('SOUND_GAME_SWITCH1', GameWAD+':SOUNDS\SWITCH1');
1842 g_Sound_CreateWADEx('SOUND_GAME_SWITCH0', GameWAD+':SOUNDS\SWITCH0');
1843 g_Sound_CreateWADEx('SOUND_GAME_RADIO', GameWAD+':SOUNDS\RADIO');
1844 g_Sound_CreateWADEx('SOUND_ANNOUNCER_GOOD1', GameWAD+':SOUNDS\GOOD1');
1845 g_Sound_CreateWADEx('SOUND_ANNOUNCER_GOOD2', GameWAD+':SOUNDS\GOOD2');
1846 g_Sound_CreateWADEx('SOUND_ANNOUNCER_GOOD3', GameWAD+':SOUNDS\GOOD3');
1847 g_Sound_CreateWADEx('SOUND_ANNOUNCER_GOOD4', GameWAD+':SOUNDS\GOOD4');
1848 g_Sound_CreateWADEx('SOUND_ANNOUNCER_KILL2X', GameWAD+':SOUNDS\KILL2X');
1849 g_Sound_CreateWADEx('SOUND_ANNOUNCER_KILL3X', GameWAD+':SOUNDS\KILL3X');
1850 g_Sound_CreateWADEx('SOUND_ANNOUNCER_KILL4X', GameWAD+':SOUNDS\KILL4X');
1851 g_Sound_CreateWADEx('SOUND_ANNOUNCER_KILLMX', GameWAD+':SOUNDS\KILLMX');
1853 goodsnd[0] := TPlayableSound.Create();
1854 goodsnd[1] := TPlayableSound.Create();
1855 goodsnd[2] := TPlayableSound.Create();
1856 goodsnd[3] := TPlayableSound.Create();
1858 goodsnd[0].SetByName('SOUND_ANNOUNCER_GOOD1');
1859 goodsnd[1].SetByName('SOUND_ANNOUNCER_GOOD2');
1860 goodsnd[2].SetByName('SOUND_ANNOUNCER_GOOD3');
1861 goodsnd[3].SetByName('SOUND_ANNOUNCER_GOOD4');
1863 killsnd[0] := TPlayableSound.Create();
1864 killsnd[1] := TPlayableSound.Create();
1865 killsnd[2] := TPlayableSound.Create();
1866 killsnd[3] := TPlayableSound.Create();
1868 killsnd[0].SetByName('SOUND_ANNOUNCER_KILL2X');
1869 killsnd[1].SetByName('SOUND_ANNOUNCER_KILL3X');
1870 killsnd[2].SetByName('SOUND_ANNOUNCER_KILL4X');
1871 killsnd[3].SetByName('SOUND_ANNOUNCER_KILLMX');
1873 g_Game_SetLoadingText(_lc[I_LOAD_ITEMS_DATA], 0, False);
1874 g_Items_LoadData();
1876 g_Game_SetLoadingText(_lc[I_LOAD_WEAPONS_DATA], 0, False);
1877 g_Weapon_LoadData();
1879 g_Monsters_LoadData();
1881 DataLoaded := True;
1882 end;
1884 procedure g_Game_FreeData();
1885 begin
1886 if not DataLoaded then Exit;
1888 g_Items_FreeData();
1889 g_Weapon_FreeData();
1890 g_Monsters_FreeData();
1892 e_WriteLog('Releasing game data...', MSG_NOTIFY);
1894 g_Texture_Delete('NOTEXTURE');
1895 g_Texture_Delete('TEXTURE_PLAYER_HUD');
1896 g_Texture_Delete('TEXTURE_PLAYER_HUDBG');
1897 g_Texture_Delete('TEXTURE_PLAYER_ARMORHUD');
1898 g_Texture_Delete('TEXTURE_PLAYER_REDFLAG');
1899 g_Texture_Delete('TEXTURE_PLAYER_REDFLAG_S');
1900 g_Texture_Delete('TEXTURE_PLAYER_REDFLAG_D');
1901 g_Texture_Delete('TEXTURE_PLAYER_BLUEFLAG');
1902 g_Texture_Delete('TEXTURE_PLAYER_BLUEFLAG_S');
1903 g_Texture_Delete('TEXTURE_PLAYER_BLUEFLAG_D');
1904 g_Texture_Delete('TEXTURE_PLAYER_TALKBUBBLE');
1905 g_Texture_Delete('TEXTURE_PLAYER_INVULPENTA');
1906 g_Frames_DeleteByName('FRAMES_TELEPORT');
1907 g_Sound_Delete('SOUND_GAME_TELEPORT');
1908 g_Sound_Delete('SOUND_GAME_NOTELEPORT');
1909 g_Sound_Delete('SOUND_GAME_DOOROPEN');
1910 g_Sound_Delete('SOUND_GAME_DOORCLOSE');
1911 g_Sound_Delete('SOUND_GAME_BULK1');
1912 g_Sound_Delete('SOUND_GAME_BULK2');
1913 g_Sound_Delete('SOUND_GAME_BUBBLE1');
1914 g_Sound_Delete('SOUND_GAME_BUBBLE2');
1915 g_Sound_Delete('SOUND_GAME_SWITCH1');
1916 g_Sound_Delete('SOUND_GAME_SWITCH0');
1918 goodsnd[0].Free();
1919 goodsnd[1].Free();
1920 goodsnd[2].Free();
1921 goodsnd[3].Free();
1923 g_Sound_Delete('SOUND_ANNOUNCER_GOOD1');
1924 g_Sound_Delete('SOUND_ANNOUNCER_GOOD2');
1925 g_Sound_Delete('SOUND_ANNOUNCER_GOOD3');
1926 g_Sound_Delete('SOUND_ANNOUNCER_GOOD4');
1928 killsnd[0].Free();
1929 killsnd[1].Free();
1930 killsnd[2].Free();
1931 killsnd[3].Free();
1933 g_Sound_Delete('SOUND_ANNOUNCER_KILL2X');
1934 g_Sound_Delete('SOUND_ANNOUNCER_KILL3X');
1935 g_Sound_Delete('SOUND_ANNOUNCER_KILL4X');
1936 g_Sound_Delete('SOUND_ANNOUNCER_KILLMX');
1938 DataLoaded := False;
1939 end;
1941 procedure DrawCustomStat();
1942 var
1943 pc, x, y, w, _y,
1944 w1, w2, w3,
1945 t, p, m: Integer;
1946 ww1, hh1: Word;
1947 ww2, hh2, r, g, b, rr, gg, bb: Byte;
1948 s1, s2, topstr: String;
1949 begin
1950 e_TextureFontGetSize(gStdFont, ww2, hh2);
1952 e_PollInput();
1953 if e_KeyPressed(IK_TAB) then
1954 begin
1955 if not gStatsPressed then
1956 begin
1957 gStatsOff := not gStatsOff;
1958 gStatsPressed := True;
1959 end;
1960 end
1961 else
1962 gStatsPressed := False;
1964 if gStatsOff then
1965 begin
1966 s1 := _lc[I_MENU_INTER_NOTICE_TAB];
1967 w := (Length(s1) * ww2) div 2;
1968 x := gScreenWidth div 2 - w;
1969 y := 8;
1970 e_TextureFontPrint(x, y, s1, gStdFont);
1971 Exit;
1972 end;
1974 if (gGameSettings.GameMode = GM_COOP) then
1975 begin
1976 if gMissionFailed then
1977 topstr := _lc[I_MENU_INTER_MISSION_FAIL]
1978 else
1979 topstr := _lc[I_MENU_INTER_LEVEL_COMPLETE];
1980 end
1981 else
1982 topstr := _lc[I_MENU_INTER_ROUND_OVER];
1984 e_CharFont_GetSize(gMenuFont, topstr, ww1, hh1);
1985 e_CharFont_Print(gMenuFont, (gScreenWidth div 2)-(ww1 div 2), 16, topstr);
1987 if g_Game_IsNet then
1988 begin
1989 topstr := Format(_lc[I_MENU_INTER_NOTICE_TIME], [gServInterTime]);
1990 if not gChatShow then
1991 e_TextureFontPrintEx((gScreenWidth div 2)-(Length(topstr)*ww2 div 2),
1992 gScreenHeight-(hh2+4)*2, topstr, gStdFont, 255, 255, 255, 1);
1993 end;
1995 if g_Game_IsClient then
1996 topstr := _lc[I_MENU_INTER_NOTICE_MAP]
1997 else
1998 topstr := _lc[I_MENU_INTER_NOTICE_SPACE];
1999 if not gChatShow then
2000 e_TextureFontPrintEx((gScreenWidth div 2)-(Length(topstr)*ww2 div 2),
2001 gScreenHeight-(hh2+4), topstr, gStdFont, 255, 255, 255, 1);
2003 x := 32;
2004 y := 16+hh1+16;
2006 w := gScreenWidth-x*2;
2008 w2 := (w-16) div 6;
2009 w3 := w2;
2010 w1 := w-16-w2-w3;
2012 e_DrawFillQuad(x, y, gScreenWidth-x-1, gScreenHeight-y-1, 64, 64, 64, 32);
2013 e_DrawQuad(x, y, gScreenWidth-x-1, gScreenHeight-y-1, 255, 127, 0);
2015 m := Max(Length(_lc[I_MENU_MAP])+1, Length(_lc[I_GAME_GAME_TIME])+1)*ww2;
2017 case CustomStat.GameMode of
2018 GM_DM:
2019 begin
2020 if gGameSettings.MaxLives = 0 then
2021 s1 := _lc[I_GAME_DM]
2022 else
2023 s1 := _lc[I_GAME_LMS];
2024 end;
2025 GM_TDM:
2026 begin
2027 if gGameSettings.MaxLives = 0 then
2028 s1 := _lc[I_GAME_TDM]
2029 else
2030 s1 := _lc[I_GAME_TLMS];
2031 end;
2032 GM_CTF: s1 := _lc[I_GAME_CTF];
2033 GM_COOP:
2034 begin
2035 if gGameSettings.MaxLives = 0 then
2036 s1 := _lc[I_GAME_COOP]
2037 else
2038 s1 := _lc[I_GAME_SURV];
2039 end;
2040 else s1 := '';
2041 end;
2043 _y := y+16;
2044 e_TextureFontPrintEx(x+(w div 2)-(Length(s1)*ww2 div 2), _y, s1, gStdFont, 255, 255, 255, 1);
2045 _y := _y+8;
2047 _y := _y+16;
2048 e_TextureFontPrintEx(x+8, _y, _lc[I_MENU_MAP], gStdFont, 255, 127, 0, 1);
2049 e_TextureFontPrint(x+8+m, _y, Format('%s - %s', [CustomStat.Map, CustomStat.MapName]), gStdFont);
2051 _y := _y+16;
2052 e_TextureFontPrintEx(x+8, _y, _lc[I_GAME_GAME_TIME], gStdFont, 255, 127, 0, 1);
2053 e_TextureFontPrint(x+8+m, _y, Format('%d:%.2d:%.2d', [CustomStat.GameTime div 1000 div 3600,
2054 (CustomStat.GameTime div 1000 div 60) mod 60,
2055 CustomStat.GameTime div 1000 mod 60]), gStdFont);
2057 pc := Length(CustomStat.PlayerStat);
2058 if pc = 0 then Exit;
2060 if CustomStat.GameMode = GM_COOP then
2061 begin
2062 m := Max(Length(_lc[I_GAME_MONSTERS])+1, Length(_lc[I_GAME_SECRETS])+1)*ww2;
2063 _y := _y+32;
2064 s2 := _lc[I_GAME_MONSTERS];
2065 e_TextureFontPrintEx(x+8, _y, s2, gStdFont, 255, 127, 0, 1);
2066 e_TextureFontPrintEx(x+8+m, _y, IntToStr(gCoopMonstersKilled) + '/' + IntToStr(gTotalMonsters), gStdFont, 255, 255, 255, 1);
2067 _y := _y+16;
2068 s2 := _lc[I_GAME_SECRETS];
2069 e_TextureFontPrintEx(x+8, _y, s2, gStdFont, 255, 127, 0, 1);
2070 e_TextureFontPrintEx(x+8+m, _y, IntToStr(gCoopSecretsFound) + '/' + IntToStr(gSecretsCount), gStdFont, 255, 255, 255, 1);
2071 if gLastMap then
2072 begin
2073 m := Max(Length(_lc[I_GAME_MONSTERS_TOTAL])+1, Length(_lc[I_GAME_SECRETS_TOTAL])+1)*ww2;
2074 _y := _y-16;
2075 s2 := _lc[I_GAME_MONSTERS_TOTAL];
2076 e_TextureFontPrintEx(x+250, _y, s2, gStdFont, 255, 127, 0, 1);
2077 e_TextureFontPrintEx(x+250+m, _y, IntToStr(gCoopTotalMonstersKilled) + '/' + IntToStr(gCoopTotalMonsters), gStdFont, 255, 255, 255, 1);
2078 _y := _y+16;
2079 s2 := _lc[I_GAME_SECRETS_TOTAL];
2080 e_TextureFontPrintEx(x+250, _y, s2, gStdFont, 255, 127, 0, 1);
2081 e_TextureFontPrintEx(x+250+m, _y, IntToStr(gCoopTotalSecretsFound) + '/' + IntToStr(gCoopTotalSecrets), gStdFont, 255, 255, 255, 1);
2082 end;
2083 end;
2085 if CustomStat.GameMode in [GM_TDM, GM_CTF] then
2086 begin
2087 _y := _y+16+16;
2089 with CustomStat do
2090 if TeamStat[TEAM_RED].Goals > TeamStat[TEAM_BLUE].Goals then s1 := _lc[I_GAME_WIN_RED]
2091 else if TeamStat[TEAM_BLUE].Goals > TeamStat[TEAM_RED].Goals then s1 := _lc[I_GAME_WIN_BLUE]
2092 else s1 := _lc[I_GAME_WIN_DRAW];
2094 e_TextureFontPrintEx(x+8+(w div 2)-(Length(s1)*ww2 div 2), _y, s1, gStdFont, 255, 255, 255, 1);
2095 _y := _y+40;
2097 for t := TEAM_RED to TEAM_BLUE do
2098 begin
2099 if t = TEAM_RED then
2100 begin
2101 e_TextureFontPrintEx(x+8, _y, _lc[I_GAME_TEAM_RED],
2102 gStdFont, 255, 0, 0, 1);
2103 e_TextureFontPrintEx(x+w1+8, _y, IntToStr(CustomStat.TeamStat[TEAM_RED].Goals),
2104 gStdFont, 255, 0, 0, 1);
2105 r := 255;
2106 g := 0;
2107 b := 0;
2108 end
2109 else
2110 begin
2111 e_TextureFontPrintEx(x+8, _y, _lc[I_GAME_TEAM_BLUE],
2112 gStdFont, 0, 0, 255, 1);
2113 e_TextureFontPrintEx(x+w1+8, _y, IntToStr(CustomStat.TeamStat[TEAM_BLUE].Goals),
2114 gStdFont, 0, 0, 255, 1);
2115 r := 0;
2116 g := 0;
2117 b := 255;
2118 end;
2120 e_DrawLine(1, x+8, _y+20, x-8+w, _y+20, r, g, b);
2121 _y := _y+24;
2123 for p := 0 to High(CustomStat.PlayerStat) do
2124 if CustomStat.PlayerStat[p].Team = t then
2125 with CustomStat.PlayerStat[p] do
2126 begin
2127 if Spectator then
2128 begin
2129 rr := r div 2;
2130 gg := g div 2;
2131 bb := b div 2;
2132 end
2133 else
2134 begin
2135 rr := r;
2136 gg := g;
2137 bb := b;
2138 end;
2139 e_TextureFontPrintEx(x+8, _y, Name, gStdFont, rr, gg, bb, 1);
2140 e_TextureFontPrintEx(x+w1+8, _y, IntToStr(Frags), gStdFont, rr, gg, bb, 1);
2141 e_TextureFontPrintEx(x+w1+w2+8, _y, IntToStr(Deaths), gStdFont, rr, gg, bb, 1);
2142 _y := _y+24;
2143 end;
2145 _y := _y+16+16;
2146 end;
2147 end
2148 else if CustomStat.GameMode in [GM_DM, GM_COOP] then
2149 begin
2150 _y := _y+40;
2151 e_TextureFontPrintEx(x+8, _y, _lc[I_GAME_PLAYER_NAME], gStdFont, 255, 127, 0, 1);
2152 e_TextureFontPrintEx(x+8+w1, _y, _lc[I_GAME_FRAGS], gStdFont, 255, 127, 0, 1);
2153 e_TextureFontPrintEx(x+8+w1+w2, _y, _lc[I_GAME_DEATHS], gStdFont, 255, 127, 0, 1);
2155 _y := _y+24;
2156 for p := 0 to High(CustomStat.PlayerStat) do
2157 with CustomStat.PlayerStat[p] do
2158 begin
2159 e_DrawFillQuad(x+8, _y+4, x+24-1, _y+16+4-1, Color.R, Color.G, Color.B, 0);
2161 if Spectator then
2162 r := 127
2163 else
2164 r := 255;
2166 e_TextureFontPrintEx(x+8+16+8, _y+4, Name, gStdFont, r, r, r, 1, True);
2167 e_TextureFontPrintEx(x+w1+8+16+8, _y+4, IntToStr(Frags), gStdFont, r, r, r, 1, True);
2168 e_TextureFontPrintEx(x+w1+w2+8+16+8, _y+4, IntToStr(Deaths), gStdFont, r, r, r, 1, True);
2169 _y := _y+24;
2170 end;
2171 end;
2172 end;
2174 procedure DrawSingleStat();
2175 var
2176 tm, key_x, val_x, y: Integer;
2177 w1, w2, h: Word;
2178 s1, s2: String;
2180 procedure player_stat(n: Integer);
2181 var
2182 kpm: Real;
2184 begin
2185 // "Kills: # / #":
2186 s1 := Format(' %d ', [SingleStat.PlayerStat[n].Kills]);
2187 s2 := Format(' %d', [gTotalMonsters]);
2189 e_CharFont_Print(gMenuFont, key_x, y, _lc[I_MENU_INTER_KILLS]);
2190 e_CharFont_PrintEx(gMenuFont, val_x, y, s1, _RGB(255, 0, 0));
2191 e_CharFont_GetSize(gMenuFont, s1, w1, h);
2192 e_CharFont_Print(gMenuFont, val_x+w1, y, '/');
2193 s1 := s1 + '/';
2194 e_CharFont_GetSize(gMenuFont, s1, w1, h);
2195 e_CharFont_PrintEx(gMenuFont, val_x+w1, y, s2, _RGB(255, 0, 0));
2197 // "Kills-per-minute: ##.#":
2198 s1 := _lc[I_MENU_INTER_KPM];
2199 if tm > 0 then
2200 kpm := (SingleStat.PlayerStat[n].Kills / tm) * 60
2201 else
2202 kpm := SingleStat.PlayerStat[n].Kills;
2203 s2 := Format(' %.1f', [kpm]);
2205 e_CharFont_Print(gMenuFont, key_x, y+32, s1);
2206 e_CharFont_PrintEx(gMenuFont, val_x, y+32, s2, _RGB(255, 0, 0));
2208 // "Secrets found: # / #":
2209 s1 := Format(' %d ', [SingleStat.PlayerStat[n].Secrets]);
2210 s2 := Format(' %d', [SingleStat.TotalSecrets]);
2212 e_CharFont_Print(gMenuFont, key_x, y+64, _lc[I_MENU_INTER_SECRETS]);
2213 e_CharFont_PrintEx(gMenuFont, val_x, y+64, s1, _RGB(255, 0, 0));
2214 e_CharFont_GetSize(gMenuFont, s1, w1, h);
2215 e_CharFont_Print(gMenuFont, val_x+w1, y+64, '/');
2216 s1 := s1 + '/';
2217 e_CharFont_GetSize(gMenuFont, s1, w1, h);
2218 e_CharFont_PrintEx(gMenuFont, val_x+w1, y+64, s2, _RGB(255, 0, 0));
2219 end;
2221 begin
2222 // "Level Complete":
2223 e_CharFont_GetSize(gMenuFont, _lc[I_MENU_INTER_LEVEL_COMPLETE], w1, h);
2224 e_CharFont_Print(gMenuFont, (gScreenWidth-w1) div 2, 32, _lc[I_MENU_INTER_LEVEL_COMPLETE]);
2226 // Îïðåäåëÿåì êîîðäèíàòû âûðàâíèâàíèÿ ïî ñàìîé äëèííîé ñòðîêå:
2227 s1 := _lc[I_MENU_INTER_KPM];
2228 e_CharFont_GetSize(gMenuFont, s1, w1, h);
2229 Inc(w1, 16);
2230 s1 := ' 9999.9';
2231 e_CharFont_GetSize(gMenuFont, s1, w2, h);
2233 key_x := (gScreenWidth-w1-w2) div 2;
2234 val_x := key_x + w1;
2236 // "Time: #:##:##":
2237 tm := SingleStat.GameTime div 1000;
2238 s1 := _lc[I_MENU_INTER_TIME];
2239 s2 := Format(' %d:%.2d:%.2d', [tm div (60*60), (tm mod (60*60)) div 60, tm mod 60]);
2241 e_CharFont_Print(gMenuFont, key_x, 80, s1);
2242 e_CharFont_PrintEx(gMenuFont, val_x, 80, s2, _RGB(255, 0, 0));
2244 if SingleStat.TwoPlayers then
2245 begin
2246 // "Player 1":
2247 s1 := _lc[I_MENU_PLAYER_1];
2248 e_CharFont_GetSize(gMenuFont, s1, w1, h);
2249 e_CharFont_Print(gMenuFont, (gScreenWidth-w1) div 2, 128, s1);
2251 // Ñòàòèñòèêà ïåðâîãî èãðîêà:
2252 y := 176;
2253 player_stat(0);
2255 // "Player 2":
2256 s1 := _lc[I_MENU_PLAYER_2];
2257 e_CharFont_GetSize(gMenuFont, s1, w1, h);
2258 e_CharFont_Print(gMenuFont, (gScreenWidth-w1) div 2, 288, s1);
2260 // Ñòàòèñòèêà âòîðîãî èãðîêà:
2261 y := 336;
2262 player_stat(1);
2263 end
2264 else
2265 begin
2266 // Ñòàòèñòèêà ïåðâîãî èãðîêà:
2267 y := 128;
2268 player_stat(0);
2269 end;
2270 end;
2272 procedure DrawLoadingStat();
2273 var
2274 ww, hh: Word;
2275 xx, yy, i: Integer;
2276 s: String;
2277 begin
2278 if Length(LoadingStat.Msgs) = 0 then
2279 Exit;
2281 e_CharFont_GetSize(gMenuFont, _lc[I_MENU_LOADING], ww, hh);
2282 yy := (gScreenHeight div 3);
2283 e_CharFont_Print(gMenuFont, (gScreenWidth div 2)-(ww div 2), yy-2*hh, _lc[I_MENU_LOADING]);
2284 xx := (gScreenWidth div 3);
2286 with LoadingStat do
2287 for i := 0 to NextMsg-1 do
2288 begin
2289 if (i = (NextMsg-1)) and (MaxValue > 0) then
2290 s := Format('%s: %d/%d', [Msgs[i], CurValue, MaxValue])
2291 else
2292 s := Msgs[i];
2294 e_CharFont_PrintEx(gMenuSmallFont, xx, yy, s, _RGB(255, 0, 0));
2295 yy := yy + LOADING_INTERLINE;
2296 end;
2297 end;
2299 procedure DrawMinimap(p: TPlayer; RenderRect: e_graphics.TRect);
2300 var
2301 a, aX, aY, aX2, aY2, Scale, ScaleSz: Integer;
2302 begin
2303 if (gMapInfo.Width > RenderRect.Right - RenderRect.Left) or
2304 (gMapInfo.Height > RenderRect.Bottom - RenderRect.Top) then
2305 begin
2306 Scale := 1;
2307 // Ñêîëüêî ïèêñåëîâ êàðòû â 1 ïèêñåëå ìèíè-êàðòû:
2308 ScaleSz := 16 div Scale;
2309 // Ðàçìåðû ìèíè-êàðòû:
2310 aX := max(gMapInfo.Width div ScaleSz, 1);
2311 aY := max(gMapInfo.Height div ScaleSz, 1);
2312 // Ðàìêà êàðòû:
2313 e_DrawFillQuad(0, 0, aX-1, aY-1, 0, 0, 0, 0);
2315 if gWalls <> nil then
2316 begin
2317 // Ðèñóåì ñòåíû:
2318 for a := 0 to High(gWalls) do
2319 with gWalls[a] do
2320 if PanelType <> 0 then
2321 begin
2322 // Ëåâûé âåðõíèé óãîë:
2323 aX := X div ScaleSz;
2324 aY := Y div ScaleSz;
2325 // Ðàçìåðû:
2326 aX2 := max(Width div ScaleSz, 1);
2327 aY2 := max(Height div ScaleSz, 1);
2328 // Ïðàâûé íèæíèé óãîë:
2329 aX2 := aX + aX2 - 1;
2330 aY2 := aY + aY2 - 1;
2332 case PanelType of
2333 PANEL_WALL: e_DrawFillQuad(aX, aY, aX2, aY2, 208, 208, 208, 0);
2334 PANEL_OPENDOOR, PANEL_CLOSEDOOR:
2335 if Enabled then e_DrawFillQuad(aX, aY, aX2, aY2, 160, 160, 160, 0);
2336 end;
2337 end;
2338 end;
2339 if gSteps <> nil then
2340 begin
2341 // Ðèñóåì ñòóïåíè:
2342 for a := 0 to High(gSteps) do
2343 with gSteps[a] do
2344 if PanelType <> 0 then
2345 begin
2346 // Ëåâûé âåðõíèé óãîë:
2347 aX := X div ScaleSz;
2348 aY := Y div ScaleSz;
2349 // Ðàçìåðû:
2350 aX2 := max(Width div ScaleSz, 1);
2351 aY2 := max(Height div ScaleSz, 1);
2352 // Ïðàâûé íèæíèé óãîë:
2353 aX2 := aX + aX2 - 1;
2354 aY2 := aY + aY2 - 1;
2356 e_DrawFillQuad(aX, aY, aX2, aY2, 128, 128, 128, 0);
2357 end;
2358 end;
2359 if gLifts <> nil then
2360 begin
2361 // Ðèñóåì ëèôòû:
2362 for a := 0 to High(gLifts) do
2363 with gLifts[a] do
2364 if PanelType <> 0 then
2365 begin
2366 // Ëåâûé âåðõíèé óãîë:
2367 aX := X div ScaleSz;
2368 aY := Y div ScaleSz;
2369 // Ðàçìåðû:
2370 aX2 := max(Width div ScaleSz, 1);
2371 aY2 := max(Height div ScaleSz, 1);
2372 // Ïðàâûé íèæíèé óãîë:
2373 aX2 := aX + aX2 - 1;
2374 aY2 := aY + aY2 - 1;
2376 case LiftType of
2377 0: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 72, 36, 0);
2378 1: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 124, 96, 0);
2379 2: e_DrawFillQuad(aX, aY, aX2, aY2, 200, 80, 4, 0);
2380 3: e_DrawFillQuad(aX, aY, aX2, aY2, 252, 140, 56, 0);
2381 end;
2382 end;
2383 end;
2384 if gWater <> nil then
2385 begin
2386 // Ðèñóåì âîäó:
2387 for a := 0 to High(gWater) do
2388 with gWater[a] do
2389 if PanelType <> 0 then
2390 begin
2391 // Ëåâûé âåðõíèé óãîë:
2392 aX := X div ScaleSz;
2393 aY := Y div ScaleSz;
2394 // Ðàçìåðû:
2395 aX2 := max(Width div ScaleSz, 1);
2396 aY2 := max(Height div ScaleSz, 1);
2397 // Ïðàâûé íèæíèé óãîë:
2398 aX2 := aX + aX2 - 1;
2399 aY2 := aY + aY2 - 1;
2401 e_DrawFillQuad(aX, aY, aX2, aY2, 0, 0, 192, 0);
2402 end;
2403 end;
2404 if gAcid1 <> nil then
2405 begin
2406 // Ðèñóåì êèñëîòó 1:
2407 for a := 0 to High(gAcid1) do
2408 with gAcid1[a] do
2409 if PanelType <> 0 then
2410 begin
2411 // Ëåâûé âåðõíèé óãîë:
2412 aX := X div ScaleSz;
2413 aY := Y div ScaleSz;
2414 // Ðàçìåðû:
2415 aX2 := max(Width div ScaleSz, 1);
2416 aY2 := max(Height div ScaleSz, 1);
2417 // Ïðàâûé íèæíèé óãîë:
2418 aX2 := aX + aX2 - 1;
2419 aY2 := aY + aY2 - 1;
2421 e_DrawFillQuad(aX, aY, aX2, aY2, 0, 176, 0, 0);
2422 end;
2423 end;
2424 if gAcid2 <> nil then
2425 begin
2426 // Ðèñóåì êèñëîòó 2:
2427 for a := 0 to High(gAcid2) do
2428 with gAcid2[a] do
2429 if PanelType <> 0 then
2430 begin
2431 // Ëåâûé âåðõíèé óãîë:
2432 aX := X div ScaleSz;
2433 aY := Y div ScaleSz;
2434 // Ðàçìåðû:
2435 aX2 := max(Width div ScaleSz, 1);
2436 aY2 := max(Height div ScaleSz, 1);
2437 // Ïðàâûé íèæíèé óãîë:
2438 aX2 := aX + aX2 - 1;
2439 aY2 := aY + aY2 - 1;
2441 e_DrawFillQuad(aX, aY, aX2, aY2, 176, 0, 0, 0);
2442 end;
2443 end;
2444 if gPlayers <> nil then
2445 begin
2446 // Ðèñóåì èãðîêîâ:
2447 for a := 0 to High(gPlayers) do
2448 if gPlayers[a] <> nil then with gPlayers[a] do
2449 if Live then begin
2450 // Ëåâûé âåðõíèé óãîë:
2451 aX := Obj.X div ScaleSz + 1;
2452 aY := Obj.Y div ScaleSz + 1;
2453 // Ðàçìåðû:
2454 aX2 := max(Obj.Rect.Width div ScaleSz, 1);
2455 aY2 := max(Obj.Rect.Height div ScaleSz, 1);
2456 // Ïðàâûé íèæíèé óãîë:
2457 aX2 := aX + aX2 - 1;
2458 aY2 := aY + aY2 - 1;
2460 if gPlayers[a] = p then
2461 e_DrawFillQuad(aX, aY, aX2, aY2, 0, 255, 0, 0)
2462 else
2463 case Team of
2464 TEAM_RED: e_DrawFillQuad(aX, aY, aX2, aY2, 255, 0, 0, 0);
2465 TEAM_BLUE: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 0, 255, 0);
2466 else e_DrawFillQuad(aX, aY, aX2, aY2, 255, 128, 0, 0);
2467 end;
2468 end;
2469 end;
2470 if gMonsters <> nil then
2471 begin
2472 // Ðèñóåì ìîíñòðîâ:
2473 for a := 0 to High(gMonsters) do
2474 if gMonsters[a] <> nil then with gMonsters[a] do
2475 if Live then begin
2476 // Ëåâûé âåðõíèé óãîë:
2477 aX := Obj.X div ScaleSz + 1;
2478 aY := Obj.Y div ScaleSz + 1;
2479 // Ðàçìåðû:
2480 aX2 := max(Obj.Rect.Width div ScaleSz, 1);
2481 aY2 := max(Obj.Rect.Height div ScaleSz, 1);
2482 // Ïðàâûé íèæíèé óãîë:
2483 aX2 := aX + aX2 - 1;
2484 aY2 := aY + aY2 - 1;
2486 e_DrawFillQuad(aX, aY, aX2, aY2, 255, 255, 0, 0);
2487 end;
2488 end;
2489 end;
2490 end;
2492 procedure DrawMapView(x, y, w, h: Integer);
2493 var
2494 bx, by: Integer;
2495 begin
2496 glPushMatrix();
2498 bx := Round(x/(gMapInfo.Width - w)*(gBackSize.X - w));
2499 by := Round(y/(gMapInfo.Height - h)*(gBackSize.Y - h));
2500 g_Map_DrawBack(-bx, -by);
2502 sX := x;
2503 sY := y;
2504 sWidth := w;
2505 sHeight := h;
2507 glTranslatef(-x, -y, 0);
2509 g_Map_DrawPanels(PANEL_BACK);
2510 g_Map_DrawPanels(PANEL_STEP);
2511 g_Items_Draw();
2512 g_Weapon_Draw();
2513 g_Player_DrawShells();
2514 g_Player_DrawAll();
2515 g_Player_DrawCorpses();
2516 g_Map_DrawPanels(PANEL_WALL);
2517 g_Monsters_Draw();
2518 g_Map_DrawPanels(PANEL_CLOSEDOOR);
2519 g_GFX_Draw();
2520 g_Map_DrawFlags();
2521 g_Map_DrawPanels(PANEL_ACID1);
2522 g_Map_DrawPanels(PANEL_ACID2);
2523 g_Map_DrawPanels(PANEL_WATER);
2524 g_Map_DrawPanels(PANEL_FORE);
2525 if g_debug_HealthBar then
2526 begin
2527 g_Monsters_DrawHealth();
2528 g_Player_DrawHealth();
2529 end;
2531 glPopMatrix();
2532 end;
2534 procedure DrawPlayer(p: TPlayer);
2535 var
2536 px, py, a, b, c, d: Integer;
2537 //R: TRect;
2538 begin
2539 if (p = nil) or (p.FDummy) then
2540 begin
2541 glPushMatrix();
2542 g_Map_DrawBack(0, 0);
2543 glPopMatrix();
2544 Exit;
2545 end;
2547 gPlayerDrawn := p;
2549 glPushMatrix();
2551 px := p.GameX + PLAYER_RECT_CX;
2552 py := p.GameY + PLAYER_RECT_CY;
2554 if px > (gPlayerScreenSize.X div 2) then
2555 a := -px + (gPlayerScreenSize.X div 2)
2556 else
2557 a := 0;
2558 if py > (gPlayerScreenSize.Y div 2) then
2559 b := -py + (gPlayerScreenSize.Y div 2)
2560 else
2561 b := 0;
2562 if px > (gMapInfo.Width - (gPlayerScreenSize.X div 2)) then
2563 a := -gMapInfo.Width + gPlayerScreenSize.X;
2564 if py > (gMapInfo.Height - (gPlayerScreenSize.Y div 2)) then
2565 b := -gMapInfo.Height + gPlayerScreenSize.Y;
2566 if gMapInfo.Width <= gPlayerScreenSize.X then
2567 a := 0;
2568 if gMapInfo.Height <= gPlayerScreenSize.Y then
2569 b := 0;
2571 if p.IncCam <> 0 then
2572 begin
2573 if py > (gMapInfo.Height - (gPlayerScreenSize.Y div 2)) then
2574 begin
2575 if p.IncCam > 120-(py-(gMapInfo.Height-(gPlayerScreenSize.Y div 2))) then
2576 p.IncCam := 120-(py-(gMapInfo.Height-(gPlayerScreenSize.Y div 2)));
2577 end;
2579 if py < (gPlayerScreenSize.Y div 2) then
2580 begin
2581 if p.IncCam < -120+((gPlayerScreenSize.Y div 2)-py) then
2582 p.IncCam := -120+((gPlayerScreenSize.Y div 2)-py);
2583 end;
2585 if p.IncCam < 0 then
2586 while (py+(gPlayerScreenSize.Y div 2)-p.IncCam > gMapInfo.Height) and
2587 (p.IncCam < 0) do
2588 p.IncCam := p.IncCam + 1;
2590 if p.IncCam > 0 then
2591 while (py-(gPlayerScreenSize.Y div 2)-p.IncCam < 0) and
2592 (p.IncCam > 0) do
2593 p.IncCam := p.IncCam - 1;
2594 end;
2596 if (px< gPlayerScreenSize.X div 2) or
2597 (gMapInfo.Width-gPlayerScreenSize.X <= 256) then
2598 c := 0
2599 else
2600 if (px > gMapInfo.Width-(gPlayerScreenSize.X div 2)) then
2601 c := gBackSize.X - gPlayerScreenSize.X
2602 else
2603 c := Round((px-(gPlayerScreenSize.X div 2))/(gMapInfo.Width-gPlayerScreenSize.X)*(gBackSize.X-gPlayerScreenSize.X));
2605 if (py-p.IncCam <= gPlayerScreenSize.Y div 2) or
2606 (gMapInfo.Height-gPlayerScreenSize.Y <= 256) then
2607 d := 0
2608 else
2609 if (py-p.IncCam >= gMapInfo.Height-(gPlayerScreenSize.Y div 2)) then
2610 d := gBackSize.Y - gPlayerScreenSize.Y
2611 else
2612 d := Round((py-p.IncCam-(gPlayerScreenSize.Y div 2))/(gMapInfo.Height-gPlayerScreenSize.Y)*(gBackSize.Y-gPlayerScreenSize.Y));
2614 g_Map_DrawBack(-c, -d);
2616 sX := -a;
2617 sY := -(b+p.IncCam);
2618 sWidth := gPlayerScreenSize.X;
2619 sHeight := gPlayerScreenSize.Y;
2621 glTranslatef(a, b+p.IncCam, 0);
2623 g_Map_DrawPanels(PANEL_BACK);
2624 g_Map_DrawPanels(PANEL_STEP);
2625 g_Items_Draw();
2626 g_Weapon_Draw();
2627 g_Player_DrawShells();
2628 g_Player_DrawAll();
2629 g_Player_DrawCorpses();
2630 g_Map_DrawPanels(PANEL_WALL);
2631 g_Monsters_Draw();
2632 g_Map_DrawPanels(PANEL_CLOSEDOOR);
2633 g_GFX_Draw();
2634 g_Map_DrawFlags();
2635 g_Map_DrawPanels(PANEL_ACID1);
2636 g_Map_DrawPanels(PANEL_ACID2);
2637 g_Map_DrawPanels(PANEL_WATER);
2638 g_Map_DrawPanels(PANEL_FORE);
2639 if g_debug_HealthBar then
2640 begin
2641 g_Monsters_DrawHealth();
2642 g_Player_DrawHealth();
2643 end;
2645 if p.FSpectator then
2646 e_TextureFontPrintEx(p.GameX + PLAYER_RECT_CX - 4,
2647 p.GameY + PLAYER_RECT_CY - 4,
2648 'X', gStdFont, 255, 255, 255, 1, True);
2650 for a := 0 to High(gCollideMap) do
2651 for b := 0 to High(gCollideMap[a]) do
2652 begin
2653 d := 0;
2654 if ByteBool(gCollideMap[a, b] and MARK_WALL) then
2655 d := d + 1;
2656 if ByteBool(gCollideMap[a, b] and MARK_DOOR) then
2657 d := d + 2;
2659 case d of
2660 1: e_DrawPoint(1, b, a, 200, 200, 200);
2661 2: e_DrawPoint(1, b, a, 64, 64, 255);
2662 3: e_DrawPoint(1, b, a, 255, 0, 255);
2663 end;
2664 end;
2667 glPopMatrix();
2669 p.DrawPain();
2670 p.DrawPickup();
2671 p.DrawRulez();
2672 if gShowMap then DrawMinimap(p, _TRect(0, 0, 128, 128));
2673 if g_Debug_Player then
2674 g_Player_DrawDebug(p);
2675 p.DrawGUI();
2676 end;
2678 procedure g_Game_Draw();
2679 var
2680 ID: DWORD;
2681 w, h: Word;
2682 ww, hh: Byte;
2683 Time: Int64;
2684 back: string;
2685 plView1, plView2: TPlayer;
2686 Split: Boolean;
2687 begin
2688 if gExit = EXIT_QUIT then Exit;
2690 Time := GetTimer() {div 1000};
2691 FPSCounter := FPSCounter+1;
2692 if Time - FPSTime >= 1000 then
2693 begin
2694 FPS := FPSCounter;
2695 FPSCounter := 0;
2696 FPSTime := Time;
2697 end;
2699 if gGameOn or (gState = STATE_FOLD) then
2700 begin
2701 if (gPlayer1 <> nil) and (gPlayer2 <> nil) then
2702 begin
2703 gSpectMode := SPECT_NONE;
2704 if not gRevertPlayers then
2705 begin
2706 plView1 := gPlayer1;
2707 plView2 := gPlayer2;
2708 end
2709 else
2710 begin
2711 plView1 := gPlayer2;
2712 plView2 := gPlayer1;
2713 end;
2714 end
2715 else
2716 if (gPlayer1 <> nil) or (gPlayer2 <> nil) then
2717 begin
2718 gSpectMode := SPECT_NONE;
2719 if gPlayer2 = nil then
2720 plView1 := gPlayer1
2721 else
2722 plView1 := gPlayer2;
2723 plView2 := nil;
2724 end
2725 else
2726 begin
2727 plView1 := nil;
2728 plView2 := nil;
2729 end;
2731 if (plView1 = nil) and (plView2 = nil) and (gSpectMode = SPECT_NONE) then
2732 gSpectMode := SPECT_STATS;
2734 if gSpectMode = SPECT_PLAYERS then
2735 if gPlayers <> nil then
2736 begin
2737 plView1 := GetActivePlayer_ByID(gSpectPID1);
2738 if plView1 = nil then
2739 begin
2740 gSpectPID1 := GetActivePlayerID_Next();
2741 plView1 := GetActivePlayer_ByID(gSpectPID1);
2742 end;
2743 if gSpectViewTwo then
2744 begin
2745 plView2 := GetActivePlayer_ByID(gSpectPID2);
2746 if plView2 = nil then
2747 begin
2748 gSpectPID2 := GetActivePlayerID_Next();
2749 plView2 := GetActivePlayer_ByID(gSpectPID2);
2750 end;
2751 end;
2752 end;
2754 if gSpectMode = SPECT_MAPVIEW then
2755 begin
2756 // Ðåæèì ïðîñìîòðà êàðòû
2757 Split := False;
2758 e_SetViewPort(0, 0, gScreenWidth, gScreenHeight);
2759 DrawMapView(gSpectX, gSpectY, gScreenWidth, gScreenHeight);
2760 gHearPoint1.Active := True;
2761 gHearPoint1.Coords.X := gScreenWidth div 2 + gSpectX;
2762 gHearPoint1.Coords.Y := gScreenHeight div 2 + gSpectY;
2763 gHearPoint2.Active := False;
2764 end
2765 else
2766 begin
2767 Split := (plView1 <> nil) and (plView2 <> nil);
2769 // Òî÷êè ñëóõà èãðîêîâ
2770 if plView1 <> nil then
2771 begin
2772 gHearPoint1.Active := True;
2773 gHearPoint1.Coords.X := plView1.GameX;
2774 gHearPoint1.Coords.Y := plView1.GameY;
2775 end else
2776 gHearPoint1.Active := False;
2777 if plView2 <> nil then
2778 begin
2779 gHearPoint2.Active := True;
2780 gHearPoint2.Coords.X := plView2.GameX;
2781 gHearPoint2.Coords.Y := plView2.GameY;
2782 end else
2783 gHearPoint2.Active := False;
2785 // Ðàçìåð ýêðàíîâ èãðîêîâ:
2786 gPlayerScreenSize.X := gScreenWidth-196;
2787 if Split then
2788 begin
2789 gPlayerScreenSize.Y := gScreenHeight div 2;
2790 if gScreenHeight mod 2 = 0 then
2791 Dec(gPlayerScreenSize.Y);
2792 end
2793 else
2794 gPlayerScreenSize.Y := gScreenHeight;
2796 if Split then
2797 if gScreenHeight mod 2 = 0 then
2798 e_SetViewPort(0, gPlayerScreenSize.Y+2, gPlayerScreenSize.X+196, gPlayerScreenSize.Y)
2799 else
2800 e_SetViewPort(0, gPlayerScreenSize.Y+1, gPlayerScreenSize.X+196, gPlayerScreenSize.Y);
2802 DrawPlayer(plView1);
2803 gPlayer1ScreenCoord.X := sX;
2804 gPlayer1ScreenCoord.Y := sY;
2806 if Split then
2807 begin
2808 e_SetViewPort(0, 0, gPlayerScreenSize.X+196, gPlayerScreenSize.Y);
2810 DrawPlayer(plView2);
2811 gPlayer2ScreenCoord.X := sX;
2812 gPlayer2ScreenCoord.Y := sY;
2813 end;
2815 e_SetViewPort(0, 0, gScreenWidth, gScreenHeight);
2817 if Split then
2818 e_DrawLine(2, 0, gScreenHeight div 2, gScreenWidth, gScreenHeight div 2, 0, 0, 0);
2819 end;
2821 if MessageText <> '' then
2822 begin
2823 w := 0;
2824 h := 0;
2825 e_CharFont_GetSizeFmt(gMenuFont, MessageText, w, h);
2826 if Split then
2827 e_CharFont_PrintFmt(gMenuFont, (gScreenWidth div 2)-(w div 2),
2828 (gScreenHeight div 2)-(h div 2), MessageText)
2829 else
2830 e_CharFont_PrintFmt(gMenuFont, (gScreenWidth div 2)-(w div 2),
2831 Round(gScreenHeight / 2.75)-(h div 2), MessageText);
2832 end;
2834 if IsDrawStat or (gSpectMode = 1) then DrawStat();
2836 if gSpectHUD and (not gChatShow) and (gSpectMode <> SPECT_NONE) then
2837 begin
2838 // Draw spectator GUI
2839 ww := 0;
2840 hh := 0;
2841 e_TextureFontGetSize(gStdFont, ww, hh);
2842 case gSpectMode of
2843 SPECT_STATS:
2844 e_TextureFontPrintEx(0, gScreenHeight - (hh+2)*2, 'MODE: Stats', gStdFont, 255, 255, 255, 1);
2845 SPECT_MAPVIEW:
2846 e_TextureFontPrintEx(0, gScreenHeight - (hh+2)*2, 'MODE: Observe Map', gStdFont, 255, 255, 255, 1);
2847 SPECT_PLAYERS:
2848 e_TextureFontPrintEx(0, gScreenHeight - (hh+2)*2, 'MODE: Watch Players', gStdFont, 255, 255, 255, 1);
2849 end;
2850 e_TextureFontPrintEx(2*ww, gScreenHeight - (hh+2), '< jump >', gStdFont, 255, 255, 255, 1);
2851 if gSpectMode = SPECT_MAPVIEW then
2852 begin
2853 e_TextureFontPrintEx(22*ww, gScreenHeight - (hh+2)*2, '[-]', gStdFont, 255, 255, 255, 1);
2854 e_TextureFontPrintEx(26*ww, gScreenHeight - (hh+2)*2, 'Step ' + IntToStr(gSpectStep), gStdFont, 255, 255, 255, 1);
2855 e_TextureFontPrintEx(34*ww, gScreenHeight - (hh+2)*2, '[+]', gStdFont, 255, 255, 255, 1);
2856 e_TextureFontPrintEx(18*ww, gScreenHeight - (hh+2), '<prev weap>', gStdFont, 255, 255, 255, 1);
2857 e_TextureFontPrintEx(30*ww, gScreenHeight - (hh+2), '<next weap>', gStdFont, 255, 255, 255, 1);
2858 end;
2859 if gSpectMode = SPECT_PLAYERS then
2860 begin
2861 e_TextureFontPrintEx(22*ww, gScreenHeight - (hh+2)*2, 'Player 1', gStdFont, 255, 255, 255, 1);
2862 e_TextureFontPrintEx(20*ww, gScreenHeight - (hh+2), '<left/right>', gStdFont, 255, 255, 255, 1);
2863 if gSpectViewTwo then
2864 begin
2865 e_TextureFontPrintEx(37*ww, gScreenHeight - (hh+2)*2, 'Player 2', gStdFont, 255, 255, 255, 1);
2866 e_TextureFontPrintEx(34*ww, gScreenHeight - (hh+2), '<prev w/next w>', gStdFont, 255, 255, 255, 1);
2867 e_TextureFontPrintEx(52*ww, gScreenHeight - (hh+2)*2, '2x View', gStdFont, 255, 255, 255, 1);
2868 e_TextureFontPrintEx(51*ww, gScreenHeight - (hh+2), '<up/down>', gStdFont, 255, 255, 255, 1);
2869 end
2870 else
2871 begin
2872 e_TextureFontPrintEx(35*ww, gScreenHeight - (hh+2)*2, '2x View', gStdFont, 255, 255, 255, 1);
2873 e_TextureFontPrintEx(34*ww, gScreenHeight - (hh+2), '<up/down>', gStdFont, 255, 255, 255, 1);
2874 end;
2875 end;
2876 end;
2877 end;
2879 if gPause and gGameOn and (g_ActiveWindow = nil) then
2880 begin
2881 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2883 e_CharFont_GetSize(gMenuFont, _lc[I_MENU_PAUSE], w, h);
2884 e_CharFont_Print(gMenuFont, (gScreenWidth div 2)-(w div 2),
2885 (gScreenHeight div 2)-(h div 2), _lc[I_MENU_PAUSE]);
2886 end;
2888 if not gGameOn then
2889 begin
2890 if (gState = STATE_MENU) then
2891 begin
2892 if ((g_ActiveWindow = nil) or (g_ActiveWindow.BackTexture = '')) then
2893 begin
2894 if g_Texture_Get('MENU_BACKGROUND', ID) then
2895 e_DrawSize(ID, 0, 0, 0, False, False, gScreenWidth, gScreenHeight)
2896 else e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
2897 end;
2898 if g_ActiveWindow <> nil then
2899 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2900 end;
2902 if gState = STATE_FOLD then
2903 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 0, 0, 0, EndingGameCounter);
2905 if gState = STATE_INTERCUSTOM then
2906 begin
2907 if gLastMap and (gGameSettings.GameMode = GM_COOP) then
2908 begin
2909 back := 'TEXTURE_endpic';
2910 if not g_Texture_Get(back, ID) then
2911 back := _lc[I_TEXTURE_ENDPIC];
2912 end
2913 else
2914 back := 'INTER';
2916 if g_Texture_Get(back, ID) then
2917 e_DrawSize(ID, 0, 0, 0, False, False, gScreenWidth, gScreenHeight)
2918 else
2919 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
2921 DrawCustomStat();
2923 if g_ActiveWindow <> nil then
2924 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2925 end;
2927 if gState = STATE_INTERSINGLE then
2928 begin
2929 if EndingGameCounter > 0 then
2930 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 0, 0, 0, EndingGameCounter)
2931 else
2932 begin
2933 back := 'INTER';
2935 if g_Texture_Get(back, ID) then
2936 e_DrawSize(ID, 0, 0, 0, False, False, gScreenWidth, gScreenHeight)
2937 else
2938 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
2940 DrawSingleStat();
2942 if g_ActiveWindow <> nil then
2943 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2944 end;
2945 end;
2947 if gState = STATE_ENDPIC then
2948 begin
2949 ID := DWORD(-1);
2950 if not g_Texture_Get('TEXTURE_endpic', ID) then
2951 g_Texture_Get(_lc[I_TEXTURE_ENDPIC], ID);
2953 if ID <> DWORD(-1) then
2954 e_DrawSize(ID, 0, 0, 0, False, False, gScreenWidth, gScreenHeight)
2955 else
2956 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
2958 if g_ActiveWindow <> nil then
2959 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2960 end;
2962 if gState = STATE_SLIST then
2963 begin
2964 if g_Texture_Get('MENU_BACKGROUND', ID) then
2965 begin
2966 e_DrawSize(ID, 0, 0, 0, False, False, gScreenWidth, gScreenHeight);
2967 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2968 end;
2969 g_Serverlist_Draw(slCurrent);
2970 end;
2971 end;
2973 if g_ActiveWindow <> nil then
2974 begin
2975 if gGameOn then
2976 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2977 g_ActiveWindow.Draw();
2978 end;
2980 g_Console_Draw();
2982 if g_debug_Sounds and gGameOn then
2983 begin
2984 for w := 0 to High(e_SoundsArray) do
2985 for h := 0 to e_SoundsArray[w].nRefs do
2986 e_DrawPoint(1, w+100, h+100, 255, 0, 0);
2987 end;
2989 if gShowFPS then
2990 begin
2991 e_TextureFontPrint(0, 0, Format('FPS: %d', [FPS]), gStdFont);
2992 e_TextureFontPrint(0, 16, Format('UPS: %d', [UPS]), gStdFont);
2993 end;
2995 if gGameOn and gShowTime and (gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT]) then
2996 e_TextureFontPrint(gScreenWidth-72, 0,
2997 Format('%d:%.2d:%.2d', [gTime div 1000 div 3600, (gTime div 1000 div 60) mod 60, gTime div 1000 mod 60]),
2998 gStdFont);
2999 end;
3001 procedure g_Game_Quit();
3002 begin
3003 g_Game_StopAllSounds(True);
3004 gMusic.Free();
3005 g_Game_SaveOptions();
3006 g_Game_FreeData();
3007 g_PlayerModel_FreeData();
3008 g_Texture_DeleteAll();
3009 g_Frames_DeleteAll();
3010 g_Menu_Free();
3012 if NetInitDone then g_Net_Free;
3014 // Íàäî óäàëèòü êàðòó ïîñëå òåñòà:
3015 if gMapToDelete <> '' then
3016 g_Game_DeleteTestMap();
3018 gExit := EXIT_QUIT;
3019 PushExitEvent();
3020 end;
3022 procedure g_FatalError(Text: String);
3023 begin
3024 g_Console_Add(Format(_lc[I_FATAL_ERROR], [Text]), True);
3025 e_WriteLog(Format(_lc[I_FATAL_ERROR], [Text]), MSG_WARNING);
3027 gExit := EXIT_SIMPLE;
3028 end;
3030 procedure g_SimpleError(Text: String);
3031 begin
3032 g_Console_Add(Format(_lc[I_SIMPLE_ERROR], [Text]), True);
3033 e_WriteLog(Format(_lc[I_SIMPLE_ERROR], [Text]), MSG_WARNING);
3034 end;
3036 procedure g_Game_SetupScreenSize();
3037 var
3038 d: Single;
3039 begin
3040 // Ðàçìåð ýêðàíîâ èãðîêîâ:
3041 gPlayerScreenSize.X := gScreenWidth-196;
3042 if (gPlayer1 <> nil) and (gPlayer2 <> nil) then
3043 gPlayerScreenSize.Y := gScreenHeight div 2
3044 else
3045 gPlayerScreenSize.Y := gScreenHeight;
3047 // Ðàçìåð çàäíåãî ïëàíà:
3048 if BackID <> DWORD(-1) then
3049 begin
3050 d := SKY_STRETCH;
3052 if (gScreenWidth*d > gMapInfo.Width) or
3053 (gScreenHeight*d > gMapInfo.Height) then
3054 d := 1.0;
3056 gBackSize.X := Round(gScreenWidth*d);
3057 gBackSize.Y := Round(gScreenHeight*d);
3058 end;
3059 end;
3061 procedure g_Game_ChangeResolution(newWidth, newHeight: Word; nowFull, nowMax: Boolean);
3062 begin
3063 g_Window_SetSize(newWidth, newHeight, nowFull);
3064 end;
3066 procedure g_Game_AddPlayer(Team: Byte = TEAM_NONE);
3067 begin
3068 if ((not gGameOn) and (gState <> STATE_INTERCUSTOM))
3069 or (not (gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT])) then
3070 Exit;
3071 if gPlayer1 = nil then
3072 begin
3073 if g_Game_IsClient then
3074 begin
3075 if NetPlrUID1 > -1 then
3076 begin
3077 MC_SEND_CheatRequest(NET_CHEAT_SPECTATE);
3078 gPlayer1 := g_Player_Get(NetPlrUID1);
3079 end;
3080 Exit;
3081 end;
3083 if not (Team in [TEAM_RED, TEAM_BLUE]) then
3084 Team := gPlayer1Settings.Team;
3086 // Ñîçäàíèå ïåðâîãî èãðîêà:
3087 gPlayer1 := g_Player_Get(g_Player_Create(gPlayer1Settings.Model,
3088 gPlayer1Settings.Color,
3089 Team, False));
3090 if gPlayer1 = nil then
3091 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [1]))
3092 else
3093 begin
3094 gPlayer1.Name := gPlayer1Settings.Name;
3095 g_Console_Add(Format(_lc[I_PLAYER_JOIN], [gPlayer1.Name]), True);
3096 if g_Game_IsServer and g_Game_IsNet then
3097 MH_SEND_PlayerCreate(gPlayer1.UID);
3098 gPlayer1.Respawn(False, True);
3100 if g_Game_IsNet and NetUseMaster then
3101 g_Net_Slist_Update;
3102 end;
3104 Exit;
3105 end;
3106 if gPlayer2 = nil then
3107 begin
3108 if g_Game_IsClient then
3109 begin
3110 if NetPlrUID2 > -1 then
3111 gPlayer2 := g_Player_Get(NetPlrUID2);
3112 Exit;
3113 end;
3115 if not (Team in [TEAM_RED, TEAM_BLUE]) then
3116 Team := gPlayer2Settings.Team;
3118 // Ñîçäàíèå âòîðîãî èãðîêà:
3119 gPlayer2 := g_Player_Get(g_Player_Create(gPlayer2Settings.Model,
3120 gPlayer2Settings.Color,
3121 Team, False));
3122 if gPlayer2 = nil then
3123 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [2]))
3124 else
3125 begin
3126 gPlayer2.Name := gPlayer2Settings.Name;
3127 g_Console_Add(Format(_lc[I_PLAYER_JOIN], [gPlayer2.Name]), True);
3128 if g_Game_IsServer and g_Game_IsNet then
3129 MH_SEND_PlayerCreate(gPlayer2.UID);
3130 gPlayer2.Respawn(False, True);
3132 if g_Game_IsNet and NetUseMaster then
3133 g_Net_Slist_Update;
3134 end;
3136 Exit;
3137 end;
3138 end;
3140 procedure g_Game_RemovePlayer();
3141 var
3142 Pl: TPlayer;
3143 begin
3144 if ((not gGameOn) and (gState <> STATE_INTERCUSTOM))
3145 or (not (gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT])) then
3146 Exit;
3147 Pl := gPlayer2;
3148 if Pl <> nil then
3149 begin
3150 if g_Game_IsServer then
3151 begin
3152 Pl.Lives := 0;
3153 Pl.Kill(K_SIMPLEKILL, 0, HIT_DISCON);
3154 g_Console_Add(Format(_lc[I_PLAYER_LEAVE], [Pl.Name]), True);
3155 g_Player_Remove(Pl.UID);
3157 if g_Game_IsNet and NetUseMaster then
3158 g_Net_Slist_Update;
3159 end else
3160 gPlayer2 := nil;
3161 Exit;
3162 end;
3163 Pl := gPlayer1;
3164 if Pl <> nil then
3165 begin
3166 if g_Game_IsServer then
3167 begin
3168 Pl.Lives := 0;
3169 Pl.Kill(K_SIMPLEKILL, 0, HIT_DISCON);
3170 g_Console_Add(Format(_lc[I_PLAYER_LEAVE], [Pl.Name]), True);
3171 g_Player_Remove(Pl.UID);
3173 if g_Game_IsNet and NetUseMaster then
3174 g_Net_Slist_Update;
3175 end else
3176 begin
3177 gPlayer1 := nil;
3178 MC_SEND_CheatRequest(NET_CHEAT_SPECTATE);
3179 end;
3180 Exit;
3181 end;
3182 end;
3184 procedure g_Game_Spectate();
3185 begin
3186 g_Game_RemovePlayer();
3187 if gPlayer1 <> nil then
3188 g_Game_RemovePlayer();
3189 end;
3191 procedure g_Game_SpectateCenterView();
3192 begin
3193 gSpectX := Max(gMapInfo.Width div 2 - gScreenWidth div 2, 0);
3194 gSpectY := Max(gMapInfo.Height div 2 - gScreenHeight div 2, 0);
3195 end;
3197 procedure g_Game_StartSingle(Map: String; TwoPlayers: Boolean; nPlayers: Byte);
3198 var
3199 i, nPl: Integer;
3200 begin
3201 g_Game_Free();
3203 e_WriteLog('Starting singleplayer game...', MSG_NOTIFY);
3205 g_Game_ClearLoading();
3207 // Íàñòðîéêè èãðû:
3208 FillByte(gGameSettings, SizeOf(TGameSettings), 0);
3209 gAimLine := False;
3210 gShowMap := False;
3211 gGameSettings.GameType := GT_SINGLE;
3212 gGameSettings.MaxLives := 0;
3213 gGameSettings.Options := gGameSettings.Options + GAME_OPTION_ALLOWEXIT;
3214 gGameSettings.Options := gGameSettings.Options + GAME_OPTION_MONSTERS;
3215 gGameSettings.Options := gGameSettings.Options + GAME_OPTION_BOTVSMONSTER;
3216 gSwitchGameMode := GM_SINGLE;
3218 g_Game_ExecuteEvent('ongamestart');
3220 // Óñòàíîâêà ðàçìåðîâ îêîí èãðîêîâ:
3221 g_Game_SetupScreenSize();
3223 // Ñîçäàíèå ïåðâîãî èãðîêà:
3224 gPlayer1 := g_Player_Get(g_Player_Create(gPlayer1Settings.Model,
3225 gPlayer1Settings.Color,
3226 gPlayer1Settings.Team, False));
3227 if gPlayer1 = nil then
3228 begin
3229 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [1]));
3230 Exit;
3231 end;
3233 gPlayer1.Name := gPlayer1Settings.Name;
3234 nPl := 1;
3236 // Ñîçäàíèå âòîðîãî èãðîêà, åñëè åñòü:
3237 if TwoPlayers then
3238 begin
3239 gPlayer2 := g_Player_Get(g_Player_Create(gPlayer2Settings.Model,
3240 gPlayer2Settings.Color,
3241 gPlayer2Settings.Team, False));
3242 if gPlayer2 = nil then
3243 begin
3244 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [2]));
3245 Exit;
3246 end;
3248 gPlayer2.Name := gPlayer2Settings.Name;
3249 Inc(nPl);
3250 end;
3252 // Çàãðóçêà è çàïóñê êàðòû:
3253 if not g_Game_StartMap(MAP, True) then
3254 begin
3255 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [gGameSettings.WAD + ':\' + MAP]));
3256 Exit;
3257 end;
3259 // Íàñòðîéêè èãðîêîâ è áîòîâ:
3260 g_Player_Init();
3262 // Ñîçäàåì áîòîâ:
3263 for i := nPl+1 to nPlayers do
3264 g_Player_Create(STD_PLAYER_MODEL, _RGB(0, 0, 0), 0, True);
3265 end;
3267 procedure g_Game_StartCustom(Map: String; GameMode: Byte;
3268 TimeLimit, GoalLimit: Word;
3269 MaxLives: Byte;
3270 Options: LongWord; nPlayers: Byte);
3271 var
3272 i, nPl: Integer;
3273 begin
3274 g_Game_Free();
3276 e_WriteLog('Starting custom game...', MSG_NOTIFY);
3278 g_Game_ClearLoading();
3280 // Íàñòðîéêè èãðû:
3281 gGameSettings.GameType := GT_CUSTOM;
3282 gGameSettings.GameMode := GameMode;
3283 gSwitchGameMode := GameMode;
3284 gGameSettings.TimeLimit := TimeLimit;
3285 gGameSettings.GoalLimit := GoalLimit;
3286 gGameSettings.MaxLives := IfThen(GameMode = GM_CTF, 0, MaxLives);
3287 gGameSettings.Options := Options;
3289 gCoopTotalMonstersKilled := 0;
3290 gCoopTotalSecretsFound := 0;
3291 gCoopTotalMonsters := 0;
3292 gCoopTotalSecrets := 0;
3293 gAimLine := False;
3294 gShowMap := False;
3296 g_Game_ExecuteEvent('ongamestart');
3298 // Óñòàíîâêà ðàçìåðîâ îêîí èãðîêîâ:
3299 g_Game_SetupScreenSize();
3301 // Ðåæèì íàáëþäàòåëÿ:
3302 if nPlayers = 0 then
3303 begin
3304 gPlayer1 := nil;
3305 gPlayer2 := nil;
3306 end;
3308 nPl := 0;
3309 if nPlayers >= 1 then
3310 begin
3311 // Ñîçäàíèå ïåðâîãî èãðîêà:
3312 gPlayer1 := g_Player_Get(g_Player_Create(gPlayer1Settings.Model,
3313 gPlayer1Settings.Color,
3314 gPlayer1Settings.Team, False));
3315 if gPlayer1 = nil then
3316 begin
3317 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [1]));
3318 Exit;
3319 end;
3321 gPlayer1.Name := gPlayer1Settings.Name;
3322 Inc(nPl);
3323 end;
3325 if nPlayers >= 2 then
3326 begin
3327 // Ñîçäàíèå âòîðîãî èãðîêà:
3328 gPlayer2 := g_Player_Get(g_Player_Create(gPlayer2Settings.Model,
3329 gPlayer2Settings.Color,
3330 gPlayer2Settings.Team, False));
3331 if gPlayer2 = nil then
3332 begin
3333 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [2]));
3334 Exit;
3335 end;
3337 gPlayer2.Name := gPlayer2Settings.Name;
3338 Inc(nPl);
3339 end;
3341 // Çàãðóçêà è çàïóñê êàðòû:
3342 if not g_Game_StartMap(Map, True) then
3343 begin
3344 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Map]));
3345 Exit;
3346 end;
3348 // Íåò òî÷åê ïîÿâëåíèÿ:
3349 if (g_Map_GetPointCount(RESPAWNPOINT_PLAYER1) +
3350 g_Map_GetPointCount(RESPAWNPOINT_PLAYER2) +
3351 g_Map_GetPointCount(RESPAWNPOINT_DM) +
3352 g_Map_GetPointCount(RESPAWNPOINT_RED)+
3353 g_Map_GetPointCount(RESPAWNPOINT_BLUE)) < 1 then
3354 begin
3355 g_FatalError(_lc[I_GAME_ERROR_GET_SPAWN]);
3356 Exit;
3357 end;
3359 // Íàñòðîéêè èãðîêîâ è áîòîâ:
3360 g_Player_Init();
3362 // Ñîçäàåì áîòîâ:
3363 for i := nPl+1 to nPlayers do
3364 g_Player_Create(STD_PLAYER_MODEL, _RGB(0, 0, 0), 0, True);
3365 end;
3367 procedure g_Game_StartServer(Map: String; GameMode: Byte;
3368 TimeLimit, GoalLimit: Word; MaxLives: Byte;
3369 Options: LongWord; nPlayers: Byte;
3370 IPAddr: LongWord; Port: Word);
3371 begin
3372 g_Game_Free();
3374 e_WriteLog('Starting net game (server)...', MSG_NOTIFY);
3376 g_Game_ClearLoading();
3378 // Íàñòðîéêè èãðû:
3379 gGameSettings.GameType := GT_SERVER;
3380 gGameSettings.GameMode := GameMode;
3381 gSwitchGameMode := GameMode;
3382 gGameSettings.TimeLimit := TimeLimit;
3383 gGameSettings.GoalLimit := GoalLimit;
3384 gGameSettings.MaxLives := IfThen(GameMode = GM_CTF, 0, MaxLives);
3385 gGameSettings.Options := Options;
3387 gCoopTotalMonstersKilled := 0;
3388 gCoopTotalSecretsFound := 0;
3389 gCoopTotalMonsters := 0;
3390 gCoopTotalSecrets := 0;
3391 gAimLine := False;
3392 gShowMap := False;
3394 g_Game_ExecuteEvent('ongamestart');
3396 // Óñòàíîâêà ðàçìåðîâ îêíà èãðîêà
3397 g_Game_SetupScreenSize();
3399 // Ðåæèì íàáëþäàòåëÿ:
3400 if nPlayers = 0 then
3401 begin
3402 gPlayer1 := nil;
3403 gPlayer2 := nil;
3404 end;
3406 if nPlayers >= 1 then
3407 begin
3408 // Ñîçäàíèå ïåðâîãî èãðîêà:
3409 gPlayer1 := g_Player_Get(g_Player_Create(gPlayer1Settings.Model,
3410 gPlayer1Settings.Color,
3411 gPlayer1Settings.Team, False));
3412 if gPlayer1 = nil then
3413 begin
3414 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [1]));
3415 Exit;
3416 end;
3418 gPlayer1.Name := gPlayer1Settings.Name;
3419 end;
3421 if nPlayers >= 2 then
3422 begin
3423 // Ñîçäàíèå âòîðîãî èãðîêà:
3424 gPlayer2 := g_Player_Get(g_Player_Create(gPlayer2Settings.Model,
3425 gPlayer2Settings.Color,
3426 gPlayer2Settings.Team, False));
3427 if gPlayer2 = nil then
3428 begin
3429 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [2]));
3430 Exit;
3431 end;
3433 gPlayer2.Name := gPlayer2Settings.Name;
3434 end;
3436 // Ñòàðòóåì ñåðâåð
3437 if not g_Net_Host(IPAddr, Port, NetMaxClients) then
3438 begin
3439 g_FatalError(_lc[I_NET_MSG] + _lc[I_NET_ERR_HOST]);
3440 Exit;
3441 end;
3443 g_Net_Slist_Set(NetSlistIP, NetSlistPort);
3445 // Çàãðóçêà è çàïóñê êàðòû:
3446 if not g_Game_StartMap(Map, True) then
3447 begin
3448 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Map]));
3449 Exit;
3450 end;
3452 // Íåò òî÷åê ïîÿâëåíèÿ:
3453 if (g_Map_GetPointCount(RESPAWNPOINT_PLAYER1) +
3454 g_Map_GetPointCount(RESPAWNPOINT_PLAYER2) +
3455 g_Map_GetPointCount(RESPAWNPOINT_DM) +
3456 g_Map_GetPointCount(RESPAWNPOINT_RED)+
3457 g_Map_GetPointCount(RESPAWNPOINT_BLUE)) < 1 then
3458 begin
3459 g_FatalError(_lc[I_GAME_ERROR_GET_SPAWN]);
3460 Exit;
3461 end;
3463 // Íàñòðîéêè èãðîêîâ è áîòîâ:
3464 g_Player_Init();
3466 NetState := NET_STATE_GAME;
3467 end;
3469 procedure g_Game_StartClient(Addr: String; Port: Word; PW: String);
3470 var
3471 Map: String;
3472 WadName: string;
3473 Ptr: Pointer;
3474 T: Cardinal;
3475 MID: Byte;
3476 State: Byte;
3477 OuterLoop: Boolean;
3478 newResPath: string;
3479 begin
3480 g_Game_Free();
3482 State := 0;
3483 e_WriteLog('Starting net game (client)...', MSG_NOTIFY);
3484 e_WriteLog('NET: Trying to connect to ' + Addr + ':' + IntToStr(Port) + '...', MSG_NOTIFY);
3486 g_Game_ClearLoading();
3488 // Íàñòðîéêè èãðû:
3489 gGameSettings.GameType := GT_CLIENT;
3491 gCoopTotalMonstersKilled := 0;
3492 gCoopTotalSecretsFound := 0;
3493 gCoopTotalMonsters := 0;
3494 gCoopTotalSecrets := 0;
3495 gAimLine := False;
3496 gShowMap := False;
3498 g_Game_ExecuteEvent('ongamestart');
3500 // Óñòàíîâêà ðàçìåðîâ îêîí èãðîêîâ:
3501 g_Game_SetupScreenSize();
3503 NetState := NET_STATE_AUTH;
3505 g_Game_SetLoadingText(_lc[I_LOAD_CONNECT], 0, False);
3506 // Ñòàðòóåì êëèåíò
3507 if not g_Net_Connect(Addr, Port) then
3508 begin
3509 g_FatalError(_lc[I_NET_MSG] + _lc[I_NET_ERR_CONN]);
3510 NetState := NET_STATE_NONE;
3511 Exit;
3512 end;
3514 g_Game_SetLoadingText(_lc[I_LOAD_SEND_INFO], 0, False);
3515 MC_SEND_Info(PW);
3516 g_Game_SetLoadingText(_lc[I_LOAD_WAIT_INFO], 0, False);
3518 OuterLoop := True;
3519 while OuterLoop do
3520 begin
3521 while (enet_host_service(NetHost, @NetEvent, 0) > 0) do
3522 begin
3523 if (NetEvent.kind = ENET_EVENT_TYPE_RECEIVE) then
3524 begin
3525 Ptr := NetEvent.packet^.data;
3526 e_Raw_Seek(0);
3528 MID := e_Raw_Read_Byte(Ptr);
3530 if (MID = NET_MSG_INFO) and (State = 0) then
3531 begin
3532 NetMyID := e_Raw_Read_Byte(Ptr);
3533 NetPlrUID1 := e_Raw_Read_Word(Ptr);
3535 WadName := e_Raw_Read_String(Ptr);
3536 Map := e_Raw_Read_String(Ptr);
3538 gWADHash := e_Raw_Read_MD5(Ptr);
3540 gGameSettings.GameMode := e_Raw_Read_Byte(Ptr);
3541 gSwitchGameMode := gGameSettings.GameMode;
3542 gGameSettings.GoalLimit := e_Raw_Read_Word(Ptr);
3543 gGameSettings.TimeLimit := e_Raw_Read_Word(Ptr);
3544 gGameSettings.MaxLives := e_Raw_Read_Byte(Ptr);
3545 gGameSettings.Options := e_Raw_Read_LongWord(Ptr);
3546 T := e_Raw_Read_LongWord(Ptr);
3548 newResPath := g_Res_SearchSameWAD(MapsDir, WadName, gWADHash);
3549 if newResPath = '' then
3550 begin
3551 g_Game_SetLoadingText(_lc[I_LOAD_DL_RES], 0, False);
3552 newResPath := g_Res_DownloadWAD(WadName);
3553 if newResPath = '' then
3554 begin
3555 g_FatalError(_lc[I_NET_ERR_HASH]);
3556 enet_packet_destroy(NetEvent.packet);
3557 NetState := NET_STATE_NONE;
3558 Exit;
3559 end;
3560 end;
3561 newResPath := ExtractRelativePath(MapsDir, newResPath);
3563 gPlayer1 := g_Player_Get(g_Player_Create(gPlayer1Settings.Model,
3564 gPlayer1Settings.Color,
3565 gPlayer1Settings.Team, False));
3567 if gPlayer1 = nil then
3568 begin
3569 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [1]));
3571 enet_packet_destroy(NetEvent.packet);
3572 NetState := NET_STATE_NONE;
3573 Exit;
3574 end;
3576 gPlayer1.Name := gPlayer1Settings.Name;
3577 gPlayer1.UID := NetPlrUID1;
3578 gPlayer1.Reset(True);
3580 if not g_Game_StartMap(newResPath + ':\' + Map, True) then
3581 begin
3582 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [WadName + ':\' + Map]));
3584 enet_packet_destroy(NetEvent.packet);
3585 NetState := NET_STATE_NONE;
3586 Exit;
3587 end;
3589 gTime := T;
3591 State := 1;
3592 OuterLoop := False;
3593 enet_packet_destroy(NetEvent.packet);
3594 break;
3595 end
3596 else
3597 enet_packet_destroy(NetEvent.packet);
3598 end
3599 else
3600 if (NetEvent.kind = ENET_EVENT_TYPE_DISCONNECT) then
3601 begin
3602 State := 0;
3603 if (NetEvent.data <= NET_DISC_MAX) then
3604 g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_ERR_CONN] + ' ' +
3605 _lc[TStrings_Locale(Cardinal(I_NET_DISC_NONE) + NetEvent.data)], True);
3606 OuterLoop := False;
3607 Break;
3608 end;
3609 end;
3611 ProcessLoading();
3613 e_PollInput();
3615 if e_KeyPressed(IK_ESCAPE) or e_KeyPressed(IK_SPACE) then
3616 begin
3617 State := 0;
3618 break;
3619 end;
3620 end;
3622 if State <> 1 then
3623 begin
3624 g_FatalError(_lc[I_NET_MSG] + _lc[I_NET_ERR_CONN]);
3625 NetState := NET_STATE_NONE;
3626 Exit;
3627 end;
3629 gLMSRespawn := LMS_RESPAWN_NONE;
3630 gLMSRespawnTime := 0;
3632 g_Player_Init();
3633 NetState := NET_STATE_GAME;
3634 MC_SEND_FullStateRequest;
3635 e_WriteLog('NET: Connection successful.', MSG_NOTIFY);
3636 end;
3638 procedure g_Game_SaveOptions();
3639 begin
3640 g_Options_Write_Video(GameDir+'/'+CONFIG_FILENAME);
3641 end;
3643 procedure g_Game_ChangeMap(MapPath: String);
3644 var
3645 Force: Boolean;
3646 begin
3647 g_Game_ClearLoading();
3649 Force := gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF];
3650 // Åñëè óðîâåíü çàâåðøèëñÿ ïî òðèããåðó Âûõîä, íå î÷èùàòü èíâåíòàðü
3651 if gExitByTrigger then
3652 begin
3653 Force := False;
3654 gExitByTrigger := False;
3655 end;
3656 if not g_Game_StartMap(MapPath, Force) then
3657 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [MapPath]));
3658 end;
3660 procedure g_Game_Restart();
3661 var
3662 Map: string;
3663 begin
3664 if g_Game_IsClient then
3665 Exit;
3666 map := g_ExtractFileName(gMapInfo.Map);
3668 MessageTime := 0;
3669 gGameOn := False;
3670 g_Game_ClearLoading();
3671 g_Game_StartMap(Map, True);
3672 end;
3674 function g_Game_StartMap(Map: String; Force: Boolean = False): Boolean;
3675 var
3676 NewWAD, ResName: String;
3677 I: Integer;
3678 begin
3679 g_Map_Free();
3680 g_Player_RemoveAllCorpses();
3682 if (not g_Game_IsClient) and
3683 (gSwitchGameMode <> gGameSettings.GameMode) and
3684 (gGameSettings.GameMode <> GM_SINGLE) then
3685 begin
3686 if gSwitchGameMode = GM_CTF then
3687 gGameSettings.MaxLives := 0;
3688 gGameSettings.GameMode := gSwitchGameMode;
3689 Force := True;
3690 end else
3691 gSwitchGameMode := gGameSettings.GameMode;
3693 g_Player_ResetTeams();
3695 if Pos(':\', Map) > 0 then
3696 begin
3697 NewWAD := g_ExtractWadName(Map);
3698 ResName := g_ExtractFileName(Map);
3699 if g_Game_IsServer then
3700 begin
3701 gWADHash := MD5File(MapsDir + NewWAD);
3702 g_Game_LoadWAD(NewWAD);
3703 end else
3704 // hash recieved in MC_RECV_GameEvent -> NET_EV_MAPSTART
3705 g_Game_ClientWAD(NewWAD, gWADHash);
3706 end else
3707 ResName := Map;
3709 Result := g_Map_Load(MapsDir + gGameSettings.WAD + ':\' + ResName);
3710 if Result then
3711 begin
3712 g_Player_ResetAll(Force or gLastMap, gGameSettings.GameType = GT_SINGLE);
3714 gState := STATE_NONE;
3715 g_ActiveWindow := nil;
3716 gGameOn := True;
3718 DisableCheats();
3719 ResetTimer();
3721 if gGameSettings.GameMode = GM_CTF then
3722 begin
3723 g_Map_ResetFlag(FLAG_RED);
3724 g_Map_ResetFlag(FLAG_BLUE);
3725 // CTF, à ôëàãîâ íåò:
3726 if not g_Map_HaveFlagPoints() then
3727 g_SimpleError(_lc[I_GAME_ERROR_CTF]);
3728 end;
3729 end
3730 else
3731 begin
3732 gState := STATE_MENU;
3733 gGameOn := False;
3734 end;
3736 gExit := 0;
3737 gPause := False;
3738 gTime := 0;
3739 NetTimeToUpdate := 1;
3740 NetTimeToReliable := 0;
3741 NetTimeToMaster := NetMasterRate;
3742 gLMSRespawn := LMS_RESPAWN_NONE;
3743 gLMSRespawnTime := 0;
3744 gMissionFailed := False;
3745 gNextMap := '';
3747 gCoopMonstersKilled := 0;
3748 gCoopSecretsFound := 0;
3750 gVoteInProgress := False;
3751 gVotePassed := False;
3752 gVoteCount := 0;
3753 gVoted := False;
3755 gStatsOff := False;
3757 if not gGameOn then Exit;
3759 g_Game_SpectateCenterView();
3761 if (gGameSettings.MaxLives > 0) and (gGameSettings.WarmupTime > 0) then
3762 begin
3763 gLMSRespawn := LMS_RESPAWN_WARMUP;
3764 gLMSRespawnTime := gTime + gGameSettings.WarmupTime*1000;
3765 gLMSSoftSpawn := True;
3766 if NetMode = NET_SERVER then
3767 MH_SEND_GameEvent(NET_EV_LMS_WARMUP, (gLMSRespawnTime - gTime) div 1000)
3768 else
3769 g_Console_Add(Format(_lc[I_MSG_WARMUP_START], [(gLMSRespawnTime - gTime) div 1000]), True);
3770 end;
3772 if NetMode = NET_SERVER then
3773 begin
3774 MH_SEND_GameEvent(NET_EV_MAPSTART, gGameSettings.GameMode, Map);
3776 // Ìàñòåðñåðâåð
3777 if NetUseMaster then
3778 begin
3779 if (NetMHost = nil) or (NetMPeer = nil) then
3780 if not g_Net_Slist_Connect then
3781 g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_SLIST_ERROR]);
3783 g_Net_Slist_Update;
3784 end;
3786 if NetClients <> nil then
3787 for I := 0 to High(NetClients) do
3788 if NetClients[I].Used then
3789 begin
3790 NetClients[I].Voted := False;
3791 if NetClients[I].RequestedFullUpdate then
3792 begin
3793 MH_SEND_Everything((NetClients[I].State = NET_STATE_AUTH), I);
3794 NetClients[I].RequestedFullUpdate := False;
3795 end;
3796 end;
3798 g_Net_UnbanNonPermHosts();
3799 end;
3801 if gLastMap then
3802 begin
3803 gCoopTotalMonstersKilled := 0;
3804 gCoopTotalSecretsFound := 0;
3805 gCoopTotalMonsters := 0;
3806 gCoopTotalSecrets := 0;
3807 gLastMap := False;
3808 end;
3810 g_Game_ExecuteEvent('onmapstart');
3811 end;
3813 procedure SetFirstLevel();
3814 begin
3815 gNextMap := '';
3817 MapList := g_Map_GetMapsList(MapsDir + gGameSettings.WAD);
3818 if MapList = nil then
3819 Exit;
3821 SortSArray(MapList);
3822 gNextMap := MapList[Low(MapList)];
3824 MapList := nil;
3825 end;
3827 procedure g_Game_ExitLevel(Map: Char16);
3828 begin
3829 gNextMap := Map;
3831 gCoopTotalMonstersKilled := gCoopTotalMonstersKilled + gCoopMonstersKilled;
3832 gCoopTotalSecretsFound := gCoopTotalSecretsFound + gCoopSecretsFound;
3833 gCoopTotalMonsters := gCoopTotalMonsters + gTotalMonsters;
3834 gCoopTotalSecrets := gCoopTotalSecrets + gSecretsCount;
3836 // Âûøëè â âûõîä â Îäèíî÷íîé èãðå:
3837 if gGameSettings.GameType = GT_SINGLE then
3838 gExit := EXIT_ENDLEVELSINGLE
3839 else // Âûøëè â âûõîä â Ñâîåé èãðå
3840 begin
3841 gExit := EXIT_ENDLEVELCUSTOM;
3842 if gGameSettings.GameMode = GM_COOP then
3843 g_Player_RememberAll;
3845 if not g_Map_Exist(MapsDir + gGameSettings.WAD + ':\' + gNextMap) then
3846 begin
3847 gLastMap := True;
3848 if gGameSettings.GameMode = GM_COOP then
3849 gStatsOff := True;
3851 gStatsPressed := True;
3852 gNextMap := 'MAP01';
3854 if not g_Map_Exist(MapsDir + gGameSettings.WAD + ':\' + gNextMap) then
3855 g_Game_NextLevel;
3857 if g_Game_IsNet then
3858 begin
3859 MH_SEND_GameStats();
3860 MH_SEND_CoopStats();
3861 end;
3862 end;
3863 end;
3864 end;
3866 procedure g_Game_RestartLevel();
3867 var
3868 Map: string;
3869 begin
3870 if gGameSettings.GameMode = GM_SINGLE then
3871 begin
3872 g_Game_Restart();
3873 Exit;
3874 end;
3875 gExit := EXIT_ENDLEVELCUSTOM;
3876 Map := g_ExtractFileName(gMapInfo.Map);
3877 gNextMap := Map;
3878 end;
3880 procedure g_Game_ClientWAD(NewWAD: String; WHash: TMD5Digest);
3881 var
3882 gWAD: String;
3883 begin
3884 if LowerCase(NewWAD) = LowerCase(gGameSettings.WAD) then
3885 Exit;
3886 if not g_Game_IsClient then
3887 Exit;
3888 gWAD := g_Res_SearchSameWAD(MapsDir, ExtractFileName(NewWAD), WHash);
3889 if gWAD = '' then
3890 begin
3891 g_Game_SetLoadingText(_lc[I_LOAD_DL_RES], 0, False);
3892 gWAD := g_Res_DownloadWAD(ExtractFileName(NewWAD));
3893 if gWAD = '' then
3894 begin
3895 g_Game_Free();
3896 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_WAD], [ExtractFileName(NewWAD)]));
3897 Exit;
3898 end;
3899 end;
3900 NewWAD := ExtractRelativePath(MapsDir, gWAD);
3901 g_Game_LoadWAD(NewWAD);
3902 end;
3904 procedure g_Game_RestartRound(NoMapRestart: Boolean = False);
3905 var
3906 i, n, nb, nr: Integer;
3907 begin
3908 if not g_Game_IsServer then Exit;
3909 if gLMSRespawn = LMS_RESPAWN_NONE then Exit;
3910 gLMSRespawn := LMS_RESPAWN_NONE;
3911 gLMSRespawnTime := 0;
3912 MessageTime := 0;
3914 if (gGameSettings.GameMode = GM_COOP) and not NoMapRestart then
3915 begin
3916 gMissionFailed := True;
3917 g_Game_RestartLevel;
3918 Exit;
3919 end;
3921 n := 0; nb := 0; nr := 0;
3922 for i := Low(gPlayers) to High(gPlayers) do
3923 if (gPlayers[i] <> nil) and
3924 ((not gPlayers[i].FSpectator) or gPlayers[i].FWantsInGame or
3925 (gPlayers[i] is TBot)) then
3926 begin
3927 Inc(n);
3928 if gPlayers[i].Team = TEAM_RED then Inc(nr)
3929 else if gPlayers[i].Team = TEAM_BLUE then Inc(nb)
3930 end;
3932 if (n < 2) or ((gGameSettings.GameMode = GM_TDM) and ((nr = 0) or (nb = 0))) then
3933 begin
3934 // wait a second until the fuckers finally decide to join
3935 gLMSRespawn := LMS_RESPAWN_WARMUP;
3936 gLMSRespawnTime := gTime + 1000;
3937 gLMSSoftSpawn := NoMapRestart;
3938 Exit;
3939 end;
3941 g_Player_RemoveAllCorpses;
3942 g_Game_Message(_lc[I_MESSAGE_LMS_START], 144);
3943 if g_Game_IsNet then
3944 MH_SEND_GameEvent(NET_EV_LMS_START);
3946 for i := Low(gPlayers) to High(gPlayers) do
3947 begin
3948 if gPlayers[i] = nil then continue;
3949 if gPlayers[i] is TBot then gPlayers[i].FWantsInGame := True;
3950 // don't touch normal spectators
3951 if gPlayers[i].FSpectator and not gPlayers[i].FWantsInGame then
3952 begin
3953 gPlayers[i].FNoRespawn := True;
3954 gPlayers[i].Lives := 0;
3955 if g_Game_IsNet then
3956 MH_SEND_PlayerStats(gPlayers[I].UID);
3957 continue;
3958 end;
3959 gPlayers[i].FNoRespawn := False;
3960 gPlayers[i].Lives := gGameSettings.MaxLives;
3961 gPlayers[i].Respawn(False, True);
3962 if gGameSettings.GameMode = GM_COOP then
3963 begin
3964 gPlayers[i].Frags := 0;
3965 gPlayers[i].RecallState;
3966 end;
3967 if (gPlayer1 = nil) and (gLMSPID1 > 0) then
3968 gPlayer1 := g_Player_Get(gLMSPID1);
3969 if (gPlayer2 = nil) and (gLMSPID2 > 0) then
3970 gPlayer2 := g_Player_Get(gLMSPID2);
3971 end;
3973 for i := Low(gItems) to High(gItems) do
3974 begin
3975 if gItems[i].Respawnable then
3976 begin
3977 gItems[i].QuietRespawn := True;
3978 gItems[i].RespawnTime := 0;
3979 end
3980 else
3981 begin
3982 g_Items_Remove(i);
3983 if g_Game_IsNet then MH_SEND_ItemDestroy(True, i);
3984 end;
3985 end;
3987 for i := Low(gMonsters) to High(gMonsters) do
3988 begin
3989 if (gMonsters[i] <> nil) and not gMonsters[i].FNoRespawn then
3990 gMonsters[i].Respawn;
3991 end;
3993 gLMSSoftSpawn := False;
3994 end;
3996 function g_Game_GetFirstMap(WAD: String): String;
3997 begin
3998 Result := '';
4000 MapList := g_Map_GetMapsList(WAD);
4001 if MapList = nil then
4002 Exit;
4004 SortSArray(MapList);
4005 Result := MapList[Low(MapList)];
4007 if not g_Map_Exist(WAD + ':\' + Result) then
4008 Result := '';
4010 MapList := nil;
4011 end;
4013 function g_Game_GetNextMap(): String;
4014 var
4015 I: Integer;
4016 Map: string;
4017 begin
4018 Result := '';
4020 MapList := g_Map_GetMapsList(MapsDir + gGameSettings.WAD);
4021 if MapList = nil then
4022 Exit;
4024 Map := g_ExtractFileName(gMapInfo.Map);
4026 SortSArray(MapList);
4027 MapIndex := -255;
4028 for I := Low(MapList) to High(MapList) do
4029 if Map = MapList[I] then
4030 begin
4031 MapIndex := I;
4032 Break;
4033 end;
4035 if MapIndex <> -255 then
4036 begin
4037 if MapIndex = High(MapList) then
4038 Result := MapList[Low(MapList)]
4039 else
4040 Result := MapList[MapIndex + 1];
4042 if not g_Map_Exist(MapsDir + gGameSettings.WAD + ':\' + Result) then Result := Map;
4043 end;
4045 MapList := nil;
4046 end;
4048 procedure g_Game_NextLevel();
4049 begin
4050 if gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF, GM_COOP] then
4051 gExit := EXIT_ENDLEVELCUSTOM
4052 else
4053 begin
4054 gExit := EXIT_ENDLEVELSINGLE;
4055 Exit;
4056 end;
4058 if gNextMap <> '' then Exit;
4059 gNextMap := g_Game_GetNextMap();
4060 end;
4062 function g_Game_IsTestMap(): Boolean;
4063 begin
4064 result := StrEquCI1251(TEST_MAP_NAME, g_ExtractFileName(gMapInfo.Map));
4065 end;
4067 procedure g_Game_DeleteTestMap();
4068 var
4069 a: Integer;
4070 MapName: Char16;
4071 WadName: string;
4073 WAD: TWADFile;
4074 MapList: SArray;
4075 time: Integer;
4077 begin
4078 a := Pos('.wad:\', gMapToDelete);
4079 if a = 0 then
4080 Exit;
4082 // Âûäåëÿåì èìÿ wad-ôàéëà è èìÿ êàðòû:
4083 WadName := Copy(gMapToDelete, 1, a + 3);
4084 Delete(gMapToDelete, 1, a + 5);
4085 gMapToDelete := UpperCase(gMapToDelete);
4086 MapName := '';
4087 CopyMemory(@MapName[0], @gMapToDelete[1], Min(16, Length(gMapToDelete)));
4090 // Èìÿ êàðòû íå ñòàíäàðòíîå òåñòîâîå:
4091 if MapName <> TEST_MAP_NAME then
4092 Exit;
4094 if not gTempDelete then
4095 begin
4096 time := g_GetFileTime(WadName);
4097 WAD := TWADFile.Create();
4099 // ×èòàåì Wad-ôàéë:
4100 if not WAD.ReadFile(WadName) then
4101 begin // Íåò òàêîãî WAD-ôàéëà
4102 WAD.Free();
4103 Exit;
4104 end;
4106 // Ñîñòàâëÿåì ñïèñîê êàðò è èùåì íóæíóþ:
4107 WAD.CreateImage();
4108 MapList := WAD.GetResourcesList('');
4110 if MapList <> nil then
4111 for a := 0 to High(MapList) do
4112 if MapList[a] = MapName then
4113 begin
4114 // Óäàëÿåì è ñîõðàíÿåì:
4115 WAD.RemoveResource('', MapName);
4116 WAD.SaveTo(WadName);
4117 Break;
4118 end;
4120 WAD.Free();
4121 g_SetFileTime(WadName, time);
4122 end else
4124 if gTempDelete then DeleteFile(WadName);
4125 end;
4127 procedure GameCVars(P: SArray);
4128 var
4129 a, b: Integer;
4130 stat: TPlayerStatArray;
4131 cmd, s: string;
4132 config: TConfig;
4133 begin
4134 stat := nil;
4135 cmd := LowerCase(P[0]);
4136 if cmd = 'r_showfps' then
4137 begin
4138 if (Length(P) > 1) and
4139 ((P[1] = '1') or (P[1] = '0')) then
4140 gShowFPS := (P[1][1] = '1');
4142 if gShowFPS then
4143 g_Console_Add(_lc[I_MSG_SHOW_FPS_ON])
4144 else
4145 g_Console_Add(_lc[I_MSG_SHOW_FPS_OFF]);
4146 end
4147 else if (cmd = 'g_friendlyfire') and not g_Game_IsClient then
4148 begin
4149 with gGameSettings do
4150 begin
4151 if (Length(P) > 1) and
4152 ((P[1] = '1') or (P[1] = '0')) then
4153 begin
4154 if (P[1][1] = '1') then
4155 Options := Options or GAME_OPTION_TEAMDAMAGE
4156 else
4157 Options := Options and (not GAME_OPTION_TEAMDAMAGE);
4158 end;
4160 if (LongBool(Options and GAME_OPTION_TEAMDAMAGE)) then
4161 g_Console_Add(_lc[I_MSG_FRIENDLY_FIRE_ON])
4162 else
4163 g_Console_Add(_lc[I_MSG_FRIENDLY_FIRE_OFF]);
4165 if g_Game_IsNet then MH_SEND_GameSettings;
4166 end;
4167 end
4168 else if (cmd = 'g_weaponstay') and not g_Game_IsClient then
4169 begin
4170 with gGameSettings do
4171 begin
4172 if (Length(P) > 1) and
4173 ((P[1] = '1') or (P[1] = '0')) then
4174 begin
4175 if (P[1][1] = '1') then
4176 Options := Options or GAME_OPTION_WEAPONSTAY
4177 else
4178 Options := Options and (not GAME_OPTION_WEAPONSTAY);
4179 end;
4181 if (LongBool(Options and GAME_OPTION_WEAPONSTAY)) then
4182 g_Console_Add(_lc[I_MSG_WEAPONSTAY_ON])
4183 else
4184 g_Console_Add(_lc[I_MSG_WEAPONSTAY_OFF]);
4186 if g_Game_IsNet then MH_SEND_GameSettings;
4187 end;
4188 end
4189 else if cmd = 'g_gamemode' then
4190 begin
4191 a := g_Game_TextToMode(P[1]);
4192 if a = GM_SINGLE then a := GM_COOP;
4193 if (Length(P) > 1) and (a <> GM_NONE) and (not g_Game_IsClient) then
4194 begin
4195 gSwitchGameMode := a;
4196 if (gGameOn and (gGameSettings.GameMode = GM_SINGLE)) or
4197 (gState = STATE_INTERSINGLE) then
4198 gSwitchGameMode := GM_SINGLE;
4199 if not gGameOn then
4200 gGameSettings.GameMode := gSwitchGameMode;
4201 end;
4202 if gSwitchGameMode = gGameSettings.GameMode then
4203 g_Console_Add(Format(_lc[I_MSG_GAMEMODE_CURRENT],
4204 [g_Game_ModeToText(gGameSettings.GameMode)]))
4205 else
4206 g_Console_Add(Format(_lc[I_MSG_GAMEMODE_CHANGE],
4207 [g_Game_ModeToText(gGameSettings.GameMode),
4208 g_Game_ModeToText(gSwitchGameMode)]));
4209 end
4210 else if (cmd = 'g_allow_exit') and not g_Game_IsClient then
4211 begin
4212 with gGameSettings do
4213 begin
4214 if (Length(P) > 1) and
4215 ((P[1] = '1') or (P[1] = '0')) then
4216 begin
4217 if (P[1][1] = '1') then
4218 Options := Options or GAME_OPTION_ALLOWEXIT
4219 else
4220 Options := Options and (not GAME_OPTION_ALLOWEXIT);
4221 end;
4223 if (LongBool(Options and GAME_OPTION_ALLOWEXIT)) then
4224 g_Console_Add(_lc[I_MSG_ALLOWEXIT_ON])
4225 else
4226 g_Console_Add(_lc[I_MSG_ALLOWEXIT_OFF]);
4227 g_Console_Add(_lc[I_MSG_ONMAPCHANGE]);
4229 if g_Game_IsNet then MH_SEND_GameSettings;
4230 end;
4231 end
4232 else if (cmd = 'g_allow_monsters') and not g_Game_IsClient then
4233 begin
4234 with gGameSettings do
4235 begin
4236 if (Length(P) > 1) and
4237 ((P[1] = '1') or (P[1] = '0')) then
4238 begin
4239 if (P[1][1] = '1') then
4240 Options := Options or GAME_OPTION_MONSTERS
4241 else
4242 Options := Options and (not GAME_OPTION_MONSTERS);
4243 end;
4245 if (LongBool(Options and GAME_OPTION_MONSTERS)) then
4246 g_Console_Add(_lc[I_MSG_ALLOWMON_ON])
4247 else
4248 g_Console_Add(_lc[I_MSG_ALLOWMON_OFF]);
4249 g_Console_Add(_lc[I_MSG_ONMAPCHANGE]);
4251 if g_Game_IsNet then MH_SEND_GameSettings;
4252 end;
4253 end
4254 else if (cmd = 'g_bot_vsplayers') and not g_Game_IsClient then
4255 begin
4256 with gGameSettings do
4257 begin
4258 if (Length(P) > 1) and
4259 ((P[1] = '1') or (P[1] = '0')) then
4260 begin
4261 if (P[1][1] = '1') then
4262 Options := Options or GAME_OPTION_BOTVSPLAYER
4263 else
4264 Options := Options and (not GAME_OPTION_BOTVSPLAYER);
4265 end;
4267 if (LongBool(Options and GAME_OPTION_BOTVSPLAYER)) then
4268 g_Console_Add(_lc[I_MSG_BOTSVSPLAYERS_ON])
4269 else
4270 g_Console_Add(_lc[I_MSG_BOTSVSPLAYERS_OFF]);
4272 if g_Game_IsNet then MH_SEND_GameSettings;
4273 end;
4274 end
4275 else if (cmd = 'g_bot_vsmonsters') and not g_Game_IsClient then
4276 begin
4277 with gGameSettings do
4278 begin
4279 if (Length(P) > 1) and
4280 ((P[1] = '1') or (P[1] = '0')) then
4281 begin
4282 if (P[1][1] = '1') then
4283 Options := Options or GAME_OPTION_BOTVSMONSTER
4284 else
4285 Options := Options and (not GAME_OPTION_BOTVSMONSTER);
4286 end;
4288 if (LongBool(Options and GAME_OPTION_BOTVSMONSTER)) then
4289 g_Console_Add(_lc[I_MSG_BOTSVSMONSTERS_ON])
4290 else
4291 g_Console_Add(_lc[I_MSG_BOTSVSMONSTERS_OFF]);
4293 if g_Game_IsNet then MH_SEND_GameSettings;
4294 end;
4295 end
4296 else if (cmd = 'g_warmuptime') and not g_Game_IsClient then
4297 begin
4298 if Length(P) > 1 then
4299 begin
4300 if StrToIntDef(P[1], gGameSettings.WarmupTime) = 0 then
4301 gGameSettings.WarmupTime := 30
4302 else
4303 gGameSettings.WarmupTime := StrToIntDef(P[1], gGameSettings.WarmupTime);
4304 end;
4306 g_Console_Add(Format(_lc[I_MSG_WARMUP],
4307 [gGameSettings.WarmupTime]));
4308 g_Console_Add(_lc[I_MSG_ONMAPCHANGE]);
4309 end
4310 else if cmd = 'net_interp' then
4311 begin
4312 if (Length(P) > 1) then
4313 NetInterpLevel := StrToIntDef(P[1], NetInterpLevel);
4315 g_Console_Add('net_interp = ' + IntToStr(NetInterpLevel));
4316 config := TConfig.CreateFile(GameDir+'/'+CONFIG_FILENAME);
4317 config.WriteInt('Client', 'InterpolationSteps', NetInterpLevel);
4318 config.SaveFile(GameDir+'/'+CONFIG_FILENAME);
4319 config.Free();
4320 end
4321 else if cmd = 'net_forceplayerupdate' then
4322 begin
4323 if (Length(P) > 1) and
4324 ((P[1] = '1') or (P[1] = '0')) then
4325 NetForcePlayerUpdate := (P[1][1] = '1');
4327 if NetForcePlayerUpdate then
4328 g_Console_Add('net_forceplayerupdate = 1')
4329 else
4330 g_Console_Add('net_forceplayerupdate = 0');
4331 config := TConfig.CreateFile(GameDir+'/'+CONFIG_FILENAME);
4332 config.WriteBool('Client', 'ForcePlayerUpdate', NetForcePlayerUpdate);
4333 config.SaveFile(GameDir+'/'+CONFIG_FILENAME);
4334 config.Free();
4335 end
4336 else if cmd = 'net_predictself' then
4337 begin
4338 if (Length(P) > 1) and
4339 ((P[1] = '1') or (P[1] = '0')) then
4340 NetPredictSelf := (P[1][1] = '1');
4342 if NetPredictSelf then
4343 g_Console_Add('net_predictself = 1')
4344 else
4345 g_Console_Add('net_predictself = 0');
4346 config := TConfig.CreateFile(GameDir+'/'+CONFIG_FILENAME);
4347 config.WriteBool('Client', 'PredictSelf', NetPredictSelf);
4348 config.SaveFile(GameDir+'/'+CONFIG_FILENAME);
4349 config.Free();
4350 end
4351 else if cmd = 'sv_name' then
4352 begin
4353 if (Length(P) > 1) and (Length(P[1]) > 0) then
4354 begin
4355 NetServerName := P[1];
4356 if Length(NetServerName) > 64 then
4357 SetLength(NetServerName, 64);
4358 if g_Game_IsServer and g_Game_IsNet and NetUseMaster then
4359 g_Net_Slist_Update;
4360 end;
4362 g_Console_Add(cmd + ' = "' + NetServerName + '"');
4363 end
4364 else if cmd = 'sv_passwd' then
4365 begin
4366 if (Length(P) > 1) and (Length(P[1]) > 0) then
4367 begin
4368 NetPassword := P[1];
4369 if Length(NetPassword) > 24 then
4370 SetLength(NetPassword, 24);
4371 if g_Game_IsServer and g_Game_IsNet and NetUseMaster then
4372 g_Net_Slist_Update;
4373 end;
4375 g_Console_Add(cmd + ' = "' + AnsiLowerCase(NetPassword) + '"');
4376 end
4377 else if cmd = 'sv_maxplrs' then
4378 begin
4379 if (Length(P) > 1) then
4380 begin
4381 NetMaxClients := Min(Max(StrToIntDef(P[1], NetMaxClients), 1), NET_MAXCLIENTS);
4382 if g_Game_IsServer and g_Game_IsNet then
4383 begin
4384 b := 0;
4385 for a := 0 to High(NetClients) do
4386 if NetClients[a].Used then
4387 begin
4388 Inc(b);
4389 if b > NetMaxClients then
4390 begin
4391 s := g_Player_Get(NetClients[a].Player).Name;
4392 enet_peer_disconnect(NetClients[a].Peer, NET_DISC_FULL);
4393 g_Console_Add(Format(_lc[I_PLAYER_KICK], [s]));
4394 MH_SEND_GameEvent(NET_EV_PLAYER_KICK, 0, s);
4395 end;
4396 end;
4397 if NetUseMaster then
4398 g_Net_Slist_Update;
4399 end;
4400 end;
4402 g_Console_Add(cmd + ' = ' + IntToStr(NetMaxClients));
4403 end
4404 else if cmd = 'sv_public' then
4405 begin
4406 if (Length(P) > 1) then
4407 begin
4408 NetUseMaster := StrToIntDef(P[1], Byte(NetUseMaster)) > 0;
4409 if g_Game_IsServer and g_Game_IsNet then
4410 if NetUseMaster then
4411 begin
4412 if NetMPeer = nil then
4413 if not g_Net_Slist_Connect() then
4414 g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_SLIST_ERROR]);
4415 g_Net_Slist_Update();
4416 end
4417 else
4418 if NetMPeer <> nil then
4419 g_Net_Slist_Disconnect();
4420 end;
4422 g_Console_Add(cmd + ' = ' + IntToStr(Byte(NetUseMaster)));
4423 end
4424 else if cmd = 'sv_intertime' then
4425 begin
4426 if (Length(P) > 1) then
4427 gDefInterTime := Min(Max(StrToIntDef(P[1], gDefInterTime), -1), 120);
4429 g_Console_Add(cmd + ' = ' + IntToStr(gDefInterTime));
4430 end
4431 else if cmd = 'p1_name' then
4432 begin
4433 if (Length(P) > 1) and gGameOn then
4434 begin
4435 if g_Game_IsClient then
4436 begin
4437 gPlayer1Settings.Name := b_Text_Unformat(P[1]);
4438 MC_SEND_PlayerSettings;
4439 end
4440 else
4441 if gPlayer1 <> nil then
4442 begin
4443 gPlayer1.Name := b_Text_Unformat(P[1]);
4444 if g_Game_IsNet then MH_SEND_PlayerSettings(gPlayer1.UID);
4445 end
4446 else
4447 gPlayer1Settings.Name := b_Text_Unformat(P[1]);
4448 end;
4449 end
4450 else if cmd = 'p2_name' then
4451 begin
4452 if (Length(P) > 1) and gGameOn then
4453 begin
4454 if g_Game_IsClient then
4455 begin
4456 gPlayer2Settings.Name := b_Text_Unformat(P[1]);
4457 MC_SEND_PlayerSettings;
4458 end
4459 else
4460 if gPlayer2 <> nil then
4461 begin
4462 gPlayer2.Name := b_Text_Unformat(P[1]);
4463 if g_Game_IsNet then MH_SEND_PlayerSettings(gPlayer2.UID);
4464 end
4465 else
4466 gPlayer2Settings.Name := b_Text_Unformat(P[1]);
4467 end;
4468 end
4469 else if cmd = 'p1_color' then
4470 begin
4471 if Length(P) > 3 then
4472 if g_Game_IsClient then
4473 begin
4474 gPlayer1Settings.Color := _RGB(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4475 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4476 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4477 MC_SEND_PlayerSettings;
4478 end
4479 else
4480 if gPlayer1 <> nil then
4481 begin
4482 gPlayer1.Model.SetColor(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4483 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4484 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4485 if g_Game_IsNet then MH_SEND_PlayerSettings(gPlayer1.UID);
4486 end
4487 else
4488 gPlayer1Settings.Color := _RGB(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4489 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4490 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4491 end
4492 else if (cmd = 'p2_color') and not g_Game_IsNet then
4493 begin
4494 if Length(P) > 3 then
4495 if g_Game_IsClient then
4496 begin
4497 gPlayer2Settings.Color := _RGB(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4498 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4499 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4500 MC_SEND_PlayerSettings;
4501 end
4502 else
4503 if gPlayer2 <> nil then
4504 begin
4505 gPlayer2.Model.SetColor(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4506 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4507 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4508 if g_Game_IsNet then MH_SEND_PlayerSettings(gPlayer2.UID);
4509 end
4510 else
4511 gPlayer2Settings.Color := _RGB(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4512 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4513 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4514 end
4515 else if gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT] then
4516 begin
4517 if cmd = 'r_showtime' then
4518 begin
4519 if (Length(P) > 1) and
4520 ((P[1] = '1') or (P[1] = '0')) then
4521 gShowTime := (P[1][1] = '1');
4523 if gShowTime then
4524 g_Console_Add(_lc[I_MSG_TIME_ON])
4525 else
4526 g_Console_Add(_lc[I_MSG_TIME_OFF]);
4527 end
4528 else if cmd = 'r_showscore' then
4529 begin
4530 if (Length(P) > 1) and
4531 ((P[1] = '1') or (P[1] = '0')) then
4532 gShowGoals := (P[1][1] = '1');
4534 if gShowGoals then
4535 g_Console_Add(_lc[I_MSG_SCORE_ON])
4536 else
4537 g_Console_Add(_lc[I_MSG_SCORE_OFF]);
4538 end
4539 else if cmd = 'r_showstat' then
4540 begin
4541 if (Length(P) > 1) and
4542 ((P[1] = '1') or (P[1] = '0')) then
4543 gShowStat := (P[1][1] = '1');
4545 if gShowStat then
4546 g_Console_Add(_lc[I_MSG_STATS_ON])
4547 else
4548 g_Console_Add(_lc[I_MSG_STATS_OFF]);
4549 end
4550 else if cmd = 'r_showkillmsg' then
4551 begin
4552 if (Length(P) > 1) and
4553 ((P[1] = '1') or (P[1] = '0')) then
4554 gShowKillMsg := (P[1][1] = '1');
4556 if gShowKillMsg then
4557 g_Console_Add(_lc[I_MSG_KILL_MSGS_ON])
4558 else
4559 g_Console_Add(_lc[I_MSG_KILL_MSGS_OFF]);
4560 end
4561 else if cmd = 'r_showlives' then
4562 begin
4563 if (Length(P) > 1) and
4564 ((P[1] = '1') or (P[1] = '0')) then
4565 gShowLives := (P[1][1] = '1');
4567 if gShowLives then
4568 g_Console_Add(_lc[I_MSG_LIVES_ON])
4569 else
4570 g_Console_Add(_lc[I_MSG_LIVES_OFF]);
4571 end
4572 else if cmd = 'r_showspect' then
4573 begin
4574 if (Length(P) > 1) and
4575 ((P[1] = '1') or (P[1] = '0')) then
4576 gSpectHUD := (P[1][1] = '1');
4578 if gSpectHUD then
4579 g_Console_Add(_lc[I_MSG_SPECT_HUD_ON])
4580 else
4581 g_Console_Add(_lc[I_MSG_SPECT_HUD_OFF]);
4582 end
4583 else if cmd = 'r_showping' then
4584 begin
4585 if (Length(P) > 1) and
4586 ((P[1] = '1') or (P[1] = '0')) then
4587 gShowPing := (P[1][1] = '1');
4589 if gShowPing then
4590 g_Console_Add(_lc[I_MSG_PING_ON])
4591 else
4592 g_Console_Add(_lc[I_MSG_PING_OFF]);
4593 end
4594 else if (cmd = 'g_scorelimit') and not g_Game_IsClient then
4595 begin
4596 if Length(P) > 1 then
4597 begin
4598 if StrToIntDef(P[1], gGameSettings.GoalLimit) = 0 then
4599 gGameSettings.GoalLimit := 0
4600 else
4601 begin
4602 b := 0;
4604 if gGameSettings.GameMode = GM_DM then
4605 begin // DM
4606 stat := g_Player_GetStats();
4607 if stat <> nil then
4608 for a := 0 to High(stat) do
4609 if stat[a].Frags > b then
4610 b := stat[a].Frags;
4611 end
4612 else // TDM/CTF
4613 b := Max(gTeamStat[TEAM_RED].Goals, gTeamStat[TEAM_BLUE].Goals);
4615 gGameSettings.GoalLimit := Max(StrToIntDef(P[1], gGameSettings.GoalLimit), b);
4616 end;
4618 if g_Game_IsNet then MH_SEND_GameSettings;
4619 end;
4621 g_Console_Add(Format(_lc[I_MSG_SCORE_LIMIT], [gGameSettings.GoalLimit]));
4622 end
4623 else if (cmd = 'g_timelimit') and not g_Game_IsClient then
4624 begin
4625 if (Length(P) > 1) and (StrToIntDef(P[1], -1) >= 0) then
4626 gGameSettings.TimeLimit := StrToIntDef(P[1], -1);
4628 g_Console_Add(Format(_lc[I_MSG_TIME_LIMIT],
4629 [gGameSettings.TimeLimit div 3600,
4630 (gGameSettings.TimeLimit div 60) mod 60,
4631 gGameSettings.TimeLimit mod 60]));
4632 if g_Game_IsNet then MH_SEND_GameSettings;
4633 end
4634 else if (cmd = 'g_maxlives') and not g_Game_IsClient then
4635 begin
4636 if Length(P) > 1 then
4637 begin
4638 if StrToIntDef(P[1], gGameSettings.MaxLives) = 0 then
4639 gGameSettings.MaxLives := 0
4640 else
4641 begin
4642 b := 0;
4643 stat := g_Player_GetStats();
4644 if stat <> nil then
4645 for a := 0 to High(stat) do
4646 if stat[a].Lives > b then
4647 b := stat[a].Lives;
4648 gGameSettings.MaxLives :=
4649 Max(StrToIntDef(P[1], gGameSettings.MaxLives), b);
4650 end;
4651 end;
4653 g_Console_Add(Format(_lc[I_MSG_LIVES],
4654 [gGameSettings.MaxLives]));
4655 if g_Game_IsNet then MH_SEND_GameSettings;
4656 end;
4657 end;
4658 end;
4660 procedure DebugCommands(P: SArray);
4661 var
4662 a, b: Integer;
4663 cmd: string;
4664 //pt: TPoint;
4665 begin
4666 // Êîìàíäû îòëàäî÷íîãî ðåæèìà:
4667 if gDebugMode then
4668 begin
4669 cmd := LowerCase(P[0]);
4670 if cmd = 'd_window' then
4671 begin
4672 g_Console_Add(Format('gWinPosX = %d, gWinPosY %d', [gWinPosX, gWinPosY]));
4673 g_Console_Add(Format('gWinRealPosX = %d, gWinRealPosY %d', [gWinRealPosX, gWinRealPosY]));
4674 g_Console_Add(Format('gScreenWidth = %d, gScreenHeight = %d', [gScreenWidth, gScreenHeight]));
4675 g_Console_Add(Format('gWinSizeX = %d, gWinSizeY = %d', [gWinSizeX, gWinSizeY]));
4676 g_Console_Add(Format('Frame X = %d, Y = %d, Caption Y = %d', [gWinFrameX, gWinFrameY, gWinCaption]));
4677 end
4678 else if cmd = 'd_sounds' then
4679 begin
4680 if (Length(P) > 1) and
4681 ((P[1] = '1') or (P[1] = '0')) then
4682 g_Debug_Sounds := (P[1][1] = '1');
4684 g_Console_Add(Format('d_sounds is %d', [Byte(g_Debug_Sounds)]));
4685 end
4686 else if cmd = 'd_frames' then
4687 begin
4688 if (Length(P) > 1) and
4689 ((P[1] = '1') or (P[1] = '0')) then
4690 g_Debug_Frames := (P[1][1] = '1');
4692 g_Console_Add(Format('d_frames is %d', [Byte(g_Debug_Frames)]));
4693 end
4694 else if cmd = 'd_winmsg' then
4695 begin
4696 if (Length(P) > 1) and
4697 ((P[1] = '1') or (P[1] = '0')) then
4698 g_Debug_WinMsgs := (P[1][1] = '1');
4700 g_Console_Add(Format('d_winmsg is %d', [Byte(g_Debug_WinMsgs)]));
4701 end
4702 else if (cmd = 'd_monoff') and not g_Game_IsNet then
4703 begin
4704 if (Length(P) > 1) and
4705 ((P[1] = '1') or (P[1] = '0')) then
4706 g_Debug_MonsterOff := (P[1][1] = '1');
4708 g_Console_Add(Format('d_monoff is %d', [Byte(g_debug_MonsterOff)]));
4709 end
4710 else if (cmd = 'd_botoff') and not g_Game_IsNet then
4711 begin
4712 if Length(P) > 1 then
4713 case P[1][1] of
4714 '0': g_debug_BotAIOff := 0;
4715 '1': g_debug_BotAIOff := 1;
4716 '2': g_debug_BotAIOff := 2;
4717 '3': g_debug_BotAIOff := 3;
4718 end;
4720 g_Console_Add(Format('d_botoff is %d', [g_debug_BotAIOff]));
4721 end
4722 else if cmd = 'd_monster' then
4723 begin
4724 if gGameOn and (gPlayer1 <> nil) and (gPlayer1.Live) and (not g_Game_IsNet) then
4725 if Length(P) < 2 then
4726 begin
4727 g_Console_Add(cmd + ' [ID | Name] [behaviour]');
4728 g_Console_Add('ID | Name');
4729 for b := MONSTER_DEMON to MONSTER_MAN do
4730 g_Console_Add(Format('%2d | %s', [b, g_Monsters_GetNameByID(b)]));
4731 end else
4732 begin
4733 a := StrToIntDef(P[1], 0);
4734 if (a < MONSTER_DEMON) or (a > MONSTER_MAN) then
4735 a := g_Monsters_GetIDByName(P[1]);
4737 if (a < MONSTER_DEMON) or (a > MONSTER_MAN) then
4738 g_Console_Add(Format(_lc[I_MSG_NO_MONSTER], [P[1]]))
4739 else
4740 begin
4741 with gPlayer1.Obj do
4742 b := g_Monsters_Create(a,
4743 X + Rect.X + (Rect.Width div 2),
4744 Y + Rect.Y + Rect.Height,
4745 gPlayer1.Direction, True);
4746 if (Length(P) > 2) and (b >= 0) then
4747 gMonsters[b].MonsterBehaviour := Min(Max(StrToIntDef(P[2], BH_NORMAL), BH_NORMAL), BH_GOOD);
4748 end;
4749 end;
4750 end
4751 else if (cmd = 'd_health') then
4752 begin
4753 if (Length(P) > 1) and
4754 ((P[1] = '1') or (P[1] = '0')) then
4755 g_debug_HealthBar := (P[1][1] = '1');
4757 g_Console_Add(Format('d_health is %d', [Byte(g_debug_HealthBar)]));
4758 end
4759 else if (cmd = 'd_player') then
4760 begin
4761 if (Length(P) > 1) and
4762 ((P[1] = '1') or (P[1] = '0')) then
4763 g_debug_Player := (P[1][1] = '1');
4765 g_Console_Add(Format(cmd + ' is %d', [Byte(g_Debug_Player)]));
4766 end
4767 else if (cmd = 'd_joy') then
4768 begin
4769 for a := 1 to 8 do
4770 g_Console_Add(e_JoystickStateToString(a));
4771 end;
4772 end
4773 else
4774 g_Console_Add(_lc[I_MSG_NOT_DEBUG]);
4775 end;
4778 procedure GameCheats(P: SArray);
4779 var
4780 cmd: string;
4781 f, a: Integer;
4782 plr: TPlayer;
4783 begin
4784 if (not gGameOn) or (not gCheats) or ((gGameSettings.GameType <> GT_SINGLE) and
4785 (gGameSettings.GameMode <> GM_COOP) and (not gDebugMode)) or g_Game_IsNet then
4786 begin
4787 g_Console_Add('not available');
4788 exit;
4789 end;
4790 plr := gPlayer1;
4791 if plr = nil then
4792 begin
4793 g_Console_Add('where is the player?!');
4794 exit;
4795 end;
4796 cmd := LowerCase(P[0]);
4797 // god
4798 if cmd = 'god' then
4799 begin
4800 plr.GodMode := not plr.GodMode;
4801 if plr.GodMode then g_Console_Add('player is godlike now') else g_Console_Add('player is mortal now');
4802 exit;
4803 end;
4804 // give <health|exit|weapons|air|suit|jetpack|berserk|all>
4805 if cmd = 'give' then
4806 begin
4807 if length(P) < 2 then begin g_Console_Add('give what?!'); exit; end;
4808 for f := 1 to High(P) do
4809 begin
4810 cmd := LowerCase(P[f]);
4811 if cmd = 'health' then begin plr.RestoreHealthArmor(); g_Console_Add('player feels himself better'); continue; end;
4812 if (cmd = 'all') or (cmd = 'weapons') then begin plr.AllRulez(False); g_Console_Add('player got the gifts'); continue; end;
4813 if cmd = 'exit' then
4814 begin
4815 if gTriggers <> nil then
4816 begin
4817 for a := 0 to High(gTriggers) do
4818 begin
4819 if gTriggers[a].TriggerType = TRIGGER_EXIT then
4820 begin
4821 g_Console_Add('player left the map');
4822 gExitByTrigger := True;
4823 g_Game_ExitLevel(gTriggers[a].Data.MapName);
4824 break;
4825 end;
4826 end;
4827 end;
4828 continue;
4829 end;
4830 if cmd = 'air' then begin plr.GiveItem(ITEM_OXYGEN); g_Console_Add('player got some air'); continue; end;
4831 if cmd = 'jetpack' then begin plr.GiveItem(ITEM_JETPACK); g_Console_Add('player got jetpack'); continue; end;
4832 if cmd = 'suit' then begin plr.GiveItem(ITEM_SUIT); g_Console_Add('player got envirosuit'); continue; end;
4833 if cmd = 'berserk' then begin plr.GiveItem(ITEM_MEDKIT_BLACK); g_Console_Add('player got berserk pack'); continue; end;
4834 g_Console_Add('i don''t know how to give '''+cmd+'''!');
4835 end;
4836 exit;
4837 end;
4838 // open
4839 if cmd = 'open' then
4840 begin
4841 g_Console_Add('player activated sesame');
4842 g_Triggers_OpenAll();
4843 exit;
4844 end;
4845 // fly
4846 if cmd = 'fly' then
4847 begin
4848 gFly := not gFly;
4849 if gFly then g_Console_Add('player feels himself lighter') else g_Console_Add('player lost his wings');
4850 exit;
4851 end;
4852 // noclip
4853 if cmd = 'noclip' then
4854 begin
4855 plr.SwitchNoClip;
4856 g_Console_Add('wall hardeness adjusted');
4857 exit;
4858 end;
4859 // notarget
4860 if cmd = 'notarget' then
4861 begin
4862 plr.NoTarget := not plr.NoTarget;
4863 if plr.NoTarget then g_Console_Add('player hides in shadows') else g_Console_Add('player is brave again');
4864 exit;
4865 end;
4866 // noreload
4867 if cmd = 'noreload' then
4868 begin
4869 plr.NoReload := not plr.NoReload;
4870 if plr.NoReload then g_Console_Add('player is action hero now') else g_Console_Add('player is ordinary man now');
4871 exit;
4872 end;
4873 // speedy
4874 if cmd = 'speedy' then
4875 begin
4876 MAX_RUNVEL := 32-MAX_RUNVEL;
4877 g_Console_Add('speed adjusted');
4878 exit;
4879 end;
4880 // jumpy
4881 if cmd = 'jumpy' then
4882 begin
4883 VEL_JUMP := 30-VEL_JUMP;
4884 g_Console_Add('jump height adjusted');
4885 exit;
4886 end;
4887 // automap
4888 if cmd = 'automap' then
4889 begin
4890 gShowMap := not gShowMap;
4891 if gShowMap then g_Console_Add('player gains second sight') else g_Console_Add('player lost second sight');
4892 exit;
4893 end;
4894 // aimline
4895 if cmd = 'aimline' then
4896 begin
4897 gAimLine := not gAimLine;
4898 if gAimLine then g_Console_Add('player gains laser sight') else g_Console_Add('player lost laser sight');
4899 exit;
4900 end;
4901 end;
4903 procedure GameCommands(P: SArray);
4904 var
4905 a, b: Integer;
4906 s, pw: String;
4907 chstr: string;
4908 cmd: string;
4909 pl: pTNetClient = nil;
4910 plr: TPlayer;
4911 prt: Word;
4912 nm: Boolean;
4913 listen: LongWord;
4914 begin
4915 // Îáùèå êîìàíäû:
4916 cmd := LowerCase(P[0]);
4917 chstr := '';
4918 if (cmd = 'quit') or
4919 (cmd = 'exit') then
4920 begin
4921 g_Game_Free();
4922 g_Game_Quit();
4923 Exit;
4924 end
4925 else if cmd = 'pause' then
4926 begin
4927 if (g_ActiveWindow = nil) then
4928 g_Game_Pause(not gPause);
4929 end
4930 else if cmd = 'endgame' then
4931 gExit := EXIT_SIMPLE
4932 else if cmd = 'restart' then
4933 begin
4934 if gGameOn or (gState in [STATE_INTERSINGLE, STATE_INTERCUSTOM]) then
4935 begin
4936 if g_Game_IsClient then
4937 begin
4938 g_Console_Add(_lc[I_MSG_SERVERONLY]);
4939 Exit;
4940 end;
4941 g_Game_Restart();
4942 end else
4943 g_Console_Add(_lc[I_MSG_NOT_GAME]);
4944 end
4945 else if cmd = 'kick' then
4946 begin
4947 if g_Game_IsServer then
4948 begin
4949 if Length(P) < 2 then
4950 begin
4951 g_Console_Add('kick <name>');
4952 Exit;
4953 end;
4954 if P[1] = '' then
4955 begin
4956 g_Console_Add('kick <name>');
4957 Exit;
4958 end;
4960 if g_Game_IsNet then
4961 pl := g_Net_Client_ByName(P[1]);
4962 if (pl <> nil) then
4963 begin
4964 s := g_Net_ClientName_ByID(pl^.ID);
4965 enet_peer_disconnect(pl^.Peer, NET_DISC_KICK);
4966 g_Console_Add(Format(_lc[I_PLAYER_KICK], [s]));
4967 MH_SEND_GameEvent(NET_EV_PLAYER_KICK, 0, s);
4968 if NetUseMaster then
4969 g_Net_Slist_Update;
4970 end else if gPlayers <> nil then
4971 for a := Low(gPlayers) to High(gPlayers) do
4972 if gPlayers[a] <> nil then
4973 if Copy(LowerCase(gPlayers[a].Name), 1, Length(P[1])) = LowerCase(P[1]) then
4974 begin
4975 // Íå îòêëþ÷àòü îñíîâíûõ èãðîêîâ â ñèíãëå
4976 if not(gPlayers[a] is TBot) and (gGameSettings.GameType = GT_SINGLE) then
4977 continue;
4978 gPlayers[a].Lives := 0;
4979 gPlayers[a].Kill(K_SIMPLEKILL, 0, HIT_DISCON);
4980 g_Console_Add(Format(_lc[I_PLAYER_LEAVE], [gPlayers[a].Name]), True);
4981 g_Player_Remove(gPlayers[a].UID);
4982 if NetUseMaster then
4983 g_Net_Slist_Update;
4984 // Åñëè íå ïåðåìåøàòü, ïðè äîáàâëåíèè íîâûõ áîòîâ ïîÿâÿòñÿ ñòàðûå
4985 g_Bot_MixNames();
4986 end;
4987 end else
4988 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
4989 end
4990 else if cmd = 'kick_id' then
4991 begin
4992 if g_Game_IsServer and g_Game_IsNet then
4993 begin
4994 if Length(P) < 2 then
4995 begin
4996 g_Console_Add('kick_id <client ID>');
4997 Exit;
4998 end;
4999 if P[1] = '' then
5000 begin
5001 g_Console_Add('kick_id <client ID>');
5002 Exit;
5003 end;
5005 a := StrToIntDef(P[1], 0);
5006 if (NetClients <> nil) and (a <= High(NetClients)) then
5007 begin
5008 if NetClients[a].Used and (NetClients[a].Peer <> nil) then
5009 begin
5010 s := g_Net_ClientName_ByID(NetClients[a].ID);
5011 enet_peer_disconnect(NetClients[a].Peer, NET_DISC_KICK);
5012 g_Console_Add(Format(_lc[I_PLAYER_KICK], [s]));
5013 MH_SEND_GameEvent(NET_EV_PLAYER_KICK, 0, s);
5014 if NetUseMaster then
5015 g_Net_Slist_Update;
5016 end;
5017 end;
5018 end else
5019 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5020 end
5021 else if cmd = 'ban' then
5022 begin
5023 if g_Game_IsServer and g_Game_IsNet then
5024 begin
5025 if Length(P) < 2 then
5026 begin
5027 g_Console_Add('ban <name>');
5028 Exit;
5029 end;
5030 if P[1] = '' then
5031 begin
5032 g_Console_Add('ban <name>');
5033 Exit;
5034 end;
5036 pl := g_Net_Client_ByName(P[1]);
5037 if (pl <> nil) then
5038 begin
5039 s := g_Net_ClientName_ByID(pl^.ID);
5040 g_Net_BanHost(pl^.Peer^.address.host, False);
5041 enet_peer_disconnect(pl^.Peer, NET_DISC_TEMPBAN);
5042 g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
5043 MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
5044 if NetUseMaster then
5045 g_Net_Slist_Update;
5046 end else
5047 g_Console_Add(Format(_lc[I_NET_ERR_NAME404], [P[1]]));
5048 end else
5049 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5050 end
5051 else if cmd = 'ban_id' then
5052 begin
5053 if g_Game_IsServer and g_Game_IsNet then
5054 begin
5055 if Length(P) < 2 then
5056 begin
5057 g_Console_Add('ban_id <client ID>');
5058 Exit;
5059 end;
5060 if P[1] = '' then
5061 begin
5062 g_Console_Add('ban_id <client ID>');
5063 Exit;
5064 end;
5066 a := StrToIntDef(P[1], 0);
5067 if (NetClients <> nil) and (a <= High(NetClients)) then
5068 if NetClients[a].Used and (NetClients[a].Peer <> nil) then
5069 begin
5070 s := g_Net_ClientName_ByID(NetClients[a].ID);
5071 g_Net_BanHost(NetClients[a].Peer^.address.host, False);
5072 enet_peer_disconnect(NetClients[a].Peer, NET_DISC_TEMPBAN);
5073 g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
5074 MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
5075 if NetUseMaster then
5076 g_Net_Slist_Update;
5077 end;
5078 end else
5079 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5080 end
5081 else if cmd = 'permban' then
5082 begin
5083 if g_Game_IsServer and g_Game_IsNet then
5084 begin
5085 if Length(P) < 2 then
5086 begin
5087 g_Console_Add('permban <name>');
5088 Exit;
5089 end;
5090 if P[1] = '' then
5091 begin
5092 g_Console_Add('permban <name>');
5093 Exit;
5094 end;
5096 pl := g_Net_Client_ByName(P[1]);
5097 if (pl <> nil) then
5098 begin
5099 s := g_Net_ClientName_ByID(pl^.ID);
5100 g_Net_BanHost(pl^.Peer^.address.host);
5101 enet_peer_disconnect(pl^.Peer, NET_DISC_BAN);
5102 g_Net_SaveBanList();
5103 g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
5104 MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
5105 if NetUseMaster then
5106 g_Net_Slist_Update;
5107 end else
5108 g_Console_Add(Format(_lc[I_NET_ERR_NAME404], [P[1]]));
5109 end else
5110 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5111 end
5112 else if cmd = 'permban_id' then
5113 begin
5114 if g_Game_IsServer and g_Game_IsNet then
5115 begin
5116 if Length(P) < 2 then
5117 begin
5118 g_Console_Add('permban_id <client ID>');
5119 Exit;
5120 end;
5121 if P[1] = '' then
5122 begin
5123 g_Console_Add('permban_id <client ID>');
5124 Exit;
5125 end;
5127 a := StrToIntDef(P[1], 0);
5128 if (NetClients <> nil) and (a <= High(NetClients)) then
5129 if NetClients[a].Used and (NetClients[a].Peer <> nil) then
5130 begin
5131 s := g_Net_ClientName_ByID(NetClients[a].ID);
5132 g_Net_BanHost(NetClients[a].Peer^.address.host);
5133 enet_peer_disconnect(NetClients[a].Peer, NET_DISC_BAN);
5134 g_Net_SaveBanList();
5135 g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
5136 MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
5137 if NetUseMaster then
5138 g_Net_Slist_Update;
5139 end;
5140 end else
5141 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5142 end
5143 else if cmd = 'unban' then
5144 begin
5145 if g_Game_IsServer and g_Game_IsNet then
5146 begin
5147 if Length(P) < 2 then
5148 begin
5149 g_Console_Add('unban <IP Address>');
5150 Exit;
5151 end;
5152 if P[1] = '' then
5153 begin
5154 g_Console_Add('unban <IP Address>');
5155 Exit;
5156 end;
5158 if g_Net_UnbanHost(P[1]) then
5159 begin
5160 g_Console_Add(Format(_lc[I_MSG_UNBAN_OK], [P[1]]));
5161 g_Net_SaveBanList();
5162 end else
5163 g_Console_Add(Format(_lc[I_MSG_UNBAN_FAIL], [P[1]]));
5164 end else
5165 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5166 end
5167 else if cmd = 'clientlist' then
5168 begin
5169 if g_Game_IsServer and g_Game_IsNet then
5170 begin
5171 b := 0;
5172 if NetClients <> nil then
5173 for a := Low(NetClients) to High(NetClients) do
5174 if NetClients[a].Used and (NetClients[a].Peer <> nil) then
5175 begin
5176 plr := g_Player_Get(NetClients[a].Player);
5177 if plr = nil then continue;
5178 Inc(b);
5179 g_Console_Add(Format('#%2d: %-15s | %s', [a,
5180 IpToStr(NetClients[a].Peer^.address.host), plr.Name]));
5181 end;
5182 if b = 0 then
5183 g_Console_Add(_lc[I_MSG_NOCLIENTS]);
5184 end else
5185 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5186 end
5187 else if cmd = 'connect' then
5188 begin
5189 if (NetMode = NET_NONE) then
5190 begin
5191 if Length(P) < 2 then
5192 begin
5193 g_Console_Add('connect <IP> [port] [password]');
5194 Exit;
5195 end;
5196 if P[1] = '' then
5197 begin
5198 g_Console_Add('connect <IP> [port] [password]');
5199 Exit;
5200 end;
5202 if Length(P) > 2 then
5203 prt := StrToIntDef(P[2], 25666)
5204 else
5205 prt := 25666;
5207 if Length(P) > 3 then
5208 pw := P[3]
5209 else
5210 pw := '';
5212 g_Game_StartClient(P[1], prt, pw);
5213 end;
5214 end
5215 else if cmd = 'disconnect' then
5216 begin
5217 if (NetMode = NET_CLIENT) then
5218 g_Net_Disconnect();
5219 end
5220 else if cmd = 'reconnect' then
5221 begin
5222 if (NetMode = NET_SERVER) then
5223 Exit;
5225 if (NetMode = NET_CLIENT) then
5226 begin
5227 g_Net_Disconnect();
5228 gExit := EXIT_SIMPLE;
5229 EndGame;
5230 end;
5232 //TODO: Use last successful password to reconnect, instead of ''
5233 g_Game_StartClient(NetClientIP, NetClientPort, '');
5234 end
5235 else if (cmd = 'addbot') or
5236 (cmd = 'bot_add') then
5237 begin
5238 if Length(P) > 1 then
5239 g_Bot_Add(TEAM_NONE, StrToIntDef(P[1], 2))
5240 else
5241 g_Bot_Add(TEAM_NONE, 2);
5242 end
5243 else if cmd = 'bot_addlist' then
5244 begin
5245 if Length(P) > 1 then
5246 if Length(P) = 2 then
5247 g_Bot_AddList(TEAM_NONE, P[1], StrToIntDef(P[1], -1))
5248 else
5249 g_Bot_AddList(IfThen(P[2] = 'red', TEAM_RED, TEAM_BLUE), P[1], StrToIntDef(P[1], -1));
5250 end
5251 else if cmd = 'bot_removeall' then
5252 g_Bot_RemoveAll()
5253 else if cmd = 'chat' then
5254 begin
5255 if g_Game_IsNet then
5256 begin
5257 if Length(P) > 1 then
5258 begin
5259 for a := 1 to High(P) do
5260 chstr := chstr + P[a] + ' ';
5262 if Length(chstr) > 200 then SetLength(chstr, 200);
5264 if Length(chstr) < 1 then
5265 begin
5266 g_Console_Add('chat <text>');
5267 Exit;
5268 end;
5270 chstr := b_Text_Format(chstr);
5271 if g_Game_IsClient then
5272 MC_SEND_Chat(chstr, NET_CHAT_PLAYER)
5273 else
5274 MH_SEND_Chat(gPlayer1Settings.Name + ': ' + chstr, NET_CHAT_PLAYER);
5275 end
5276 else
5277 g_Console_Add('chat <text>');
5278 end else
5279 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5280 end
5281 else if cmd = 'teamchat' then
5282 begin
5283 if g_Game_IsNet and (gGameSettings.GameMode in [GM_TDM, GM_CTF]) then
5284 begin
5285 if Length(P) > 1 then
5286 begin
5287 for a := 1 to High(P) do
5288 chstr := chstr + P[a] + ' ';
5290 if Length(chstr) > 200 then SetLength(chstr, 200);
5292 if Length(chstr) < 1 then
5293 begin
5294 g_Console_Add('teamchat <text>');
5295 Exit;
5296 end;
5298 chstr := b_Text_Format(chstr);
5299 if g_Game_IsClient then
5300 MC_SEND_Chat(chstr, NET_CHAT_TEAM)
5301 else
5302 MH_SEND_Chat(gPlayer1Settings.Name + ': ' + chstr, NET_CHAT_TEAM,
5303 gPlayer1Settings.Team);
5304 end
5305 else
5306 g_Console_Add('teamchat <text>');
5307 end else
5308 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5309 end
5310 else if cmd = 'game' then
5311 begin
5312 if gGameSettings.GameType <> GT_NONE then
5313 begin
5314 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5315 Exit;
5316 end;
5317 if Length(P) = 1 then
5318 begin
5319 g_Console_Add(cmd + ' <WAD> [MAP] [# players]');
5320 Exit;
5321 end;
5322 // Èãðà åù¸ íå çàïóùåíà, ñíà÷àëà íàì íàäî çàãðóçèòü êàêîé-òî WAD
5323 P[1] := addWadExtension(P[1]);
5324 if FileExists(MapsDir + P[1]) then
5325 begin
5326 // Åñëè êàðòà íå óêàçàíà, áåð¸ì ïåðâóþ êàðòó â ôàéëå
5327 if Length(P) < 3 then
5328 begin
5329 SetLength(P, 3);
5330 P[2] := g_Game_GetFirstMap(MapsDir + P[1]);
5331 end;
5333 s := P[1] + ':\' + UpperCase(P[2]);
5335 if g_Map_Exist(MapsDir + s) then
5336 begin
5337 // Çàïóñêàåì ñâîþ èãðó
5338 g_Game_Free();
5339 with gGameSettings do
5340 begin
5341 GameMode := g_Game_TextToMode(gcGameMode);
5342 if gSwitchGameMode <> GM_NONE then
5343 GameMode := gSwitchGameMode;
5344 if GameMode = GM_NONE then GameMode := GM_DM;
5345 if GameMode = GM_SINGLE then GameMode := GM_COOP;
5346 b := 1;
5347 if Length(P) >= 4 then
5348 b := StrToIntDef(P[3], 1);
5349 g_Game_StartCustom(s, GameMode, TimeLimit,
5350 GoalLimit, MaxLives, Options, b);
5351 end;
5352 end
5353 else
5354 if P[2] = '' then
5355 g_Console_Add(Format(_lc[I_MSG_NO_MAPS], [P[1]]))
5356 else
5357 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [UpperCase(P[2])]));
5358 end else
5359 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[1]]));
5360 end
5361 else if cmd = 'host' then
5362 begin
5363 if gGameSettings.GameType <> GT_NONE then
5364 begin
5365 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5366 Exit;
5367 end;
5368 if Length(P) < 4 then
5369 begin
5370 g_Console_Add(cmd + ' <listen IP> <port> <WAD> [MAP] [# players]');
5371 Exit;
5372 end;
5373 if not StrToIp(P[1], listen) then
5374 Exit;
5375 prt := StrToIntDef(P[2], 25666);
5377 P[3] := addWadExtension(P[3]);
5378 if FileExists(MapsDir + P[3]) then
5379 begin
5380 // Åñëè êàðòà íå óêàçàíà, áåð¸ì ïåðâóþ êàðòó â ôàéëå
5381 if Length(P) < 5 then
5382 begin
5383 SetLength(P, 5);
5384 P[4] := g_Game_GetFirstMap(MapsDir + P[1]);
5385 end;
5387 s := P[3] + ':\' + UpperCase(P[4]);
5389 if g_Map_Exist(MapsDir + s) then
5390 begin
5391 // Çàïóñêàåì ñâîþ èãðó
5392 g_Game_Free();
5393 with gGameSettings do
5394 begin
5395 GameMode := g_Game_TextToMode(gcGameMode);
5396 if gSwitchGameMode <> GM_NONE then
5397 GameMode := gSwitchGameMode;
5398 if GameMode = GM_NONE then GameMode := GM_DM;
5399 if GameMode = GM_SINGLE then GameMode := GM_COOP;
5400 b := 0;
5401 if Length(P) >= 6 then
5402 b := StrToIntDef(P[5], 0);
5403 g_Game_StartServer(s, GameMode, TimeLimit,
5404 GoalLimit, MaxLives, Options, b, listen, prt);
5405 end;
5406 end
5407 else
5408 if P[4] = '' then
5409 g_Console_Add(Format(_lc[I_MSG_NO_MAPS], [P[3]]))
5410 else
5411 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [UpperCase(P[4])]));
5412 end else
5413 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[3]]));
5414 end
5415 else if cmd = 'map' then
5416 begin
5417 if Length(P) = 1 then
5418 begin
5419 if g_Game_IsServer and (gGameSettings.GameType <> GT_SINGLE) then
5420 begin
5421 g_Console_Add(cmd + ' <MAP>');
5422 g_Console_Add(cmd + ' <WAD> [MAP]');
5423 end else
5424 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5425 end else
5426 if g_Game_IsServer and (gGameSettings.GameType <> GT_SINGLE) then
5427 begin
5428 // Èä¸ò ñâîÿ èãðà èëè ñåðâåð
5429 if Length(P) < 3 then
5430 begin
5431 // Ïåðâûé ïàðàìåòð - ëèáî êàðòà, ëèáî èìÿ WAD ôàéëà
5432 s := UpperCase(P[1]);
5433 if g_Map_Exist(MapsDir + gGameSettings.WAD + ':\' + s) then
5434 begin // Êàðòà íàøëàñü
5435 gExitByTrigger := False;
5436 if gGameOn then
5437 begin // Èä¸ò èãðà - çàâåðøàåì óðîâåíü
5438 gNextMap := s;
5439 gExit := EXIT_ENDLEVELCUSTOM;
5440 end
5441 else // Èíòåðìèññèÿ - ñðàçó çàãðóæàåì êàðòó
5442 g_Game_ChangeMap(s);
5443 end else
5444 begin
5445 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [s]));
5446 // Òàêîé êàðòû íåò, èùåì WAD ôàéë
5447 P[1] := addWadExtension(P[1]);
5448 if FileExists(MapsDir + P[1]) then
5449 begin
5450 // Ïàðàìåòðà êàðòû íåò, ïîýòîìó ñòàâèì ïåðâóþ èç ôàéëà
5451 SetLength(P, 3);
5452 P[2] := g_Game_GetFirstMap(MapsDir + P[1]);
5454 s := P[1] + ':\' + P[2];
5456 if g_Map_Exist(MapsDir + s) then
5457 begin
5458 gExitByTrigger := False;
5459 if gGameOn then
5460 begin // Èä¸ò èãðà - çàâåðøàåì óðîâåíü
5461 gNextMap := s;
5462 gExit := EXIT_ENDLEVELCUSTOM;
5463 end
5464 else // Èíòåðìèññèÿ - ñðàçó çàãðóæàåì êàðòó
5465 g_Game_ChangeMap(s);
5466 end else
5467 if P[2] = '' then
5468 g_Console_Add(Format(_lc[I_MSG_NO_MAPS], [P[1]]))
5469 else
5470 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [P[2]]));
5471 end else
5472 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[1]]));
5473 end;
5474 end else
5475 begin
5476 // Óêàçàíî äâà ïàðàìåòðà, çíà÷èò ïåðâûé - WAD ôàéë, à âòîðîé - êàðòà
5477 P[1] := addWadExtension(P[1]);
5478 if FileExists(MapsDir + P[1]) then
5479 begin
5480 // Íàøëè WAD ôàéë
5481 P[2] := UpperCase(P[2]);
5482 s := P[1] + ':\' + P[2];
5484 if g_Map_Exist(MapsDir + s) then
5485 begin // Íàøëè êàðòó
5486 gExitByTrigger := False;
5487 if gGameOn then
5488 begin // Èä¸ò èãðà - çàâåðøàåì óðîâåíü
5489 gNextMap := s;
5490 gExit := EXIT_ENDLEVELCUSTOM;
5491 end
5492 else // Èíòåðìèññèÿ - ñðàçó çàãðóæàåì êàðòó
5493 g_Game_ChangeMap(s);
5494 end else
5495 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [P[2]]));
5496 end else
5497 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[1]]));
5498 end;
5499 end else
5500 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5501 end
5502 else if cmd = 'nextmap' then
5503 begin
5504 if not(gGameOn or (gState = STATE_INTERCUSTOM)) then
5505 g_Console_Add(_lc[I_MSG_NOT_GAME])
5506 else begin
5507 nm := True;
5508 if Length(P) = 1 then
5509 begin
5510 if g_Game_IsServer and (gGameSettings.GameType <> GT_SINGLE) then
5511 begin
5512 g_Console_Add(cmd + ' <MAP>');
5513 g_Console_Add(cmd + ' <WAD> [MAP]');
5514 end else begin
5515 nm := False;
5516 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5517 end;
5518 end else
5519 begin
5520 nm := False;
5521 if g_Game_IsServer and (gGameSettings.GameType <> GT_SINGLE) then
5522 begin
5523 if Length(P) < 3 then
5524 begin
5525 // Ïåðâûé ïàðàìåòð - ëèáî êàðòà, ëèáî èìÿ WAD ôàéëà
5526 s := UpperCase(P[1]);
5527 if g_Map_Exist(MapsDir + gGameSettings.WAD + ':\' + s) then
5528 begin // Êàðòà íàøëàñü
5529 gExitByTrigger := False;
5530 gNextMap := s;
5531 nm := True;
5532 end else
5533 begin
5534 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [s]));
5535 // Òàêîé êàðòû íåò, èùåì WAD ôàéë
5536 P[1] := addWadExtension(P[1]);
5537 if FileExists(MapsDir + P[1]) then
5538 begin
5539 // Ïàðàìåòðà êàðòû íåò, ïîýòîìó ñòàâèì ïåðâóþ èç ôàéëà
5540 SetLength(P, 3);
5541 P[2] := g_Game_GetFirstMap(MapsDir + P[1]);
5543 s := P[1] + ':\' + P[2];
5545 if g_Map_Exist(MapsDir + s) then
5546 begin // Óñòàíàâëèâàåì êàðòó
5547 gExitByTrigger := False;
5548 gNextMap := s;
5549 nm := True;
5550 end else
5551 if P[2] = '' then
5552 g_Console_Add(Format(_lc[I_MSG_NO_MAPS], [P[1]]))
5553 else
5554 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [P[2]]));
5555 end else
5556 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[1]]));
5557 end;
5558 end else
5559 begin
5560 // Óêàçàíî äâà ïàðàìåòðà, çíà÷èò ïåðâûé - WAD ôàéë, à âòîðîé - êàðòà
5561 P[1] := addWadExtension(P[1]);
5562 if FileExists(MapsDir + P[1]) then
5563 begin
5564 // Íàøëè WAD ôàéë
5565 P[2] := UpperCase(P[2]);
5566 s := P[1] + ':\' + P[2];
5568 if g_Map_Exist(MapsDir + s) then
5569 begin // Íàøëè êàðòó
5570 gExitByTrigger := False;
5571 gNextMap := s;
5572 nm := True;
5573 end else
5574 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [P[2]]));
5575 end else
5576 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[1]]));
5577 end;
5578 end else
5579 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5580 end;
5581 if nm then
5582 if gNextMap = '' then
5583 g_Console_Add(_lc[I_MSG_NEXTMAP_UNSET])
5584 else
5585 g_Console_Add(Format(_lc[I_MSG_NEXTMAP_SET], [gNextMap]));
5586 end;
5587 end
5588 else if (cmd = 'endmap') or (cmd = 'goodbye') then
5589 begin
5590 if not gGameOn then
5591 g_Console_Add(_lc[I_MSG_NOT_GAME])
5592 else
5593 if g_Game_IsServer and (gGameSettings.GameType <> GT_SINGLE) then
5594 begin
5595 gExitByTrigger := False;
5596 // Ñëåäóþùàÿ êàðòà íå çàäàíà, ïðîáóåì íàéòè òðèããåð Âûõîä
5597 if (gNextMap = '') and (gTriggers <> nil) then
5598 for a := 0 to High(gTriggers) do
5599 if gTriggers[a].TriggerType = TRIGGER_EXIT then
5600 begin
5601 gExitByTrigger := True;
5602 gNextMap := gTriggers[a].Data.MapName;
5603 Break;
5604 end;
5605 // Èùåì ñëåäóþùóþ êàðòó â WAD ôàéëå
5606 if gNextMap = '' then
5607 gNextMap := g_Game_GetNextMap();
5608 // Ïðîâåðÿåì, íå çàäàí ëè WAD ôàéë ðåñóðñíîé ñòðîêîé
5609 if Pos(':\', gNextMap) = 0 then
5610 s := gGameSettings.WAD + ':\' + gNextMap
5611 else
5612 s := gNextMap;
5613 // Åñëè êàðòà íàéäåíà, âûõîäèì ñ óðîâíÿ
5614 if g_Map_Exist(MapsDir + s) then
5615 gExit := EXIT_ENDLEVELCUSTOM
5616 else
5617 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [gNextMap]));
5618 end else
5619 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5620 end
5621 else if (cmd = 'event') then
5622 begin
5623 if (Length(P) <= 1) then
5624 begin
5625 for a := 0 to High(gEvents) do
5626 if gEvents[a].Command = '' then
5627 g_Console_Add(gEvents[a].Name + ' <none>')
5628 else
5629 g_Console_Add(gEvents[a].Name + ' "' + gEvents[a].Command + '"');
5630 Exit;
5631 end;
5632 if (Length(P) = 2) then
5633 begin
5634 for a := 0 to High(gEvents) do
5635 if gEvents[a].Name = P[1] then
5636 if gEvents[a].Command = '' then
5637 g_Console_Add(gEvents[a].Name + ' <none>')
5638 else
5639 g_Console_Add(gEvents[a].Name + ' "' + gEvents[a].Command + '"');
5640 Exit;
5641 end;
5642 for a := 0 to High(gEvents) do
5643 if gEvents[a].Name = P[1] then
5644 begin
5645 gEvents[a].Command := '';
5646 for b := 2 to High(P) do
5647 if Pos(' ', P[b]) = 0 then
5648 gEvents[a].Command := gEvents[a].Command + ' ' + P[b]
5649 else
5650 gEvents[a].Command := gEvents[a].Command + ' "' + P[b] + '"';
5651 gEvents[a].Command := Trim(gEvents[a].Command);
5652 Exit;
5653 end;
5654 end
5655 // Êîìàíäû Ñâîåé èãðû:
5656 else if gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT] then
5657 begin
5658 if cmd = 'bot_addred' then
5659 begin
5660 if Length(P) > 1 then
5661 g_Bot_Add(TEAM_RED, StrToIntDef(P[1], 2))
5662 else
5663 g_Bot_Add(TEAM_RED, 2);
5664 end
5665 else if cmd = 'bot_addblue' then
5666 begin
5667 if Length(P) > 1 then
5668 g_Bot_Add(TEAM_BLUE, StrToIntDef(P[1], 2))
5669 else
5670 g_Bot_Add(TEAM_BLUE, 2);
5671 end
5672 else if cmd = 'suicide' then
5673 begin
5674 if gGameOn then
5675 begin
5676 if g_Game_IsClient then
5677 MC_SEND_CheatRequest(NET_CHEAT_SUICIDE)
5678 else
5679 begin
5680 if gPlayer1 <> nil then
5681 gPlayer1.Damage(SUICIDE_DAMAGE, gPlayer1.UID, 0, 0, HIT_SELF);
5682 if gPlayer2 <> nil then
5683 gPlayer2.Damage(SUICIDE_DAMAGE, gPlayer2.UID, 0, 0, HIT_SELF);
5684 end;
5685 end;
5686 end
5687 else if cmd = 'spectate' then
5688 begin
5689 if not gGameOn then
5690 Exit;
5691 g_Game_Spectate();
5692 end
5693 else if cmd = 'say' then
5694 begin
5695 if g_Game_IsServer and g_Game_IsNet then
5696 begin
5697 if Length(P) > 1 then
5698 begin
5699 chstr := '';
5700 for a := 1 to High(P) do
5701 chstr := chstr + P[a] + ' ';
5703 if Length(chstr) > 200 then SetLength(chstr, 200);
5705 if Length(chstr) < 1 then
5706 begin
5707 g_Console_Add('say <text>');
5708 Exit;
5709 end;
5711 chstr := b_Text_Format(chstr);
5712 MH_SEND_Chat(chstr, NET_CHAT_PLAYER);
5713 end
5714 else g_Console_Add('say <text>');
5715 end else
5716 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5717 end
5718 else if cmd = 'tell' then
5719 begin
5720 if g_Game_IsServer and g_Game_IsNet then
5721 begin
5722 if (Length(P) > 2) and (P[1] <> '') then
5723 begin
5724 chstr := '';
5725 for a := 2 to High(P) do
5726 chstr := chstr + P[a] + ' ';
5728 if Length(chstr) > 200 then SetLength(chstr, 200);
5730 if Length(chstr) < 1 then
5731 begin
5732 g_Console_Add('tell <playername> <text>');
5733 Exit;
5734 end;
5736 pl := g_Net_Client_ByName(P[1]);
5737 if pl <> nil then
5738 MH_SEND_Chat(b_Text_Format(chstr), NET_CHAT_PLAYER, pl^.ID)
5739 else
5740 g_Console_Add(Format(_lc[I_NET_ERR_NAME404], [P[1]]));
5741 end
5742 else g_Console_Add('tell <playername> <text>');
5743 end else
5744 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5745 end
5746 else if (cmd = 'overtime') and not g_Game_IsClient then
5747 begin
5748 if (Length(P) = 1) or (StrToIntDef(P[1], -1) <= 0) then
5749 Exit;
5750 // Äîïîëíèòåëüíîå âðåìÿ:
5751 gGameSettings.TimeLimit := (gTime - gGameStartTime) div 1000 + Word(StrToIntDef(P[1], 0));
5753 g_Console_Add(Format(_lc[I_MSG_TIME_LIMIT],
5754 [gGameSettings.TimeLimit div 3600,
5755 (gGameSettings.TimeLimit div 60) mod 60,
5756 gGameSettings.TimeLimit mod 60]));
5757 if g_Game_IsNet then MH_SEND_GameSettings;
5758 end
5759 else if (cmd = 'rcon_password') and g_Game_IsClient then
5760 begin
5761 if (Length(P) <= 1) then
5762 g_Console_Add('rcon_password <password>')
5763 else
5764 MC_SEND_RCONPassword(P[1]);
5765 end
5766 else if cmd = 'rcon' then
5767 begin
5768 if g_Game_IsClient then
5769 begin
5770 if Length(P) > 1 then
5771 begin
5772 chstr := '';
5773 for a := 1 to High(P) do
5774 chstr := chstr + P[a] + ' ';
5776 if Length(chstr) > 200 then SetLength(chstr, 200);
5778 if Length(chstr) < 1 then
5779 begin
5780 g_Console_Add('rcon <command>');
5781 Exit;
5782 end;
5784 MC_SEND_RCONCommand(chstr);
5785 end
5786 else g_Console_Add('rcon <command>');
5787 end;
5788 end
5789 else if cmd = 'ready' then
5790 begin
5791 if g_Game_IsServer and (gLMSRespawn = LMS_RESPAWN_WARMUP) then
5792 gLMSRespawnTime := gTime + 100;
5793 end
5794 else if (cmd = 'callvote') and g_Game_IsNet then
5795 begin
5796 if Length(P) > 1 then
5797 begin
5798 chstr := '';
5799 for a := 1 to High(P) do begin
5800 if a > 1 then chstr := chstr + ' ';
5801 chstr := chstr + P[a];
5802 end;
5804 if Length(chstr) > 200 then SetLength(chstr, 200);
5806 if Length(chstr) < 1 then
5807 begin
5808 g_Console_Add('callvote <command>');
5809 Exit;
5810 end;
5812 if g_Game_IsClient then
5813 MC_SEND_Vote(True, chstr)
5814 else
5815 g_Game_StartVote(chstr, gPlayer1Settings.Name);
5816 g_Console_Process('vote', True);
5817 end
5818 else
5819 g_Console_Add('callvote <command>');
5820 end
5821 else if (cmd = 'vote') and g_Game_IsNet then
5822 begin
5823 if g_Game_IsClient then
5824 MC_SEND_Vote(False)
5825 else if gVoteInProgress then
5826 begin
5827 if (gPlayer1 <> nil) or (gPlayer2 <> nil) then
5828 a := Floor((NetClientCount+1)/2.0) + 1
5829 else
5830 a := Floor(NetClientCount/2.0) + 1;
5831 if gVoted then
5832 begin
5833 Dec(gVoteCount);
5834 gVoted := False;
5835 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_REVOKED], [gPlayer1Settings.Name, gVoteCount, a]), True);
5836 MH_SEND_VoteEvent(NET_VE_REVOKE, gPlayer1Settings.Name, 'a', gVoteCount, a);
5837 end
5838 else
5839 begin
5840 Inc(gVoteCount);
5841 gVoted := True;
5842 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_VOTE], [gPlayer1Settings.Name, gVoteCount, a]), True);
5843 MH_SEND_VoteEvent(NET_VE_VOTE, gPlayer1Settings.Name, 'a', gVoteCount, a);
5844 g_Game_CheckVote;
5845 end;
5846 end;
5847 end
5848 end;
5849 end;
5851 procedure g_TakeScreenShot();
5852 var
5853 a: Word;
5854 FileName: string;
5855 ssdir, t: string;
5856 st: TStream;
5857 ok: Boolean;
5858 begin
5859 if e_NoGraphics then Exit;
5860 ssdir := GameDir+'/screenshots';
5861 if not findFileCI(ssdir, true) then
5862 begin
5863 // try to create dir
5864 try
5865 CreateDir(ssdir);
5866 except
5867 end;
5868 if not findFileCI(ssdir, true) then exit; // alas
5869 end;
5870 try
5871 for a := 1 to High(Word) do
5872 begin
5873 FileName := Format(ssdir+'screenshot%.3d.png', [a]);
5874 t := FileName;
5875 if findFileCI(t, true) then continue;
5876 if not findFileCI(FileName) then
5877 begin
5878 ok := false;
5879 st := createDiskFile(FileName);
5880 try
5881 e_MakeScreenshot(st, gScreenWidth, gScreenHeight);
5882 ok := true;
5883 finally
5884 st.Free();
5885 end;
5886 if not ok then try DeleteFile(FileName); except end else g_Console_Add(Format(_lc[I_CONSOLE_SCREENSHOT], [ExtractFileName(FileName)]));
5887 break;
5888 end;
5889 end;
5890 except
5891 end;
5892 end;
5894 procedure g_Game_InGameMenu(Show: Boolean);
5895 begin
5896 if (g_ActiveWindow = nil) and Show then
5897 begin
5898 if gGameSettings.GameType = GT_SINGLE then
5899 g_GUI_ShowWindow('GameSingleMenu')
5900 else
5901 begin
5902 if g_Game_IsClient then
5903 g_GUI_ShowWindow('GameClientMenu')
5904 else
5905 if g_Game_IsNet then
5906 g_GUI_ShowWindow('GameServerMenu')
5907 else
5908 g_GUI_ShowWindow('GameCustomMenu');
5909 end;
5910 g_Sound_PlayEx('MENU_OPEN');
5912 // Ïàóçà ïðè ìåíþ òîëüêî â îäèíî÷íîé èãðå:
5913 if (not g_Game_IsNet) then
5914 g_Game_Pause(True);
5915 end
5916 else
5917 if (g_ActiveWindow <> nil) and (not Show) then
5918 begin
5919 // Ïàóçà ïðè ìåíþ òîëüêî â îäèíî÷íîé èãðå:
5920 if (not g_Game_IsNet) then
5921 g_Game_Pause(False);
5922 end;
5923 end;
5925 procedure g_Game_Pause(Enable: Boolean);
5926 begin
5927 if not gGameOn then
5928 Exit;
5930 if gPause = Enable then
5931 Exit;
5933 if not (gGameSettings.GameType in [GT_SINGLE, GT_CUSTOM]) then
5934 Exit;
5936 gPause := Enable;
5937 g_Game_PauseAllSounds(Enable);
5938 end;
5940 procedure g_Game_PauseAllSounds(Enable: Boolean);
5941 var
5942 i: Integer;
5943 begin
5944 // Òðèããåðû:
5945 if gTriggers <> nil then
5946 for i := 0 to High(gTriggers) do
5947 with gTriggers[i] do
5948 if (TriggerType = TRIGGER_SOUND) and
5949 (Sound <> nil) and
5950 Sound.IsPlaying() then
5951 begin
5952 Sound.Pause(Enable);
5953 end;
5955 // Çâóêè èãðîêîâ:
5956 if gPlayers <> nil then
5957 for i := 0 to High(gPlayers) do
5958 if gPlayers[i] <> nil then
5959 gPlayers[i].PauseSounds(Enable);
5961 // Ìóçûêà:
5962 if gMusic <> nil then
5963 gMusic.Pause(Enable);
5964 end;
5966 procedure g_Game_StopAllSounds(all: Boolean);
5967 var
5968 i: Integer;
5969 begin
5970 if gTriggers <> nil then
5971 for i := 0 to High(gTriggers) do
5972 with gTriggers[i] do
5973 if (TriggerType = TRIGGER_SOUND) and
5974 (Sound <> nil) then
5975 Sound.Stop();
5977 if gMusic <> nil then
5978 gMusic.Stop();
5980 if all then
5981 e_StopChannels();
5982 end;
5984 procedure g_Game_UpdateTriggerSounds();
5985 var
5986 i: Integer;
5987 begin
5988 if gTriggers <> nil then
5989 for i := 0 to High(gTriggers) do
5990 with gTriggers[i] do
5991 if (TriggerType = TRIGGER_SOUND) and
5992 (Sound <> nil) and
5993 (Data.Local) and
5994 Sound.IsPlaying() then
5995 begin
5996 if ((gPlayer1 <> nil) and g_CollidePoint(gPlayer1.GameX, gPlayer1.GameY, X, Y, Width, Height)) or
5997 ((gPlayer2 <> nil) and g_CollidePoint(gPlayer2.GameX, gPlayer2.GameY, X, Y, Width, Height)) then
5998 begin
5999 Sound.SetPan(0.5 - Data.Pan/255.0);
6000 Sound.SetVolume(Data.Volume/255.0);
6001 end
6002 else
6003 Sound.SetCoords(X+(Width div 2), Y+(Height div 2), Data.Volume/255.0);
6004 end;
6005 end;
6007 function g_Game_IsWatchedPlayer(UID: Word): Boolean;
6008 begin
6009 Result := False;
6010 if (gPlayer1 <> nil) and (gPlayer1.UID = UID) then
6011 begin
6012 Result := True;
6013 Exit;
6014 end;
6015 if (gPlayer2 <> nil) and (gPlayer2.UID = UID) then
6016 begin
6017 Result := True;
6018 Exit;
6019 end;
6020 if gSpectMode <> SPECT_PLAYERS then
6021 Exit;
6022 if gSpectPID1 = UID then
6023 begin
6024 Result := True;
6025 Exit;
6026 end;
6027 if gSpectViewTwo and (gSpectPID2 = UID) then
6028 begin
6029 Result := True;
6030 Exit;
6031 end;
6032 end;
6034 function g_Game_IsWatchedTeam(Team: Byte): Boolean;
6035 var
6036 Pl: TPlayer;
6037 begin
6038 Result := False;
6039 if (gPlayer1 <> nil) and (gPlayer1.Team = Team) then
6040 begin
6041 Result := True;
6042 Exit;
6043 end;
6044 if (gPlayer2 <> nil) and (gPlayer2.Team = Team) then
6045 begin
6046 Result := True;
6047 Exit;
6048 end;
6049 if gSpectMode <> SPECT_PLAYERS then
6050 Exit;
6051 Pl := g_Player_Get(gSpectPID1);
6052 if (Pl <> nil) and (Pl.Team = Team) then
6053 begin
6054 Result := True;
6055 Exit;
6056 end;
6057 if gSpectViewTwo then
6058 begin
6059 Pl := g_Player_Get(gSpectPID2);
6060 if (Pl <> nil) and (Pl.Team = Team) then
6061 begin
6062 Result := True;
6063 Exit;
6064 end;
6065 end;
6066 end;
6068 procedure g_Game_Message(Msg: string; Time: Word);
6069 begin
6070 MessageText := b_Text_Format(Msg);
6071 MessageTime := Time;
6072 end;
6074 procedure g_Game_Announce_GoodShot(SpawnerUID: Word);
6075 var
6076 a: Integer;
6077 begin
6078 case gAnnouncer of
6079 ANNOUNCE_NONE:
6080 Exit;
6081 ANNOUNCE_ME,
6082 ANNOUNCE_MEPLUS:
6083 if not g_Game_IsWatchedPlayer(SpawnerUID) then
6084 Exit;
6085 end;
6086 for a := 0 to 3 do
6087 if goodsnd[a].IsPlaying() then
6088 Exit;
6090 goodsnd[Random(4)].Play();
6091 end;
6093 procedure g_Game_Announce_KillCombo(Param: Integer);
6094 var
6095 UID: Word;
6096 c, n: Byte;
6097 Pl: TPlayer;
6098 Name: String;
6099 begin
6100 UID := Param and $FFFF;
6101 c := Param shr 16;
6102 if c < 2 then
6103 Exit;
6105 Pl := g_Player_Get(UID);
6106 if Pl = nil then
6107 Name := '?'
6108 else
6109 Name := Pl.Name;
6111 case c of
6112 2: begin
6113 n := 0;
6114 g_Console_Add(Format(_lc[I_PLAYER_KILL_2X], [Name]), True);
6115 end;
6116 3: begin
6117 n := 1;
6118 g_Console_Add(Format(_lc[I_PLAYER_KILL_3X], [Name]), True);
6119 end;
6120 4: begin
6121 n := 2;
6122 g_Console_Add(Format(_lc[I_PLAYER_KILL_4X], [Name]), True);
6123 end;
6124 else begin
6125 n := 3;
6126 g_Console_Add(Format(_lc[I_PLAYER_KILL_MX], [Name]), True);
6127 end;
6128 end;
6130 case gAnnouncer of
6131 ANNOUNCE_NONE:
6132 Exit;
6133 ANNOUNCE_ME:
6134 if not g_Game_IsWatchedPlayer(UID) then
6135 Exit;
6136 ANNOUNCE_MEPLUS:
6137 if (not g_Game_IsWatchedPlayer(UID)) and (c < 4) then
6138 Exit;
6139 end;
6141 if killsnd[n].IsPlaying() then
6142 killsnd[n].Stop();
6143 killsnd[n].Play();
6144 end;
6146 procedure g_Game_StartVote(Command, Initiator: string);
6147 var
6148 Need: Integer;
6149 begin
6150 if not gVotesEnabled then Exit;
6151 if gGameSettings.GameType <> GT_SERVER then Exit;
6152 if gVoteInProgress or gVotePassed then
6153 begin
6154 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_INPROGRESS], [gVoteCommand]), True);
6155 MH_SEND_VoteEvent(NET_VE_INPROGRESS, gVoteCommand);
6156 Exit;
6157 end;
6158 gVoteInProgress := True;
6159 gVotePassed := False;
6160 gVoteTimer := gTime + gVoteTimeout * 1000;
6161 gVoteCount := 0;
6162 gVoted := False;
6163 gVoteCommand := Command;
6165 if (gPlayer1 <> nil) or (gPlayer2 <> nil) then
6166 Need := Floor((NetClientCount+1)/2.0)+1
6167 else
6168 Need := Floor(NetClientCount/2.0)+1;
6169 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_STARTED], [Initiator, Command, Need]), True);
6170 MH_SEND_VoteEvent(NET_VE_STARTED, Initiator, Command, Need);
6171 end;
6173 procedure g_Game_CheckVote;
6174 var
6175 I, Need: Integer;
6176 begin
6177 if gGameSettings.GameType <> GT_SERVER then Exit;
6178 if not gVoteInProgress then Exit;
6180 if (gTime >= gVoteTimer) then
6181 begin
6182 if (gPlayer1 <> nil) or (gPlayer2 <> nil) then
6183 Need := Floor((NetClientCount+1)/2.0) + 1
6184 else
6185 Need := Floor(NetClientCount/2.0) + 1;
6186 if gVoteCount >= Need then
6187 begin
6188 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_PASSED], [gVoteCommand]), True);
6189 MH_SEND_VoteEvent(NET_VE_PASSED, gVoteCommand);
6190 gVotePassed := True;
6191 gVoteCmdTimer := gTime + 5000;
6192 end
6193 else
6194 begin
6195 g_Console_Add(_lc[I_MESSAGE_VOTE_FAILED], True);
6196 MH_SEND_VoteEvent(NET_VE_FAILED);
6197 end;
6198 if NetClients <> nil then
6199 for I := Low(NetClients) to High(NetClients) do
6200 if NetClients[i].Used then
6201 NetClients[i].Voted := False;
6202 gVoteInProgress := False;
6203 gVoted := False;
6204 gVoteCount := 0;
6205 end
6206 else
6207 begin
6208 if (gPlayer1 <> nil) or (gPlayer2 <> nil) then
6209 Need := Floor((NetClientCount+1)/2.0) + 1
6210 else
6211 Need := Floor(NetClientCount/2.0) + 1;
6212 if gVoteCount >= Need then
6213 begin
6214 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_PASSED], [gVoteCommand]), True);
6215 MH_SEND_VoteEvent(NET_VE_PASSED, gVoteCommand);
6216 gVoteInProgress := False;
6217 gVotePassed := True;
6218 gVoteCmdTimer := gTime + 5000;
6219 gVoted := False;
6220 gVoteCount := 0;
6221 if NetClients <> nil then
6222 for I := Low(NetClients) to High(NetClients) do
6223 if NetClients[i].Used then
6224 NetClients[i].Voted := False;
6225 end;
6226 end;
6227 end;
6229 procedure g_Game_LoadMapList(FileName: string);
6230 var
6231 ListFile: TextFile;
6232 s: string;
6233 begin
6234 MapList := nil;
6235 MapIndex := -1;
6237 if not FileExists(FileName) then Exit;
6239 AssignFile(ListFile, FileName);
6240 Reset(ListFile);
6241 while not EOF(ListFile) do
6242 begin
6243 ReadLn(ListFile, s);
6245 s := Trim(s);
6246 if s = '' then Continue;
6248 SetLength(MapList, Length(MapList)+1);
6249 MapList[High(MapList)] := s;
6250 end;
6251 CloseFile(ListFile);
6252 end;
6254 procedure g_Game_SetDebugMode();
6255 begin
6256 gDebugMode := True;
6257 // ×èòû (äàæå â ñâîåé èãðå):
6258 gCheats := True;
6259 end;
6261 procedure g_Game_SetLoadingText(Text: String; Max: Integer; reWrite: Boolean);
6262 var
6263 i: Word;
6264 begin
6265 if Length(LoadingStat.Msgs) = 0 then
6266 Exit;
6268 with LoadingStat do
6269 begin
6270 if not reWrite then
6271 begin // Ïåðåõîäèì íà ñëåäóþùóþ ñòðîêó èëè ñêðîëëèðóåì:
6272 if NextMsg = Length(Msgs) then
6273 begin // scroll
6274 for i := 0 to High(Msgs)-1 do
6275 Msgs[i] := Msgs[i+1];
6276 end
6277 else
6278 Inc(NextMsg);
6279 end else
6280 if NextMsg = 0 then
6281 Inc(NextMsg);
6283 Msgs[NextMsg-1] := Text;
6284 CurValue := 0;
6285 MaxValue := Max;
6286 ShowCount := 0;
6287 end;
6289 g_ActiveWindow := nil;
6291 ProcessLoading;
6292 end;
6294 procedure g_Game_StepLoading();
6295 begin
6296 with LoadingStat do
6297 begin
6298 Inc(CurValue);
6299 Inc(ShowCount);
6300 if (ShowCount > LOADING_SHOW_STEP) then
6301 begin
6302 ShowCount := 0;
6303 ProcessLoading;
6304 end;
6305 end;
6306 end;
6308 procedure g_Game_ClearLoading();
6309 var
6310 len: Word;
6311 begin
6312 with LoadingStat do
6313 begin
6314 CurValue := 0;
6315 MaxValue := 0;
6316 ShowCount := 0;
6317 len := ((gScreenHeight div 3)*2 - 50) div LOADING_INTERLINE;
6318 if len < 1 then len := 1;
6319 SetLength(Msgs, len);
6320 for len := Low(Msgs) to High(Msgs) do
6321 Msgs[len] := '';
6322 NextMsg := 0;
6323 end;
6324 end;
6326 procedure Parse_Params(var pars: TParamStrValues);
6327 var
6328 i: Integer;
6329 s: String;
6330 begin
6331 SetLength(pars, 0);
6332 i := 1;
6333 while i <= ParamCount do
6334 begin
6335 s := ParamStr(i);
6336 if (s[1] = '-') and (Length(s) > 1) then
6337 begin
6338 if (s[2] = '-') and (Length(s) > 2) then
6339 begin // Îäèíî÷íûé ïàðàìåòð
6340 SetLength(pars, Length(pars) + 1);
6341 with pars[High(pars)] do
6342 begin
6343 Name := LowerCase(s);
6344 Value := '+';
6345 end;
6346 end
6347 else
6348 if (i < ParamCount) then
6349 begin // Ïàðàìåòð ñî çíà÷åíèåì
6350 Inc(i);
6351 SetLength(pars, Length(pars) + 1);
6352 with pars[High(pars)] do
6353 begin
6354 Name := LowerCase(s);
6355 Value := LowerCase(ParamStr(i));
6356 end;
6357 end;
6358 end;
6360 Inc(i);
6361 end;
6362 end;
6364 function Find_Param_Value(var pars: TParamStrValues; aName: String): String;
6365 var
6366 i: Integer;
6367 begin
6368 Result := '';
6369 for i := 0 to High(pars) do
6370 if pars[i].Name = aName then
6371 begin
6372 Result := pars[i].Value;
6373 Break;
6374 end;
6375 end;
6377 procedure g_Game_Process_Params();
6378 var
6379 pars: TParamStrValues;
6380 map: String;
6381 GMode, n: Byte;
6382 LimT, LimS: Integer;
6383 Opt: LongWord;
6384 Lives: Integer;
6385 s: String;
6386 Port: Integer;
6387 ip: String;
6388 F: TextFile;
6389 begin
6390 Parse_Params(pars);
6392 // Debug mode:
6393 s := Find_Param_Value(pars, '--debug');
6394 if (s <> '') then
6395 g_Game_SetDebugMode();
6397 // Connect when game loads
6398 ip := Find_Param_Value(pars, '-connect');
6400 if ip <> '' then
6401 begin
6402 s := Find_Param_Value(pars, '-port');
6403 if (s = '') or not TryStrToInt(s, Port) then
6404 Port := 25666;
6406 s := Find_Param_Value(pars, '-pw');
6408 g_Game_StartClient(ip, Port, s);
6409 Exit;
6410 end;
6412 // Start map when game loads:
6413 map := LowerCase(Find_Param_Value(pars, '-map'));
6414 if isWadPath(map) then
6415 begin
6416 // Game mode:
6417 s := Find_Param_Value(pars, '-gm');
6418 GMode := g_Game_TextToMode(s);
6419 if GMode = GM_NONE then GMode := GM_DM;
6420 if GMode = GM_SINGLE then GMode := GM_COOP;
6422 // Time limit:
6423 s := Find_Param_Value(pars, '-limt');
6424 if (s = '') or (not TryStrToInt(s, LimT)) then
6425 LimT := 0;
6426 if LimT < 0 then
6427 LimT := 0;
6429 // Goal limit:
6430 s := Find_Param_Value(pars, '-lims');
6431 if (s = '') or (not TryStrToInt(s, LimS)) then
6432 LimS := 0;
6433 if LimS < 0 then
6434 LimS := 0;
6436 // Lives limit:
6437 s := Find_Param_Value(pars, '-lives');
6438 if (s = '') or (not TryStrToInt(s, Lives)) then
6439 Lives := 0;
6440 if Lives < 0 then
6441 Lives := 0;
6443 // Options:
6444 s := Find_Param_Value(pars, '-opt');
6445 if (s = '') then
6446 Opt := GAME_OPTION_ALLOWEXIT or GAME_OPTION_BOTVSPLAYER or GAME_OPTION_BOTVSMONSTER
6447 else
6448 Opt := StrToIntDef(s, 0);
6449 if Opt = 0 then
6450 Opt := GAME_OPTION_ALLOWEXIT or GAME_OPTION_BOTVSPLAYER or GAME_OPTION_BOTVSMONSTER;
6452 // Close after map:
6453 s := Find_Param_Value(pars, '--close');
6454 if (s <> '') then
6455 gMapOnce := True;
6457 // Delete test map after play:
6458 s := Find_Param_Value(pars, '--testdelete');
6459 if (s <> '') then
6460 begin
6461 gMapToDelete := MapsDir + map;
6462 e_WriteLog('"--testdelete" is deprecated, use --tempdelete.', MSG_FATALERROR);
6463 Halt(1);
6464 end;
6466 // Delete temporary WAD after play:
6467 s := Find_Param_Value(pars, '--tempdelete');
6468 if (s <> '') then
6469 begin
6470 gMapToDelete := MapsDir + map;
6471 gTempDelete := True;
6472 end;
6474 // Number of players:
6475 s := Find_Param_Value(pars, '-pl');
6476 if (s = '') then
6477 n := 1
6478 else
6479 n := StrToIntDef(s, 1);
6481 // Start:
6482 s := Find_Param_Value(pars, '-port');
6483 if (s = '') or not TryStrToInt(s, Port) then
6484 g_Game_StartCustom(map, GMode, LimT, LimS, Lives, Opt, n)
6485 else
6486 g_Game_StartServer(map, GMode, LimT, LimS, Lives, Opt, n, 0, Port);
6487 end;
6489 // Execute script when game loads:
6490 s := Find_Param_Value(pars, '-exec');
6491 if s <> '' then
6492 begin
6493 if Pos(':\', s) = 0 then
6494 s := GameDir + '/' + s;
6496 {$I-}
6497 AssignFile(F, s);
6498 Reset(F);
6499 if IOResult <> 0 then
6500 begin
6501 e_WriteLog(Format(_lc[I_SIMPLE_ERROR], ['Failed to read file: ' + s]), MSG_WARNING);
6502 g_Console_Add(Format(_lc[I_CONSOLE_ERROR_READ], [s]));
6503 CloseFile(F);
6504 Exit;
6505 end;
6506 e_WriteLog('Executing script: ' + s, MSG_NOTIFY);
6507 g_Console_Add(Format(_lc[I_CONSOLE_EXEC], [s]));
6509 while not EOF(F) do
6510 begin
6511 ReadLn(F, s);
6512 if IOResult <> 0 then
6513 begin
6514 e_WriteLog(Format(_lc[I_SIMPLE_ERROR], ['Failed to read file: ' + s]), MSG_WARNING);
6515 g_Console_Add(Format(_lc[I_CONSOLE_ERROR_READ], [s]));
6516 CloseFile(F);
6517 Exit;
6518 end;
6519 if Pos('#', s) <> 1 then // script comment
6520 g_Console_Process(s, True);
6521 end;
6523 CloseFile(F);
6524 {$I+}
6525 end;
6527 SetLength(pars, 0);
6528 end;
6530 end.