DEADSOFTWARE

916602132bc0127a3268d6e6cc8c47e9fedadd12
[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, g_scripts, 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 g_Scripts_Init();
1109 g_Scripts_Load('game.conprint("Scripts Init")');
1111 gMusic := TMusic.Create();
1112 gMusic.SetByName('MUSIC_MENU');
1113 gMusic.Play();
1115 gGameSettings.WarmupTime := 30;
1117 gState := STATE_MENU;
1119 SetLength(gEvents, 6);
1120 gEvents[0].Name := 'ongamestart';
1121 gEvents[1].Name := 'ongameend';
1122 gEvents[2].Name := 'onmapstart';
1123 gEvents[3].Name := 'onmapend';
1124 gEvents[4].Name := 'oninter';
1125 gEvents[5].Name := 'onwadend';
1126 finally
1127 sfsGCEnable(); // enable releasing unused volumes
1128 end;
1129 end;
1131 procedure g_Game_Free();
1132 begin
1133 if NetMode = NET_CLIENT then g_Net_Disconnect();
1134 if NetMode = NET_SERVER then g_Net_Host_Die();
1136 g_Map_Free();
1137 g_Player_Free();
1138 g_Player_RemoveAllCorpses();
1140 gGameSettings.GameType := GT_NONE;
1141 if gGameSettings.GameMode = GM_SINGLE then
1142 gGameSettings.GameMode := GM_DM;
1143 gSwitchGameMode := gGameSettings.GameMode;
1145 gChatShow := False;
1146 gExitByTrigger := False;
1147 end;
1149 function IsActivePlayer(p: TPlayer): Boolean;
1150 begin
1151 Result := False;
1152 if p = nil then
1153 Exit;
1154 Result := (not p.FDummy) and (not p.FSpectator);
1155 end;
1157 function GetActivePlayer_ByID(ID: Integer): TPlayer;
1158 var
1159 a: Integer;
1160 begin
1161 Result := nil;
1162 if ID < 0 then
1163 Exit;
1164 if gPlayers = nil then
1165 Exit;
1166 for a := Low(gPlayers) to High(gPlayers) do
1167 if IsActivePlayer(gPlayers[a]) then
1168 begin
1169 if gPlayers[a].UID <> ID then
1170 continue;
1171 Result := gPlayers[a];
1172 break;
1173 end;
1174 end;
1176 function GetActivePlayerID_Next(Skip: Integer = -1): Integer;
1177 var
1178 a, idx: Integer;
1179 ids: Array of Word;
1180 begin
1181 Result := -1;
1182 if gPlayers = nil then
1183 Exit;
1184 SetLength(ids, 0);
1185 idx := -1;
1186 for a := Low(gPlayers) to High(gPlayers) do
1187 if IsActivePlayer(gPlayers[a]) then
1188 begin
1189 SetLength(ids, Length(ids) + 1);
1190 ids[High(ids)] := gPlayers[a].UID;
1191 if gPlayers[a].UID = Skip then
1192 idx := High(ids);
1193 end;
1194 if Length(ids) = 0 then
1195 Exit;
1196 if idx = -1 then
1197 Result := ids[0]
1198 else
1199 Result := ids[(idx + 1) mod Length(ids)];
1200 end;
1202 function GetActivePlayerID_Prev(Skip: Integer = -1): Integer;
1203 var
1204 a, idx: Integer;
1205 ids: Array of Word;
1206 begin
1207 Result := -1;
1208 if gPlayers = nil then
1209 Exit;
1210 SetLength(ids, 0);
1211 idx := -1;
1212 for a := Low(gPlayers) to High(gPlayers) do
1213 if IsActivePlayer(gPlayers[a]) then
1214 begin
1215 SetLength(ids, Length(ids) + 1);
1216 ids[High(ids)] := gPlayers[a].UID;
1217 if gPlayers[a].UID = Skip then
1218 idx := High(ids);
1219 end;
1220 if Length(ids) = 0 then
1221 Exit;
1222 if idx = -1 then
1223 Result := ids[Length(ids) - 1]
1224 else
1225 Result := ids[(Length(ids) - 1 + idx) mod Length(ids)];
1226 end;
1228 function isKeyPressed (key1: Word; key2: Word): Boolean;
1229 begin
1230 if (key1 <> 0) and e_KeyPressed(key1) then begin result := true; exit; end;
1231 if (key2 <> 0) and e_KeyPressed(key2) then begin result := true; exit; end;
1232 result := false;
1233 end;
1235 procedure processPlayerControls (plr: TPlayer; var ctrl: TPlayerControl; var MoveButton: Byte; p2hack: Boolean=false);
1236 var
1237 time: Word;
1238 strafeDir: Byte;
1239 begin
1240 if (plr = nil) then exit;
1241 if (p2hack) then time := 1000 else time := 1;
1242 strafeDir := MoveButton shr 4;
1243 MoveButton := MoveButton and $0F;
1244 with ctrl do
1245 begin
1246 if isKeyPressed(KeyLeft, KeyLeft2) and (not isKeyPressed(KeyRight, KeyRight2)) then MoveButton := 1 // Íàæàòà òîëüêî "Âëåâî"
1247 else if (not isKeyPressed(KeyLeft, KeyLeft2)) and isKeyPressed(KeyRight, KeyRight2) then MoveButton := 2 // Íàæàòà òîëüêî "Âïðàâî"
1248 else if (not isKeyPressed(KeyLeft, KeyLeft2)) and (not isKeyPressed(KeyRight, KeyRight2)) then MoveButton := 0; // Íå íàæàòû íè "Âëåâî", íè "Âïðàâî"
1250 // Ñåé÷àñ èëè ðàíüøå áûëè íàæàòû "Âëåâî"/"Âïðàâî" => ïåðåäàåì èãðîêó:
1251 if MoveButton = 1 then plr.PressKey(KEY_LEFT, time)
1252 else if MoveButton = 2 then plr.PressKey(KEY_RIGHT, time);
1254 // if we have "strafe" key, turn off old strafe mechanics
1255 if isKeyPressed(KeyStrafe, KeyStrafe2) then
1256 begin
1257 // new strafe mechanics
1258 if (strafeDir = 0) then strafeDir := MoveButton; // start strafing
1259 // now set direction according to strafe (reversed)
1260 if (strafeDir = 2) then plr.SetDirection(D_LEFT)
1261 else if (strafeDir = 1) then plr.SetDirection(D_RIGHT);
1262 end
1263 else
1264 begin
1265 strafeDir := 0; // not strafing anymore
1266 // Ðàíüøå áûëà íàæàòà "Âïðàâî", à ñåé÷àñ "Âëåâî" => áåæèì âïðàâî, ñìîòðèì âëåâî:
1267 if (MoveButton = 2) and isKeyPressed(KeyLeft, KeyLeft2) then plr.SetDirection(D_LEFT)
1268 // Ðàíüøå áûëà íàæàòà "Âëåâî", à ñåé÷àñ "Âïðàâî" => áåæèì âëåâî, ñìîòðèì âïðàâî:
1269 else if (MoveButton = 1) and isKeyPressed(KeyRight, KeyRight2) then plr.SetDirection(D_RIGHT)
1270 // ×òî-òî áûëî íàæàòî è íå èçìåíèëîñü => êóäà áåæèì, òóäà è ñìîòðèì:
1271 else if MoveButton <> 0 then plr.SetDirection(TDirection(MoveButton-1));
1272 end;
1274 // fix movebutton state
1275 MoveButton := MoveButton or (strafeDir shl 4);
1277 // Îñòàëüíûå êëàâèøè:
1278 if isKeyPressed(KeyJump, KeyJump2) then plr.PressKey(KEY_JUMP, time);
1279 if isKeyPressed(KeyUp, KeyUp2) then plr.PressKey(KEY_UP, time);
1280 if isKeyPressed(KeyDown, KeyDown2) then plr.PressKey(KEY_DOWN, time);
1281 if isKeyPressed(KeyFire, KeyFire2) then plr.PressKey(KEY_FIRE);
1282 if isKeyPressed(KeyNextWeapon, KeyNextWeapon2) then plr.PressKey(KEY_NEXTWEAPON);
1283 if isKeyPressed(KeyPrevWeapon, KeyPrevWeapon2) then plr.PressKey(KEY_PREVWEAPON);
1284 if isKeyPressed(KeyOpen, KeyOpen2) then plr.PressKey(KEY_OPEN);
1285 end;
1286 end;
1288 procedure g_Game_Update();
1289 var
1290 Msg: g_gui.TMessage;
1291 Time: Int64;
1292 a: Byte;
1293 w: Word;
1294 i, b: Integer;
1295 begin
1296 // Ïîðà âûêëþ÷àòü èãðó:
1297 if gExit = EXIT_QUIT then
1298 Exit;
1299 // Èãðà çàêîí÷èëàñü - îáðàáàòûâàåì:
1300 if gExit <> 0 then
1301 begin
1302 EndGame();
1303 if gExit = EXIT_QUIT then
1304 Exit;
1305 end;
1307 // ×èòàåì êëàâèàòóðó è äæîéñòèê, åñëè îêíî àêòèâíî:
1308 e_PollInput();
1310 // Îáíîâëÿåì êîíñîëü (äâèæåíèå è ñîîáùåíèÿ):
1311 g_Console_Update();
1313 if (NetMode = NET_NONE) and (g_Game_IsNet) and (gGameOn or (gState in [STATE_FOLD, STATE_INTERCUSTOM])) then
1314 begin
1315 gExit := EXIT_SIMPLE;
1316 EndGame();
1317 Exit;
1318 end;
1320 case gState of
1321 STATE_INTERSINGLE, // Ñòàòèñòêà ïîñëå ïðîõîæäåíèÿ óðîâíÿ â Îäèíî÷íîé èãðå
1322 STATE_INTERCUSTOM, // Ñòàòèñòêà ïîñëå ïðîõîæäåíèÿ óðîâíÿ â Ñâîåé èãðå
1323 STATE_INTERTEXT, // Òåêñò ìåæäó óðîâíÿìè
1324 STATE_INTERPIC: // Êàðòèíêà ìåæäó óðîâíÿìè
1325 begin
1326 if g_Game_IsNet and g_Game_IsServer then
1327 begin
1328 gInterTime := gInterTime + GAME_TICK;
1329 a := Min((gInterEndTime - gInterTime) div 1000 + 1, 255);
1330 if a <> gServInterTime then
1331 begin
1332 gServInterTime := a;
1333 MH_SEND_TimeSync(gServInterTime);
1334 end;
1335 end;
1337 if (not g_Game_IsClient) and
1340 (e_KeyPressed(IK_RETURN) or e_KeyPressed(IK_KPRETURN) or e_KeyPressed(IK_SPACE))
1341 and (not gJustChatted) and (not gConsoleShow) and (not gChatShow)
1342 and (g_ActiveWindow = nil)
1344 or (g_Game_IsNet and (gInterTime > gInterEndTime))
1346 then
1347 begin // Íàæàëè <Enter>/<Ïðîáåë> èëè ïðîøëî äîñòàòî÷íî âðåìåíè:
1348 g_Game_StopAllSounds(True);
1350 if gMapOnce then // Ýòî áûë òåñò
1351 gExit := EXIT_SIMPLE
1352 else
1353 if gNextMap <> '' then // Ïåðåõîäèì íà ñëåäóþùóþ êàðòó
1354 g_Game_ChangeMap(gNextMap)
1355 else // Ñëåäóþùåé êàðòû íåò
1356 begin
1357 if gGameSettings.GameType in [GT_CUSTOM, GT_SERVER] then
1358 begin
1359 // Âûõîä â ãëàâíîå ìåíþ:
1360 g_Game_Free;
1361 g_GUI_ShowWindow('MainMenu');
1362 gMusic.SetByName('MUSIC_MENU');
1363 gMusic.Play();
1364 gState := STATE_MENU;
1365 end else
1366 begin
1367 // Ôèíàëüíàÿ êàðòèíêà:
1368 g_Game_ExecuteEvent('onwadend');
1369 g_Game_Free();
1370 if not gMusic.SetByName('MUSIC_endmus') then
1371 gMusic.SetByName('MUSIC_STDENDMUS');
1372 gMusic.Play();
1373 gState := STATE_ENDPIC;
1374 end;
1375 g_Game_ExecuteEvent('ongameend');
1376 end;
1378 Exit;
1379 end;
1381 if gState = STATE_INTERTEXT then
1382 if InterText.counter > 0 then
1383 InterText.counter := InterText.counter - 1;
1384 end;
1386 STATE_FOLD: // Çàòóõàíèå ýêðàíà
1387 begin
1388 if EndingGameCounter = 0 then
1389 begin
1390 // Çàêîí÷èëñÿ óðîâåíü â Ñâîåé èãðå:
1391 if gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT] then
1392 begin
1393 if gLastMap and (gGameSettings.GameMode = GM_COOP) then
1394 begin
1395 g_Game_ExecuteEvent('onwadend');
1396 if not gMusic.SetByName('MUSIC_endmus') then
1397 gMusic.SetByName('MUSIC_STDENDMUS');
1398 end
1399 else
1400 gMusic.SetByName('MUSIC_ROUNDMUS');
1402 gMusic.Play();
1403 gState := STATE_INTERCUSTOM;
1404 end
1405 else // Çàêîí÷èëàñü ïîñëåäíÿÿ êàðòà â Îäèíî÷íîé èãðå
1406 begin
1407 gMusic.SetByName('MUSIC_INTERMUS');
1408 gMusic.Play();
1409 gState := STATE_INTERSINGLE;
1410 end;
1411 g_Game_ExecuteEvent('oninter');
1412 end
1413 else
1414 DecMin(EndingGameCounter, 6, 0);
1415 end;
1417 STATE_ENDPIC: // Êàðòèíêà îêîí÷àíèÿ ìåãàÂàäà
1418 begin
1419 if gMapOnce then // Ýòî áûë òåñò
1420 begin
1421 gExit := EXIT_SIMPLE;
1422 Exit;
1423 end;
1424 end;
1426 STATE_SLIST:
1427 g_Serverlist_Control(slCurrent);
1428 end;
1430 if g_Game_IsNet then
1431 if not gConsoleShow then
1432 if not gChatShow then
1433 begin
1434 if g_ActiveWindow = nil then
1435 begin
1436 if e_KeyPressed(gGameControls.GameControls.Chat) then
1437 g_Console_Chat_Switch(False)
1438 else if (e_KeyPressed(gGameControls.GameControls.TeamChat)) and
1439 (gGameSettings.GameMode in [GM_TDM, GM_CTF]) then
1440 g_Console_Chat_Switch(True);
1441 end;
1442 end else
1443 if not gChatEnter then
1444 if (not e_KeyPressed(gGameControls.GameControls.Chat))
1445 and (not e_KeyPressed(gGameControls.GameControls.TeamChat)) then
1446 gChatEnter := True;
1448 // Ñòàòèñòèêà ïî Tab:
1449 if gGameOn then
1450 IsDrawStat := (not gConsoleShow) and (not gChatShow) and
1451 (gGameSettings.GameType <> GT_SINGLE) and
1452 e_KeyPressed(gGameControls.GameControls.Stat);
1454 // Èãðà èäåò:
1455 if gGameOn and not gPause and (gState <> STATE_FOLD) then
1456 begin
1457 // Âðåìÿ += 28 ìèëëèñåêóíä:
1458 gTime := gTime + GAME_TICK;
1460 // Ñîîáùåíèå ïîñåðåäèíå ýêðàíà:
1461 if MessageTime = 0 then
1462 MessageText := '';
1463 if MessageTime > 0 then
1464 MessageTime := MessageTime - 1;
1466 if (g_Game_IsServer) then
1467 begin
1468 // Áûë çàäàí ëèìèò âðåìåíè:
1469 if (gGameSettings.TimeLimit > 0) then
1470 if (gTime - gGameStartTime) div 1000 >= gGameSettings.TimeLimit then
1471 begin // Îí ïðîøåë => êîíåö óðîâíÿ
1472 g_Game_NextLevel();
1473 Exit;
1474 end;
1476 // Íàäî ðåñïàâíèòü èãðîêîâ â LMS:
1477 if (gLMSRespawn > LMS_RESPAWN_NONE) and (gLMSRespawnTime < gTime) then
1478 g_Game_RestartRound(gLMSSoftSpawn);
1480 // Ïðîâåðèì ðåçóëüòàò ãîëîñîâàíèÿ, åñëè âðåìÿ ïðîøëî
1481 if gVoteInProgress and (gVoteTimer < gTime) then
1482 g_Game_CheckVote
1483 else if gVotePassed and (gVoteCmdTimer < gTime) then
1484 begin
1485 g_Console_Process(gVoteCommand);
1486 gVoteCommand := '';
1487 gVotePassed := False;
1488 end;
1490 // Çàìåðÿåì âðåìÿ çàõâàòà ôëàãîâ
1491 if gFlags[FLAG_RED].State = FLAG_STATE_CAPTURED then
1492 gFlags[FLAG_RED].CaptureTime := gFlags[FLAG_RED].CaptureTime + GAME_TICK;
1493 if gFlags[FLAG_BLUE].State = FLAG_STATE_CAPTURED then
1494 gFlags[FLAG_BLUE].CaptureTime := gFlags[FLAG_BLUE].CaptureTime + GAME_TICK;
1496 // Áûë çàäàí ëèìèò ïîáåä:
1497 if (gGameSettings.GoalLimit > 0) then
1498 begin
1499 b := 0;
1501 if gGameSettings.GameMode = GM_DM then
1502 begin // Â DM èùåì èãðîêà ñ max ôðàãàìè
1503 for i := 0 to High(gPlayers) do
1504 if gPlayers[i] <> nil then
1505 if gPlayers[i].Frags > b then
1506 b := gPlayers[i].Frags;
1507 end
1508 else
1509 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
1510 begin //  CTF/TDM âûáèðàåì êîìàíäó ñ íàèáîëüøèì ñ÷åòîì
1511 b := Max(gTeamStat[TEAM_RED].Goals, gTeamStat[TEAM_BLUE].Goals);
1512 end;
1514 // Ëèìèò ïîáåä íàáðàí => êîíåö óðîâíÿ:
1515 if b >= gGameSettings.GoalLimit then
1516 begin
1517 g_Game_NextLevel();
1518 Exit;
1519 end;
1520 end;
1522 // Îáðàáàòûâàåì êëàâèøè èãðîêîâ:
1523 if gPlayer1 <> nil then gPlayer1.ReleaseKeys();
1524 if gPlayer2 <> nil then gPlayer2.ReleaseKeys();
1525 if (not gConsoleShow) and (not gChatShow) and (g_ActiveWindow = nil) then
1526 begin
1527 processPlayerControls(gPlayer1, gGameControls.P1Control, P1MoveButton);
1528 processPlayerControls(gPlayer2, gGameControls.P2Control, P2MoveButton, true);
1529 end // if not console
1530 else
1531 begin
1532 if g_Game_IsNet and (gPlayer1 <> nil) then gPlayer1.PressKey(KEY_CHAT, 10000);
1533 end;
1534 end; // if server
1536 // Íàáëþäàòåëü
1537 if (gPlayer1 = nil) and (gPlayer2 = nil) and
1538 (not gConsoleShow) and (not gChatShow) and (g_ActiveWindow = nil) then
1539 begin
1540 if not gSpectKeyPress then
1541 begin
1542 if isKeyPressed(gGameControls.P1Control.KeyJump, gGameControls.P1Control.KeyJump2) then
1543 begin
1544 // switch spect mode
1545 case gSpectMode of
1546 SPECT_NONE: ; // not spectator
1547 SPECT_STATS,
1548 SPECT_MAPVIEW: Inc(gSpectMode);
1549 SPECT_PLAYERS: gSpectMode := SPECT_STATS; // reset to 1
1550 end;
1551 gSpectKeyPress := True;
1552 end;
1553 if gSpectMode = SPECT_MAPVIEW then
1554 begin
1555 if isKeyPressed(gGameControls.P1Control.KeyLeft, gGameControls.P1Control.KeyLeft2) then
1556 gSpectX := Max(gSpectX - gSpectStep, 0);
1557 if isKeyPressed(gGameControls.P1Control.KeyRight, gGameControls.P1Control.KeyRight2) then
1558 gSpectX := Min(gSpectX + gSpectStep, gMapInfo.Width - gScreenWidth);
1559 if isKeyPressed(gGameControls.P1Control.KeyUp, gGameControls.P1Control.KeyUp2) then
1560 gSpectY := Max(gSpectY - gSpectStep, 0);
1561 if isKeyPressed(gGameControls.P1Control.KeyDown, gGameControls.P1Control.KeyDown2) then
1562 gSpectY := Min(gSpectY + gSpectStep, gMapInfo.Height - gScreenHeight);
1563 if isKeyPressed(gGameControls.P1Control.KeyPrevWeapon, gGameControls.P1Control.KeyPrevWeapon2) then
1564 begin
1565 // decrease step
1566 if gSpectStep > 4 then gSpectStep := gSpectStep shr 1;
1567 gSpectKeyPress := True;
1568 end;
1569 if isKeyPressed(gGameControls.P1Control.KeyNextWeapon, gGameControls.P1Control.KeyNextWeapon2) then
1570 begin
1571 // increase step
1572 if gSpectStep < 64 then gSpectStep := gSpectStep shl 1;
1573 gSpectKeyPress := True;
1574 end;
1575 end;
1576 if gSpectMode = SPECT_PLAYERS then
1577 begin
1578 if isKeyPressed(gGameControls.P1Control.KeyUp, gGameControls.P1Control.KeyUp2) then
1579 begin
1580 // add second view
1581 gSpectViewTwo := True;
1582 gSpectKeyPress := True;
1583 end;
1584 if isKeyPressed(gGameControls.P1Control.KeyDown, gGameControls.P1Control.KeyDown2) then
1585 begin
1586 // remove second view
1587 gSpectViewTwo := False;
1588 gSpectKeyPress := True;
1589 end;
1590 if isKeyPressed(gGameControls.P1Control.KeyLeft, gGameControls.P1Control.KeyLeft2) then
1591 begin
1592 // prev player (view 1)
1593 gSpectPID1 := GetActivePlayerID_Prev(gSpectPID1);
1594 gSpectKeyPress := True;
1595 end;
1596 if isKeyPressed(gGameControls.P1Control.KeyRight, gGameControls.P1Control.KeyRight2) then
1597 begin
1598 // next player (view 1)
1599 gSpectPID1 := GetActivePlayerID_Next(gSpectPID1);
1600 gSpectKeyPress := True;
1601 end;
1602 if isKeyPressed(gGameControls.P1Control.KeyPrevWeapon, gGameControls.P1Control.KeyPrevWeapon2) then
1603 begin
1604 // prev player (view 2)
1605 gSpectPID2 := GetActivePlayerID_Prev(gSpectPID2);
1606 gSpectKeyPress := True;
1607 end;
1608 if isKeyPressed(gGameControls.P1Control.KeyNextWeapon, gGameControls.P1Control.KeyNextWeapon2) then
1609 begin
1610 // next player (view 2)
1611 gSpectPID2 := GetActivePlayerID_Next(gSpectPID2);
1612 gSpectKeyPress := True;
1613 end;
1614 end;
1615 end
1616 else
1617 if (not isKeyPressed(gGameControls.P1Control.KeyJump, gGameControls.P1Control.KeyJump2)) and
1618 (not isKeyPressed(gGameControls.P1Control.KeyLeft, gGameControls.P1Control.KeyLeft2)) and
1619 (not isKeyPressed(gGameControls.P1Control.KeyRight, gGameControls.P1Control.KeyRight2)) and
1620 (not isKeyPressed(gGameControls.P1Control.KeyUp, gGameControls.P1Control.KeyUp2)) and
1621 (not isKeyPressed(gGameControls.P1Control.KeyDown, gGameControls.P1Control.KeyDown2)) and
1622 (not isKeyPressed(gGameControls.P1Control.KeyPrevWeapon, gGameControls.P1Control.KeyPrevWeapon2)) and
1623 (not isKeyPressed(gGameControls.P1Control.KeyNextWeapon, gGameControls.P1Control.KeyNextWeapon2)) then
1624 gSpectKeyPress := False;
1625 end;
1627 // Îáíîâëÿåì âñå îñòàëüíîå:
1628 g_Map_Update();
1629 g_Items_Update();
1630 g_Triggers_Update();
1631 g_Weapon_Update();
1632 g_Monsters_Update();
1633 g_GFX_Update();
1634 g_Player_UpdateAll();
1635 g_Player_UpdatePhysicalObjects();
1636 if gGameSettings.GameType = GT_SERVER then
1637 if Length(gMonstersSpawned) > 0 then
1638 begin
1639 for I := 0 to High(gMonstersSpawned) do
1640 MH_SEND_MonsterSpawn(gMonstersSpawned[I]);
1641 SetLength(gMonstersSpawned, 0);
1642 end;
1644 if (gSoundTriggerTime > 8) then
1645 begin
1646 g_Game_UpdateTriggerSounds();
1647 gSoundTriggerTime := 0;
1648 end
1649 else
1650 Inc(gSoundTriggerTime);
1652 if (NetMode = NET_SERVER) then
1653 begin
1654 Inc(NetTimeToUpdate);
1655 Inc(NetTimeToReliable);
1656 if NetTimeToReliable >= NetRelupdRate then
1657 begin
1658 for I := 0 to High(gPlayers) do
1659 if gPlayers[I] <> nil then
1660 MH_SEND_PlayerPos(True, gPlayers[I].UID);
1662 if gMonsters <> nil then
1663 for I := 0 to High(gMonsters) do
1664 if gMonsters[I] <> nil then
1665 begin
1666 if (gMonsters[I].MonsterType = MONSTER_BARREL) then
1667 begin
1668 if (gMonsters[I].GameVelX <> 0) or (gMonsters[I].GameVelY <> 0) then
1669 MH_SEND_MonsterPos(gMonsters[I].UID);
1670 end
1671 else
1672 if (gMonsters[I].MonsterState <> MONSTATE_SLEEP) then
1673 if (gMonsters[I].MonsterState <> MONSTATE_DEAD) or
1674 (gMonsters[I].GameVelX <> 0) or
1675 (gMonsters[I].GameVelY <> 0) then
1676 MH_SEND_MonsterPos(gMonsters[I].UID);
1677 end;
1679 NetTimeToReliable := 0;
1680 NetTimeToUpdate := NetUpdateRate;
1681 end
1682 else if NetTimeToUpdate >= NetUpdateRate then
1683 begin
1684 if gPlayers <> nil then
1685 for I := 0 to High(gPlayers) do
1686 if gPlayers[I] <> nil then
1687 MH_SEND_PlayerPos(False, gPlayers[I].UID);
1689 if gMonsters <> nil then
1690 for I := 0 to High(gMonsters) do
1691 if gMonsters[I] <> nil then
1692 begin
1693 if (gMonsters[I].MonsterType = MONSTER_BARREL) then
1694 begin
1695 if (gMonsters[I].GameVelX <> 0) or (gMonsters[I].GameVelY <> 0) then
1696 MH_SEND_MonsterPos(gMonsters[I].UID);
1697 end
1698 else
1699 if (gMonsters[I].MonsterState <> MONSTATE_SLEEP) then
1700 if (gMonsters[I].MonsterState <> MONSTATE_DEAD) or
1701 (gMonsters[I].GameVelX <> 0) or
1702 (gMonsters[I].GameVelY <> 0) then
1703 MH_SEND_MonsterPos(gMonsters[I].UID);
1704 end;
1706 NetTimeToUpdate := 0;
1707 end;
1709 if NetUseMaster then
1710 if gTime >= NetTimeToMaster then
1711 begin
1712 if (NetMHost = nil) or (NetMPeer = nil) then
1713 if not g_Net_Slist_Connect then
1714 g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_SLIST_ERROR]);
1716 g_Net_Slist_Update;
1717 NetTimeToMaster := gTime + NetMasterRate;
1718 end;
1719 end
1720 else
1721 if NetMode = NET_CLIENT then
1722 MC_SEND_PlayerPos();
1723 end; // if gameOn ...
1725 // Àêòèâíî îêíî èíòåðôåéñà - ïåðåäàåì êëàâèøè åìó:
1726 if g_ActiveWindow <> nil then
1727 begin
1728 w := e_GetFirstKeyPressed();
1730 if (w <> IK_INVALID) then
1731 begin
1732 Msg.Msg := MESSAGE_DIKEY;
1733 Msg.wParam := w;
1734 g_ActiveWindow.OnMessage(Msg);
1735 end;
1737 // Åñëè îíî îò ýòîãî íå çàêðûëîñü, òî îáíîâëÿåì:
1738 if g_ActiveWindow <> nil then
1739 g_ActiveWindow.Update();
1741 // Íóæíî ñìåíèòü ðàçðåøåíèå:
1742 if gResolutionChange then
1743 begin
1744 e_WriteLog('Changing resolution', MSG_NOTIFY);
1745 g_Game_ChangeResolution(gRC_Width, gRC_Height, gRC_FullScreen, gRC_Maximized);
1746 gResolutionChange := False;
1747 end;
1749 // Íóæíî ñìåíèòü ÿçûê:
1750 if gLanguageChange then
1751 begin
1752 //e_WriteLog('Read language file', MSG_NOTIFY);
1753 //g_Language_Load(DataDir + gLanguage + '.txt');
1754 g_Language_Set(gLanguage);
1755 g_Menu_Reset();
1756 gLanguageChange := False;
1757 end;
1758 end;
1760 // Äåëàåì ñêðèíøîò (íå ÷àùå 200 ìèëëèñåêóíä):
1761 if e_KeyPressed(gGameControls.GameControls.TakeScreenshot) then
1762 if (GetTimer()-LastScreenShot) > 200000 div 1000 then
1763 begin
1764 g_TakeScreenShot();
1765 LastScreenShot := GetTimer();
1766 end;
1768 // Ãîðÿ÷àÿ êëàâèøà äëÿ âûçîâà ìåíþ âûõîäà èç èãðû (F10):
1769 if e_KeyPressed(IK_F10) and
1770 gGameOn and
1771 (not gConsoleShow) and
1772 (g_ActiveWindow = nil) then
1773 begin
1774 KeyPress(IK_F10);
1775 end;
1777 Time := GetTimer() {div 1000};
1779 // Îáðàáîòêà îòëîæåííûõ ñîáûòèé:
1780 if gDelayedEvents <> nil then
1781 for a := 0 to High(gDelayedEvents) do
1782 if gDelayedEvents[a].Pending and
1784 ((gDelayedEvents[a].DEType = DE_GLOBEVENT) and (gDelayedEvents[a].Time <= Time)) or
1785 ((gDelayedEvents[a].DEType > DE_GLOBEVENT) and (gDelayedEvents[a].Time <= gTime))
1786 ) then
1787 begin
1788 case gDelayedEvents[a].DEType of
1789 DE_GLOBEVENT:
1790 g_Game_ExecuteEvent(gDelayedEvents[a].DEStr);
1791 DE_BFGHIT:
1792 if gGameOn then
1793 g_Game_Announce_GoodShot(gDelayedEvents[a].DENum);
1794 DE_KILLCOMBO:
1795 if gGameOn then
1796 begin
1797 g_Game_Announce_KillCombo(gDelayedEvents[a].DENum);
1798 if g_Game_IsNet and g_Game_IsServer then
1799 MH_SEND_GameEvent(NET_EV_KILLCOMBO, gDelayedEvents[a].DENum);
1800 end;
1801 end;
1802 gDelayedEvents[a].Pending := False;
1803 end;
1805 // Êàæäóþ ñåêóíäó îáíîâëÿåì ñ÷åò÷èê îáíîâëåíèé:
1806 UPSCounter := UPSCounter + 1;
1807 if Time - UPSTime >= 1000 then
1808 begin
1809 UPS := UPSCounter;
1810 UPSCounter := 0;
1811 UPSTime := Time;
1812 end;
1813 end;
1815 procedure g_Game_LoadData();
1816 begin
1817 if DataLoaded then Exit;
1819 e_WriteLog('Loading game data...', MSG_NOTIFY);
1821 g_Texture_CreateWADEx('NOTEXTURE', GameWAD+':TEXTURES\NOTEXTURE');
1822 g_Texture_CreateWADEx('TEXTURE_PLAYER_HUD', GameWAD+':TEXTURES\HUD');
1823 g_Texture_CreateWADEx('TEXTURE_PLAYER_HUDAIR', GameWAD+':TEXTURES\AIRBAR');
1824 g_Texture_CreateWADEx('TEXTURE_PLAYER_HUDJET', GameWAD+':TEXTURES\JETBAR');
1825 g_Texture_CreateWADEx('TEXTURE_PLAYER_HUDBG', GameWAD+':TEXTURES\HUDBG');
1826 g_Texture_CreateWADEx('TEXTURE_PLAYER_ARMORHUD', GameWAD+':TEXTURES\ARMORHUD');
1827 g_Texture_CreateWADEx('TEXTURE_PLAYER_REDFLAG', GameWAD+':TEXTURES\FLAGHUD_RB');
1828 g_Texture_CreateWADEx('TEXTURE_PLAYER_REDFLAG_S', GameWAD+':TEXTURES\FLAGHUD_RS');
1829 g_Texture_CreateWADEx('TEXTURE_PLAYER_REDFLAG_D', GameWAD+':TEXTURES\FLAGHUD_RD');
1830 g_Texture_CreateWADEx('TEXTURE_PLAYER_BLUEFLAG', GameWAD+':TEXTURES\FLAGHUD_BB');
1831 g_Texture_CreateWADEx('TEXTURE_PLAYER_BLUEFLAG_S', GameWAD+':TEXTURES\FLAGHUD_BS');
1832 g_Texture_CreateWADEx('TEXTURE_PLAYER_BLUEFLAG_D', GameWAD+':TEXTURES\FLAGHUD_BD');
1833 g_Texture_CreateWADEx('TEXTURE_PLAYER_TALKBUBBLE', GameWAD+':TEXTURES\TALKBUBBLE');
1834 g_Texture_CreateWADEx('TEXTURE_PLAYER_INVULPENTA', GameWAD+':TEXTURES\PENTA');
1835 g_Frames_CreateWAD(nil, 'FRAMES_TELEPORT', GameWAD+':TEXTURES\TELEPORT', 64, 64, 10, False);
1836 g_Sound_CreateWADEx('SOUND_GAME_TELEPORT', GameWAD+':SOUNDS\TELEPORT');
1837 g_Sound_CreateWADEx('SOUND_GAME_NOTELEPORT', GameWAD+':SOUNDS\NOTELEPORT');
1838 g_Sound_CreateWADEx('SOUND_GAME_DOOROPEN', GameWAD+':SOUNDS\DOOROPEN');
1839 g_Sound_CreateWADEx('SOUND_GAME_DOORCLOSE', GameWAD+':SOUNDS\DOORCLOSE');
1840 g_Sound_CreateWADEx('SOUND_GAME_BULK1', GameWAD+':SOUNDS\BULK1');
1841 g_Sound_CreateWADEx('SOUND_GAME_BULK2', GameWAD+':SOUNDS\BULK2');
1842 g_Sound_CreateWADEx('SOUND_GAME_BUBBLE1', GameWAD+':SOUNDS\BUBBLE1');
1843 g_Sound_CreateWADEx('SOUND_GAME_BUBBLE2', GameWAD+':SOUNDS\BUBBLE2');
1844 g_Sound_CreateWADEx('SOUND_GAME_SWITCH1', GameWAD+':SOUNDS\SWITCH1');
1845 g_Sound_CreateWADEx('SOUND_GAME_SWITCH0', GameWAD+':SOUNDS\SWITCH0');
1846 g_Sound_CreateWADEx('SOUND_GAME_RADIO', GameWAD+':SOUNDS\RADIO');
1847 g_Sound_CreateWADEx('SOUND_ANNOUNCER_GOOD1', GameWAD+':SOUNDS\GOOD1');
1848 g_Sound_CreateWADEx('SOUND_ANNOUNCER_GOOD2', GameWAD+':SOUNDS\GOOD2');
1849 g_Sound_CreateWADEx('SOUND_ANNOUNCER_GOOD3', GameWAD+':SOUNDS\GOOD3');
1850 g_Sound_CreateWADEx('SOUND_ANNOUNCER_GOOD4', GameWAD+':SOUNDS\GOOD4');
1851 g_Sound_CreateWADEx('SOUND_ANNOUNCER_KILL2X', GameWAD+':SOUNDS\KILL2X');
1852 g_Sound_CreateWADEx('SOUND_ANNOUNCER_KILL3X', GameWAD+':SOUNDS\KILL3X');
1853 g_Sound_CreateWADEx('SOUND_ANNOUNCER_KILL4X', GameWAD+':SOUNDS\KILL4X');
1854 g_Sound_CreateWADEx('SOUND_ANNOUNCER_KILLMX', GameWAD+':SOUNDS\KILLMX');
1856 goodsnd[0] := TPlayableSound.Create();
1857 goodsnd[1] := TPlayableSound.Create();
1858 goodsnd[2] := TPlayableSound.Create();
1859 goodsnd[3] := TPlayableSound.Create();
1861 goodsnd[0].SetByName('SOUND_ANNOUNCER_GOOD1');
1862 goodsnd[1].SetByName('SOUND_ANNOUNCER_GOOD2');
1863 goodsnd[2].SetByName('SOUND_ANNOUNCER_GOOD3');
1864 goodsnd[3].SetByName('SOUND_ANNOUNCER_GOOD4');
1866 killsnd[0] := TPlayableSound.Create();
1867 killsnd[1] := TPlayableSound.Create();
1868 killsnd[2] := TPlayableSound.Create();
1869 killsnd[3] := TPlayableSound.Create();
1871 killsnd[0].SetByName('SOUND_ANNOUNCER_KILL2X');
1872 killsnd[1].SetByName('SOUND_ANNOUNCER_KILL3X');
1873 killsnd[2].SetByName('SOUND_ANNOUNCER_KILL4X');
1874 killsnd[3].SetByName('SOUND_ANNOUNCER_KILLMX');
1876 g_Game_SetLoadingText(_lc[I_LOAD_ITEMS_DATA], 0, False);
1877 g_Items_LoadData();
1879 g_Game_SetLoadingText(_lc[I_LOAD_WEAPONS_DATA], 0, False);
1880 g_Weapon_LoadData();
1882 g_Monsters_LoadData();
1884 DataLoaded := True;
1885 end;
1887 procedure g_Game_FreeData();
1888 begin
1889 if not DataLoaded then Exit;
1891 g_Items_FreeData();
1892 g_Weapon_FreeData();
1893 g_Monsters_FreeData();
1895 e_WriteLog('Releasing game data...', MSG_NOTIFY);
1897 g_Texture_Delete('NOTEXTURE');
1898 g_Texture_Delete('TEXTURE_PLAYER_HUD');
1899 g_Texture_Delete('TEXTURE_PLAYER_HUDBG');
1900 g_Texture_Delete('TEXTURE_PLAYER_ARMORHUD');
1901 g_Texture_Delete('TEXTURE_PLAYER_REDFLAG');
1902 g_Texture_Delete('TEXTURE_PLAYER_REDFLAG_S');
1903 g_Texture_Delete('TEXTURE_PLAYER_REDFLAG_D');
1904 g_Texture_Delete('TEXTURE_PLAYER_BLUEFLAG');
1905 g_Texture_Delete('TEXTURE_PLAYER_BLUEFLAG_S');
1906 g_Texture_Delete('TEXTURE_PLAYER_BLUEFLAG_D');
1907 g_Texture_Delete('TEXTURE_PLAYER_TALKBUBBLE');
1908 g_Texture_Delete('TEXTURE_PLAYER_INVULPENTA');
1909 g_Frames_DeleteByName('FRAMES_TELEPORT');
1910 g_Sound_Delete('SOUND_GAME_TELEPORT');
1911 g_Sound_Delete('SOUND_GAME_NOTELEPORT');
1912 g_Sound_Delete('SOUND_GAME_DOOROPEN');
1913 g_Sound_Delete('SOUND_GAME_DOORCLOSE');
1914 g_Sound_Delete('SOUND_GAME_BULK1');
1915 g_Sound_Delete('SOUND_GAME_BULK2');
1916 g_Sound_Delete('SOUND_GAME_BUBBLE1');
1917 g_Sound_Delete('SOUND_GAME_BUBBLE2');
1918 g_Sound_Delete('SOUND_GAME_SWITCH1');
1919 g_Sound_Delete('SOUND_GAME_SWITCH0');
1921 goodsnd[0].Free();
1922 goodsnd[1].Free();
1923 goodsnd[2].Free();
1924 goodsnd[3].Free();
1926 g_Sound_Delete('SOUND_ANNOUNCER_GOOD1');
1927 g_Sound_Delete('SOUND_ANNOUNCER_GOOD2');
1928 g_Sound_Delete('SOUND_ANNOUNCER_GOOD3');
1929 g_Sound_Delete('SOUND_ANNOUNCER_GOOD4');
1931 killsnd[0].Free();
1932 killsnd[1].Free();
1933 killsnd[2].Free();
1934 killsnd[3].Free();
1936 g_Sound_Delete('SOUND_ANNOUNCER_KILL2X');
1937 g_Sound_Delete('SOUND_ANNOUNCER_KILL3X');
1938 g_Sound_Delete('SOUND_ANNOUNCER_KILL4X');
1939 g_Sound_Delete('SOUND_ANNOUNCER_KILLMX');
1941 DataLoaded := False;
1942 end;
1944 procedure DrawCustomStat();
1945 var
1946 pc, x, y, w, _y,
1947 w1, w2, w3,
1948 t, p, m: Integer;
1949 ww1, hh1: Word;
1950 ww2, hh2, r, g, b, rr, gg, bb: Byte;
1951 s1, s2, topstr: String;
1952 begin
1953 e_TextureFontGetSize(gStdFont, ww2, hh2);
1955 e_PollInput();
1956 if e_KeyPressed(IK_TAB) then
1957 begin
1958 if not gStatsPressed then
1959 begin
1960 gStatsOff := not gStatsOff;
1961 gStatsPressed := True;
1962 end;
1963 end
1964 else
1965 gStatsPressed := False;
1967 if gStatsOff then
1968 begin
1969 s1 := _lc[I_MENU_INTER_NOTICE_TAB];
1970 w := (Length(s1) * ww2) div 2;
1971 x := gScreenWidth div 2 - w;
1972 y := 8;
1973 e_TextureFontPrint(x, y, s1, gStdFont);
1974 Exit;
1975 end;
1977 if (gGameSettings.GameMode = GM_COOP) then
1978 begin
1979 if gMissionFailed then
1980 topstr := _lc[I_MENU_INTER_MISSION_FAIL]
1981 else
1982 topstr := _lc[I_MENU_INTER_LEVEL_COMPLETE];
1983 end
1984 else
1985 topstr := _lc[I_MENU_INTER_ROUND_OVER];
1987 e_CharFont_GetSize(gMenuFont, topstr, ww1, hh1);
1988 e_CharFont_Print(gMenuFont, (gScreenWidth div 2)-(ww1 div 2), 16, topstr);
1990 if g_Game_IsNet then
1991 begin
1992 topstr := Format(_lc[I_MENU_INTER_NOTICE_TIME], [gServInterTime]);
1993 if not gChatShow then
1994 e_TextureFontPrintEx((gScreenWidth div 2)-(Length(topstr)*ww2 div 2),
1995 gScreenHeight-(hh2+4)*2, topstr, gStdFont, 255, 255, 255, 1);
1996 end;
1998 if g_Game_IsClient then
1999 topstr := _lc[I_MENU_INTER_NOTICE_MAP]
2000 else
2001 topstr := _lc[I_MENU_INTER_NOTICE_SPACE];
2002 if not gChatShow then
2003 e_TextureFontPrintEx((gScreenWidth div 2)-(Length(topstr)*ww2 div 2),
2004 gScreenHeight-(hh2+4), topstr, gStdFont, 255, 255, 255, 1);
2006 x := 32;
2007 y := 16+hh1+16;
2009 w := gScreenWidth-x*2;
2011 w2 := (w-16) div 6;
2012 w3 := w2;
2013 w1 := w-16-w2-w3;
2015 e_DrawFillQuad(x, y, gScreenWidth-x-1, gScreenHeight-y-1, 64, 64, 64, 32);
2016 e_DrawQuad(x, y, gScreenWidth-x-1, gScreenHeight-y-1, 255, 127, 0);
2018 m := Max(Length(_lc[I_MENU_MAP])+1, Length(_lc[I_GAME_GAME_TIME])+1)*ww2;
2020 case CustomStat.GameMode of
2021 GM_DM:
2022 begin
2023 if gGameSettings.MaxLives = 0 then
2024 s1 := _lc[I_GAME_DM]
2025 else
2026 s1 := _lc[I_GAME_LMS];
2027 end;
2028 GM_TDM:
2029 begin
2030 if gGameSettings.MaxLives = 0 then
2031 s1 := _lc[I_GAME_TDM]
2032 else
2033 s1 := _lc[I_GAME_TLMS];
2034 end;
2035 GM_CTF: s1 := _lc[I_GAME_CTF];
2036 GM_COOP:
2037 begin
2038 if gGameSettings.MaxLives = 0 then
2039 s1 := _lc[I_GAME_COOP]
2040 else
2041 s1 := _lc[I_GAME_SURV];
2042 end;
2043 else s1 := '';
2044 end;
2046 _y := y+16;
2047 e_TextureFontPrintEx(x+(w div 2)-(Length(s1)*ww2 div 2), _y, s1, gStdFont, 255, 255, 255, 1);
2048 _y := _y+8;
2050 _y := _y+16;
2051 e_TextureFontPrintEx(x+8, _y, _lc[I_MENU_MAP], gStdFont, 255, 127, 0, 1);
2052 e_TextureFontPrint(x+8+m, _y, Format('%s - %s', [CustomStat.Map, CustomStat.MapName]), gStdFont);
2054 _y := _y+16;
2055 e_TextureFontPrintEx(x+8, _y, _lc[I_GAME_GAME_TIME], gStdFont, 255, 127, 0, 1);
2056 e_TextureFontPrint(x+8+m, _y, Format('%d:%.2d:%.2d', [CustomStat.GameTime div 1000 div 3600,
2057 (CustomStat.GameTime div 1000 div 60) mod 60,
2058 CustomStat.GameTime div 1000 mod 60]), gStdFont);
2060 pc := Length(CustomStat.PlayerStat);
2061 if pc = 0 then Exit;
2063 if CustomStat.GameMode = GM_COOP then
2064 begin
2065 m := Max(Length(_lc[I_GAME_MONSTERS])+1, Length(_lc[I_GAME_SECRETS])+1)*ww2;
2066 _y := _y+32;
2067 s2 := _lc[I_GAME_MONSTERS];
2068 e_TextureFontPrintEx(x+8, _y, s2, gStdFont, 255, 127, 0, 1);
2069 e_TextureFontPrintEx(x+8+m, _y, IntToStr(gCoopMonstersKilled) + '/' + IntToStr(gTotalMonsters), gStdFont, 255, 255, 255, 1);
2070 _y := _y+16;
2071 s2 := _lc[I_GAME_SECRETS];
2072 e_TextureFontPrintEx(x+8, _y, s2, gStdFont, 255, 127, 0, 1);
2073 e_TextureFontPrintEx(x+8+m, _y, IntToStr(gCoopSecretsFound) + '/' + IntToStr(gSecretsCount), gStdFont, 255, 255, 255, 1);
2074 if gLastMap then
2075 begin
2076 m := Max(Length(_lc[I_GAME_MONSTERS_TOTAL])+1, Length(_lc[I_GAME_SECRETS_TOTAL])+1)*ww2;
2077 _y := _y-16;
2078 s2 := _lc[I_GAME_MONSTERS_TOTAL];
2079 e_TextureFontPrintEx(x+250, _y, s2, gStdFont, 255, 127, 0, 1);
2080 e_TextureFontPrintEx(x+250+m, _y, IntToStr(gCoopTotalMonstersKilled) + '/' + IntToStr(gCoopTotalMonsters), gStdFont, 255, 255, 255, 1);
2081 _y := _y+16;
2082 s2 := _lc[I_GAME_SECRETS_TOTAL];
2083 e_TextureFontPrintEx(x+250, _y, s2, gStdFont, 255, 127, 0, 1);
2084 e_TextureFontPrintEx(x+250+m, _y, IntToStr(gCoopTotalSecretsFound) + '/' + IntToStr(gCoopTotalSecrets), gStdFont, 255, 255, 255, 1);
2085 end;
2086 end;
2088 if CustomStat.GameMode in [GM_TDM, GM_CTF] then
2089 begin
2090 _y := _y+16+16;
2092 with CustomStat do
2093 if TeamStat[TEAM_RED].Goals > TeamStat[TEAM_BLUE].Goals then s1 := _lc[I_GAME_WIN_RED]
2094 else if TeamStat[TEAM_BLUE].Goals > TeamStat[TEAM_RED].Goals then s1 := _lc[I_GAME_WIN_BLUE]
2095 else s1 := _lc[I_GAME_WIN_DRAW];
2097 e_TextureFontPrintEx(x+8+(w div 2)-(Length(s1)*ww2 div 2), _y, s1, gStdFont, 255, 255, 255, 1);
2098 _y := _y+40;
2100 for t := TEAM_RED to TEAM_BLUE do
2101 begin
2102 if t = TEAM_RED then
2103 begin
2104 e_TextureFontPrintEx(x+8, _y, _lc[I_GAME_TEAM_RED],
2105 gStdFont, 255, 0, 0, 1);
2106 e_TextureFontPrintEx(x+w1+8, _y, IntToStr(CustomStat.TeamStat[TEAM_RED].Goals),
2107 gStdFont, 255, 0, 0, 1);
2108 r := 255;
2109 g := 0;
2110 b := 0;
2111 end
2112 else
2113 begin
2114 e_TextureFontPrintEx(x+8, _y, _lc[I_GAME_TEAM_BLUE],
2115 gStdFont, 0, 0, 255, 1);
2116 e_TextureFontPrintEx(x+w1+8, _y, IntToStr(CustomStat.TeamStat[TEAM_BLUE].Goals),
2117 gStdFont, 0, 0, 255, 1);
2118 r := 0;
2119 g := 0;
2120 b := 255;
2121 end;
2123 e_DrawLine(1, x+8, _y+20, x-8+w, _y+20, r, g, b);
2124 _y := _y+24;
2126 for p := 0 to High(CustomStat.PlayerStat) do
2127 if CustomStat.PlayerStat[p].Team = t then
2128 with CustomStat.PlayerStat[p] do
2129 begin
2130 if Spectator then
2131 begin
2132 rr := r div 2;
2133 gg := g div 2;
2134 bb := b div 2;
2135 end
2136 else
2137 begin
2138 rr := r;
2139 gg := g;
2140 bb := b;
2141 end;
2142 e_TextureFontPrintEx(x+8, _y, Name, gStdFont, rr, gg, bb, 1);
2143 e_TextureFontPrintEx(x+w1+8, _y, IntToStr(Frags), gStdFont, rr, gg, bb, 1);
2144 e_TextureFontPrintEx(x+w1+w2+8, _y, IntToStr(Deaths), gStdFont, rr, gg, bb, 1);
2145 _y := _y+24;
2146 end;
2148 _y := _y+16+16;
2149 end;
2150 end
2151 else if CustomStat.GameMode in [GM_DM, GM_COOP] then
2152 begin
2153 _y := _y+40;
2154 e_TextureFontPrintEx(x+8, _y, _lc[I_GAME_PLAYER_NAME], gStdFont, 255, 127, 0, 1);
2155 e_TextureFontPrintEx(x+8+w1, _y, _lc[I_GAME_FRAGS], gStdFont, 255, 127, 0, 1);
2156 e_TextureFontPrintEx(x+8+w1+w2, _y, _lc[I_GAME_DEATHS], gStdFont, 255, 127, 0, 1);
2158 _y := _y+24;
2159 for p := 0 to High(CustomStat.PlayerStat) do
2160 with CustomStat.PlayerStat[p] do
2161 begin
2162 e_DrawFillQuad(x+8, _y+4, x+24-1, _y+16+4-1, Color.R, Color.G, Color.B, 0);
2164 if Spectator then
2165 r := 127
2166 else
2167 r := 255;
2169 e_TextureFontPrintEx(x+8+16+8, _y+4, Name, gStdFont, r, r, r, 1, True);
2170 e_TextureFontPrintEx(x+w1+8+16+8, _y+4, IntToStr(Frags), gStdFont, r, r, r, 1, True);
2171 e_TextureFontPrintEx(x+w1+w2+8+16+8, _y+4, IntToStr(Deaths), gStdFont, r, r, r, 1, True);
2172 _y := _y+24;
2173 end;
2174 end;
2175 end;
2177 procedure DrawSingleStat();
2178 var
2179 tm, key_x, val_x, y: Integer;
2180 w1, w2, h: Word;
2181 s1, s2: String;
2183 procedure player_stat(n: Integer);
2184 var
2185 kpm: Real;
2187 begin
2188 // "Kills: # / #":
2189 s1 := Format(' %d ', [SingleStat.PlayerStat[n].Kills]);
2190 s2 := Format(' %d', [gTotalMonsters]);
2192 e_CharFont_Print(gMenuFont, key_x, y, _lc[I_MENU_INTER_KILLS]);
2193 e_CharFont_PrintEx(gMenuFont, val_x, y, s1, _RGB(255, 0, 0));
2194 e_CharFont_GetSize(gMenuFont, s1, w1, h);
2195 e_CharFont_Print(gMenuFont, val_x+w1, y, '/');
2196 s1 := s1 + '/';
2197 e_CharFont_GetSize(gMenuFont, s1, w1, h);
2198 e_CharFont_PrintEx(gMenuFont, val_x+w1, y, s2, _RGB(255, 0, 0));
2200 // "Kills-per-minute: ##.#":
2201 s1 := _lc[I_MENU_INTER_KPM];
2202 if tm > 0 then
2203 kpm := (SingleStat.PlayerStat[n].Kills / tm) * 60
2204 else
2205 kpm := SingleStat.PlayerStat[n].Kills;
2206 s2 := Format(' %.1f', [kpm]);
2208 e_CharFont_Print(gMenuFont, key_x, y+32, s1);
2209 e_CharFont_PrintEx(gMenuFont, val_x, y+32, s2, _RGB(255, 0, 0));
2211 // "Secrets found: # / #":
2212 s1 := Format(' %d ', [SingleStat.PlayerStat[n].Secrets]);
2213 s2 := Format(' %d', [SingleStat.TotalSecrets]);
2215 e_CharFont_Print(gMenuFont, key_x, y+64, _lc[I_MENU_INTER_SECRETS]);
2216 e_CharFont_PrintEx(gMenuFont, val_x, y+64, s1, _RGB(255, 0, 0));
2217 e_CharFont_GetSize(gMenuFont, s1, w1, h);
2218 e_CharFont_Print(gMenuFont, val_x+w1, y+64, '/');
2219 s1 := s1 + '/';
2220 e_CharFont_GetSize(gMenuFont, s1, w1, h);
2221 e_CharFont_PrintEx(gMenuFont, val_x+w1, y+64, s2, _RGB(255, 0, 0));
2222 end;
2224 begin
2225 // "Level Complete":
2226 e_CharFont_GetSize(gMenuFont, _lc[I_MENU_INTER_LEVEL_COMPLETE], w1, h);
2227 e_CharFont_Print(gMenuFont, (gScreenWidth-w1) div 2, 32, _lc[I_MENU_INTER_LEVEL_COMPLETE]);
2229 // Îïðåäåëÿåì êîîðäèíàòû âûðàâíèâàíèÿ ïî ñàìîé äëèííîé ñòðîêå:
2230 s1 := _lc[I_MENU_INTER_KPM];
2231 e_CharFont_GetSize(gMenuFont, s1, w1, h);
2232 Inc(w1, 16);
2233 s1 := ' 9999.9';
2234 e_CharFont_GetSize(gMenuFont, s1, w2, h);
2236 key_x := (gScreenWidth-w1-w2) div 2;
2237 val_x := key_x + w1;
2239 // "Time: #:##:##":
2240 tm := SingleStat.GameTime div 1000;
2241 s1 := _lc[I_MENU_INTER_TIME];
2242 s2 := Format(' %d:%.2d:%.2d', [tm div (60*60), (tm mod (60*60)) div 60, tm mod 60]);
2244 e_CharFont_Print(gMenuFont, key_x, 80, s1);
2245 e_CharFont_PrintEx(gMenuFont, val_x, 80, s2, _RGB(255, 0, 0));
2247 if SingleStat.TwoPlayers then
2248 begin
2249 // "Player 1":
2250 s1 := _lc[I_MENU_PLAYER_1];
2251 e_CharFont_GetSize(gMenuFont, s1, w1, h);
2252 e_CharFont_Print(gMenuFont, (gScreenWidth-w1) div 2, 128, s1);
2254 // Ñòàòèñòèêà ïåðâîãî èãðîêà:
2255 y := 176;
2256 player_stat(0);
2258 // "Player 2":
2259 s1 := _lc[I_MENU_PLAYER_2];
2260 e_CharFont_GetSize(gMenuFont, s1, w1, h);
2261 e_CharFont_Print(gMenuFont, (gScreenWidth-w1) div 2, 288, s1);
2263 // Ñòàòèñòèêà âòîðîãî èãðîêà:
2264 y := 336;
2265 player_stat(1);
2266 end
2267 else
2268 begin
2269 // Ñòàòèñòèêà ïåðâîãî èãðîêà:
2270 y := 128;
2271 player_stat(0);
2272 end;
2273 end;
2275 procedure DrawLoadingStat();
2276 var
2277 ww, hh: Word;
2278 xx, yy, i: Integer;
2279 s: String;
2280 begin
2281 if Length(LoadingStat.Msgs) = 0 then
2282 Exit;
2284 e_CharFont_GetSize(gMenuFont, _lc[I_MENU_LOADING], ww, hh);
2285 yy := (gScreenHeight div 3);
2286 e_CharFont_Print(gMenuFont, (gScreenWidth div 2)-(ww div 2), yy-2*hh, _lc[I_MENU_LOADING]);
2287 xx := (gScreenWidth div 3);
2289 with LoadingStat do
2290 for i := 0 to NextMsg-1 do
2291 begin
2292 if (i = (NextMsg-1)) and (MaxValue > 0) then
2293 s := Format('%s: %d/%d', [Msgs[i], CurValue, MaxValue])
2294 else
2295 s := Msgs[i];
2297 e_CharFont_PrintEx(gMenuSmallFont, xx, yy, s, _RGB(255, 0, 0));
2298 yy := yy + LOADING_INTERLINE;
2299 end;
2300 end;
2302 procedure DrawMinimap(p: TPlayer; RenderRect: e_graphics.TRect);
2303 var
2304 a, aX, aY, aX2, aY2, Scale, ScaleSz: Integer;
2305 begin
2306 if (gMapInfo.Width > RenderRect.Right - RenderRect.Left) or
2307 (gMapInfo.Height > RenderRect.Bottom - RenderRect.Top) then
2308 begin
2309 Scale := 1;
2310 // Ñêîëüêî ïèêñåëîâ êàðòû â 1 ïèêñåëå ìèíè-êàðòû:
2311 ScaleSz := 16 div Scale;
2312 // Ðàçìåðû ìèíè-êàðòû:
2313 aX := max(gMapInfo.Width div ScaleSz, 1);
2314 aY := max(gMapInfo.Height div ScaleSz, 1);
2315 // Ðàìêà êàðòû:
2316 e_DrawFillQuad(0, 0, aX-1, aY-1, 0, 0, 0, 0);
2318 if gWalls <> nil then
2319 begin
2320 // Ðèñóåì ñòåíû:
2321 for a := 0 to High(gWalls) do
2322 with gWalls[a] do
2323 if PanelType <> 0 then
2324 begin
2325 // Ëåâûé âåðõíèé óãîë:
2326 aX := X div ScaleSz;
2327 aY := Y div ScaleSz;
2328 // Ðàçìåðû:
2329 aX2 := max(Width div ScaleSz, 1);
2330 aY2 := max(Height div ScaleSz, 1);
2331 // Ïðàâûé íèæíèé óãîë:
2332 aX2 := aX + aX2 - 1;
2333 aY2 := aY + aY2 - 1;
2335 case PanelType of
2336 PANEL_WALL: e_DrawFillQuad(aX, aY, aX2, aY2, 208, 208, 208, 0);
2337 PANEL_OPENDOOR, PANEL_CLOSEDOOR:
2338 if Enabled then e_DrawFillQuad(aX, aY, aX2, aY2, 160, 160, 160, 0);
2339 end;
2340 end;
2341 end;
2342 if gSteps <> nil then
2343 begin
2344 // Ðèñóåì ñòóïåíè:
2345 for a := 0 to High(gSteps) do
2346 with gSteps[a] do
2347 if PanelType <> 0 then
2348 begin
2349 // Ëåâûé âåðõíèé óãîë:
2350 aX := X div ScaleSz;
2351 aY := Y div ScaleSz;
2352 // Ðàçìåðû:
2353 aX2 := max(Width div ScaleSz, 1);
2354 aY2 := max(Height div ScaleSz, 1);
2355 // Ïðàâûé íèæíèé óãîë:
2356 aX2 := aX + aX2 - 1;
2357 aY2 := aY + aY2 - 1;
2359 e_DrawFillQuad(aX, aY, aX2, aY2, 128, 128, 128, 0);
2360 end;
2361 end;
2362 if gLifts <> nil then
2363 begin
2364 // Ðèñóåì ëèôòû:
2365 for a := 0 to High(gLifts) do
2366 with gLifts[a] do
2367 if PanelType <> 0 then
2368 begin
2369 // Ëåâûé âåðõíèé óãîë:
2370 aX := X div ScaleSz;
2371 aY := Y div ScaleSz;
2372 // Ðàçìåðû:
2373 aX2 := max(Width div ScaleSz, 1);
2374 aY2 := max(Height div ScaleSz, 1);
2375 // Ïðàâûé íèæíèé óãîë:
2376 aX2 := aX + aX2 - 1;
2377 aY2 := aY + aY2 - 1;
2379 case LiftType of
2380 0: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 72, 36, 0);
2381 1: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 124, 96, 0);
2382 2: e_DrawFillQuad(aX, aY, aX2, aY2, 200, 80, 4, 0);
2383 3: e_DrawFillQuad(aX, aY, aX2, aY2, 252, 140, 56, 0);
2384 end;
2385 end;
2386 end;
2387 if gWater <> nil then
2388 begin
2389 // Ðèñóåì âîäó:
2390 for a := 0 to High(gWater) do
2391 with gWater[a] do
2392 if PanelType <> 0 then
2393 begin
2394 // Ëåâûé âåðõíèé óãîë:
2395 aX := X div ScaleSz;
2396 aY := Y div ScaleSz;
2397 // Ðàçìåðû:
2398 aX2 := max(Width div ScaleSz, 1);
2399 aY2 := max(Height div ScaleSz, 1);
2400 // Ïðàâûé íèæíèé óãîë:
2401 aX2 := aX + aX2 - 1;
2402 aY2 := aY + aY2 - 1;
2404 e_DrawFillQuad(aX, aY, aX2, aY2, 0, 0, 192, 0);
2405 end;
2406 end;
2407 if gAcid1 <> nil then
2408 begin
2409 // Ðèñóåì êèñëîòó 1:
2410 for a := 0 to High(gAcid1) do
2411 with gAcid1[a] do
2412 if PanelType <> 0 then
2413 begin
2414 // Ëåâûé âåðõíèé óãîë:
2415 aX := X div ScaleSz;
2416 aY := Y div ScaleSz;
2417 // Ðàçìåðû:
2418 aX2 := max(Width div ScaleSz, 1);
2419 aY2 := max(Height div ScaleSz, 1);
2420 // Ïðàâûé íèæíèé óãîë:
2421 aX2 := aX + aX2 - 1;
2422 aY2 := aY + aY2 - 1;
2424 e_DrawFillQuad(aX, aY, aX2, aY2, 0, 176, 0, 0);
2425 end;
2426 end;
2427 if gAcid2 <> nil then
2428 begin
2429 // Ðèñóåì êèñëîòó 2:
2430 for a := 0 to High(gAcid2) do
2431 with gAcid2[a] do
2432 if PanelType <> 0 then
2433 begin
2434 // Ëåâûé âåðõíèé óãîë:
2435 aX := X div ScaleSz;
2436 aY := Y div ScaleSz;
2437 // Ðàçìåðû:
2438 aX2 := max(Width div ScaleSz, 1);
2439 aY2 := max(Height div ScaleSz, 1);
2440 // Ïðàâûé íèæíèé óãîë:
2441 aX2 := aX + aX2 - 1;
2442 aY2 := aY + aY2 - 1;
2444 e_DrawFillQuad(aX, aY, aX2, aY2, 176, 0, 0, 0);
2445 end;
2446 end;
2447 if gPlayers <> nil then
2448 begin
2449 // Ðèñóåì èãðîêîâ:
2450 for a := 0 to High(gPlayers) do
2451 if gPlayers[a] <> nil then with gPlayers[a] do
2452 if Live then begin
2453 // Ëåâûé âåðõíèé óãîë:
2454 aX := Obj.X div ScaleSz + 1;
2455 aY := Obj.Y div ScaleSz + 1;
2456 // Ðàçìåðû:
2457 aX2 := max(Obj.Rect.Width div ScaleSz, 1);
2458 aY2 := max(Obj.Rect.Height div ScaleSz, 1);
2459 // Ïðàâûé íèæíèé óãîë:
2460 aX2 := aX + aX2 - 1;
2461 aY2 := aY + aY2 - 1;
2463 if gPlayers[a] = p then
2464 e_DrawFillQuad(aX, aY, aX2, aY2, 0, 255, 0, 0)
2465 else
2466 case Team of
2467 TEAM_RED: e_DrawFillQuad(aX, aY, aX2, aY2, 255, 0, 0, 0);
2468 TEAM_BLUE: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 0, 255, 0);
2469 else e_DrawFillQuad(aX, aY, aX2, aY2, 255, 128, 0, 0);
2470 end;
2471 end;
2472 end;
2473 if gMonsters <> nil then
2474 begin
2475 // Ðèñóåì ìîíñòðîâ:
2476 for a := 0 to High(gMonsters) do
2477 if gMonsters[a] <> nil then with gMonsters[a] do
2478 if Live then begin
2479 // Ëåâûé âåðõíèé óãîë:
2480 aX := Obj.X div ScaleSz + 1;
2481 aY := Obj.Y div ScaleSz + 1;
2482 // Ðàçìåðû:
2483 aX2 := max(Obj.Rect.Width div ScaleSz, 1);
2484 aY2 := max(Obj.Rect.Height div ScaleSz, 1);
2485 // Ïðàâûé íèæíèé óãîë:
2486 aX2 := aX + aX2 - 1;
2487 aY2 := aY + aY2 - 1;
2489 e_DrawFillQuad(aX, aY, aX2, aY2, 255, 255, 0, 0);
2490 end;
2491 end;
2492 end;
2493 end;
2495 procedure DrawMapView(x, y, w, h: Integer);
2496 var
2497 bx, by: Integer;
2498 begin
2499 glPushMatrix();
2501 bx := Round(x/(gMapInfo.Width - w)*(gBackSize.X - w));
2502 by := Round(y/(gMapInfo.Height - h)*(gBackSize.Y - h));
2503 g_Map_DrawBack(-bx, -by);
2505 sX := x;
2506 sY := y;
2507 sWidth := w;
2508 sHeight := h;
2510 glTranslatef(-x, -y, 0);
2512 g_Map_DrawPanels(PANEL_BACK);
2513 g_Map_DrawPanels(PANEL_STEP);
2514 g_Items_Draw();
2515 g_Weapon_Draw();
2516 g_Player_DrawShells();
2517 g_Player_DrawAll();
2518 g_Player_DrawCorpses();
2519 g_Map_DrawPanels(PANEL_WALL);
2520 g_Monsters_Draw();
2521 g_Map_DrawPanels(PANEL_CLOSEDOOR);
2522 g_GFX_Draw();
2523 g_Map_DrawFlags();
2524 g_Map_DrawPanels(PANEL_ACID1);
2525 g_Map_DrawPanels(PANEL_ACID2);
2526 g_Map_DrawPanels(PANEL_WATER);
2527 g_Map_DrawPanels(PANEL_FORE);
2528 if g_debug_HealthBar then
2529 begin
2530 g_Monsters_DrawHealth();
2531 g_Player_DrawHealth();
2532 end;
2534 glPopMatrix();
2535 end;
2537 procedure DrawPlayer(p: TPlayer);
2538 var
2539 px, py, a, b, c, d: Integer;
2540 //R: TRect;
2541 begin
2542 if (p = nil) or (p.FDummy) then
2543 begin
2544 glPushMatrix();
2545 g_Map_DrawBack(0, 0);
2546 glPopMatrix();
2547 Exit;
2548 end;
2550 gPlayerDrawn := p;
2552 glPushMatrix();
2554 px := p.GameX + PLAYER_RECT_CX;
2555 py := p.GameY + PLAYER_RECT_CY;
2557 if px > (gPlayerScreenSize.X div 2) then
2558 a := -px + (gPlayerScreenSize.X div 2)
2559 else
2560 a := 0;
2561 if py > (gPlayerScreenSize.Y div 2) then
2562 b := -py + (gPlayerScreenSize.Y div 2)
2563 else
2564 b := 0;
2565 if px > (gMapInfo.Width - (gPlayerScreenSize.X div 2)) then
2566 a := -gMapInfo.Width + gPlayerScreenSize.X;
2567 if py > (gMapInfo.Height - (gPlayerScreenSize.Y div 2)) then
2568 b := -gMapInfo.Height + gPlayerScreenSize.Y;
2569 if gMapInfo.Width <= gPlayerScreenSize.X then
2570 a := 0;
2571 if gMapInfo.Height <= gPlayerScreenSize.Y then
2572 b := 0;
2574 if p.IncCam <> 0 then
2575 begin
2576 if py > (gMapInfo.Height - (gPlayerScreenSize.Y div 2)) then
2577 begin
2578 if p.IncCam > 120-(py-(gMapInfo.Height-(gPlayerScreenSize.Y div 2))) then
2579 p.IncCam := 120-(py-(gMapInfo.Height-(gPlayerScreenSize.Y div 2)));
2580 end;
2582 if py < (gPlayerScreenSize.Y div 2) then
2583 begin
2584 if p.IncCam < -120+((gPlayerScreenSize.Y div 2)-py) then
2585 p.IncCam := -120+((gPlayerScreenSize.Y div 2)-py);
2586 end;
2588 if p.IncCam < 0 then
2589 while (py+(gPlayerScreenSize.Y div 2)-p.IncCam > gMapInfo.Height) and
2590 (p.IncCam < 0) do
2591 p.IncCam := p.IncCam + 1;
2593 if p.IncCam > 0 then
2594 while (py-(gPlayerScreenSize.Y div 2)-p.IncCam < 0) and
2595 (p.IncCam > 0) do
2596 p.IncCam := p.IncCam - 1;
2597 end;
2599 if (px< gPlayerScreenSize.X div 2) or
2600 (gMapInfo.Width-gPlayerScreenSize.X <= 256) then
2601 c := 0
2602 else
2603 if (px > gMapInfo.Width-(gPlayerScreenSize.X div 2)) then
2604 c := gBackSize.X - gPlayerScreenSize.X
2605 else
2606 c := Round((px-(gPlayerScreenSize.X div 2))/(gMapInfo.Width-gPlayerScreenSize.X)*(gBackSize.X-gPlayerScreenSize.X));
2608 if (py-p.IncCam <= gPlayerScreenSize.Y div 2) or
2609 (gMapInfo.Height-gPlayerScreenSize.Y <= 256) then
2610 d := 0
2611 else
2612 if (py-p.IncCam >= gMapInfo.Height-(gPlayerScreenSize.Y div 2)) then
2613 d := gBackSize.Y - gPlayerScreenSize.Y
2614 else
2615 d := Round((py-p.IncCam-(gPlayerScreenSize.Y div 2))/(gMapInfo.Height-gPlayerScreenSize.Y)*(gBackSize.Y-gPlayerScreenSize.Y));
2617 g_Map_DrawBack(-c, -d);
2619 sX := -a;
2620 sY := -(b+p.IncCam);
2621 sWidth := gPlayerScreenSize.X;
2622 sHeight := gPlayerScreenSize.Y;
2624 glTranslatef(a, b+p.IncCam, 0);
2626 g_Map_DrawPanels(PANEL_BACK);
2627 g_Map_DrawPanels(PANEL_STEP);
2628 g_Items_Draw();
2629 g_Weapon_Draw();
2630 g_Player_DrawShells();
2631 g_Player_DrawAll();
2632 g_Player_DrawCorpses();
2633 g_Map_DrawPanels(PANEL_WALL);
2634 g_Monsters_Draw();
2635 g_Map_DrawPanels(PANEL_CLOSEDOOR);
2636 g_GFX_Draw();
2637 g_Map_DrawFlags();
2638 g_Map_DrawPanels(PANEL_ACID1);
2639 g_Map_DrawPanels(PANEL_ACID2);
2640 g_Map_DrawPanels(PANEL_WATER);
2641 g_Map_DrawPanels(PANEL_FORE);
2642 if g_debug_HealthBar then
2643 begin
2644 g_Monsters_DrawHealth();
2645 g_Player_DrawHealth();
2646 end;
2648 if p.FSpectator then
2649 e_TextureFontPrintEx(p.GameX + PLAYER_RECT_CX - 4,
2650 p.GameY + PLAYER_RECT_CY - 4,
2651 'X', gStdFont, 255, 255, 255, 1, True);
2653 for a := 0 to High(gCollideMap) do
2654 for b := 0 to High(gCollideMap[a]) do
2655 begin
2656 d := 0;
2657 if ByteBool(gCollideMap[a, b] and MARK_WALL) then
2658 d := d + 1;
2659 if ByteBool(gCollideMap[a, b] and MARK_DOOR) then
2660 d := d + 2;
2662 case d of
2663 1: e_DrawPoint(1, b, a, 200, 200, 200);
2664 2: e_DrawPoint(1, b, a, 64, 64, 255);
2665 3: e_DrawPoint(1, b, a, 255, 0, 255);
2666 end;
2667 end;
2670 glPopMatrix();
2672 p.DrawPain();
2673 p.DrawPickup();
2674 p.DrawRulez();
2675 if gShowMap then DrawMinimap(p, _TRect(0, 0, 128, 128));
2676 if g_Debug_Player then
2677 g_Player_DrawDebug(p);
2678 p.DrawGUI();
2679 end;
2681 procedure g_Game_Draw();
2682 var
2683 ID: DWORD;
2684 w, h: Word;
2685 ww, hh: Byte;
2686 Time: Int64;
2687 back: string;
2688 plView1, plView2: TPlayer;
2689 Split: Boolean;
2690 begin
2691 if gExit = EXIT_QUIT then Exit;
2693 Time := GetTimer() {div 1000};
2694 FPSCounter := FPSCounter+1;
2695 if Time - FPSTime >= 1000 then
2696 begin
2697 FPS := FPSCounter;
2698 FPSCounter := 0;
2699 FPSTime := Time;
2700 end;
2702 if gGameOn or (gState = STATE_FOLD) then
2703 begin
2704 if (gPlayer1 <> nil) and (gPlayer2 <> nil) then
2705 begin
2706 gSpectMode := SPECT_NONE;
2707 if not gRevertPlayers then
2708 begin
2709 plView1 := gPlayer1;
2710 plView2 := gPlayer2;
2711 end
2712 else
2713 begin
2714 plView1 := gPlayer2;
2715 plView2 := gPlayer1;
2716 end;
2717 end
2718 else
2719 if (gPlayer1 <> nil) or (gPlayer2 <> nil) then
2720 begin
2721 gSpectMode := SPECT_NONE;
2722 if gPlayer2 = nil then
2723 plView1 := gPlayer1
2724 else
2725 plView1 := gPlayer2;
2726 plView2 := nil;
2727 end
2728 else
2729 begin
2730 plView1 := nil;
2731 plView2 := nil;
2732 end;
2734 if (plView1 = nil) and (plView2 = nil) and (gSpectMode = SPECT_NONE) then
2735 gSpectMode := SPECT_STATS;
2737 if gSpectMode = SPECT_PLAYERS then
2738 if gPlayers <> nil then
2739 begin
2740 plView1 := GetActivePlayer_ByID(gSpectPID1);
2741 if plView1 = nil then
2742 begin
2743 gSpectPID1 := GetActivePlayerID_Next();
2744 plView1 := GetActivePlayer_ByID(gSpectPID1);
2745 end;
2746 if gSpectViewTwo then
2747 begin
2748 plView2 := GetActivePlayer_ByID(gSpectPID2);
2749 if plView2 = nil then
2750 begin
2751 gSpectPID2 := GetActivePlayerID_Next();
2752 plView2 := GetActivePlayer_ByID(gSpectPID2);
2753 end;
2754 end;
2755 end;
2757 if gSpectMode = SPECT_MAPVIEW then
2758 begin
2759 // Ðåæèì ïðîñìîòðà êàðòû
2760 Split := False;
2761 e_SetViewPort(0, 0, gScreenWidth, gScreenHeight);
2762 DrawMapView(gSpectX, gSpectY, gScreenWidth, gScreenHeight);
2763 gHearPoint1.Active := True;
2764 gHearPoint1.Coords.X := gScreenWidth div 2 + gSpectX;
2765 gHearPoint1.Coords.Y := gScreenHeight div 2 + gSpectY;
2766 gHearPoint2.Active := False;
2767 end
2768 else
2769 begin
2770 Split := (plView1 <> nil) and (plView2 <> nil);
2772 // Òî÷êè ñëóõà èãðîêîâ
2773 if plView1 <> nil then
2774 begin
2775 gHearPoint1.Active := True;
2776 gHearPoint1.Coords.X := plView1.GameX;
2777 gHearPoint1.Coords.Y := plView1.GameY;
2778 end else
2779 gHearPoint1.Active := False;
2780 if plView2 <> nil then
2781 begin
2782 gHearPoint2.Active := True;
2783 gHearPoint2.Coords.X := plView2.GameX;
2784 gHearPoint2.Coords.Y := plView2.GameY;
2785 end else
2786 gHearPoint2.Active := False;
2788 // Ðàçìåð ýêðàíîâ èãðîêîâ:
2789 gPlayerScreenSize.X := gScreenWidth-196;
2790 if Split then
2791 begin
2792 gPlayerScreenSize.Y := gScreenHeight div 2;
2793 if gScreenHeight mod 2 = 0 then
2794 Dec(gPlayerScreenSize.Y);
2795 end
2796 else
2797 gPlayerScreenSize.Y := gScreenHeight;
2799 if Split then
2800 if gScreenHeight mod 2 = 0 then
2801 e_SetViewPort(0, gPlayerScreenSize.Y+2, gPlayerScreenSize.X+196, gPlayerScreenSize.Y)
2802 else
2803 e_SetViewPort(0, gPlayerScreenSize.Y+1, gPlayerScreenSize.X+196, gPlayerScreenSize.Y);
2805 DrawPlayer(plView1);
2806 gPlayer1ScreenCoord.X := sX;
2807 gPlayer1ScreenCoord.Y := sY;
2809 if Split then
2810 begin
2811 e_SetViewPort(0, 0, gPlayerScreenSize.X+196, gPlayerScreenSize.Y);
2813 DrawPlayer(plView2);
2814 gPlayer2ScreenCoord.X := sX;
2815 gPlayer2ScreenCoord.Y := sY;
2816 end;
2818 e_SetViewPort(0, 0, gScreenWidth, gScreenHeight);
2820 if Split then
2821 e_DrawLine(2, 0, gScreenHeight div 2, gScreenWidth, gScreenHeight div 2, 0, 0, 0);
2822 end;
2824 if MessageText <> '' then
2825 begin
2826 w := 0;
2827 h := 0;
2828 e_CharFont_GetSizeFmt(gMenuFont, MessageText, w, h);
2829 if Split then
2830 e_CharFont_PrintFmt(gMenuFont, (gScreenWidth div 2)-(w div 2),
2831 (gScreenHeight div 2)-(h div 2), MessageText)
2832 else
2833 e_CharFont_PrintFmt(gMenuFont, (gScreenWidth div 2)-(w div 2),
2834 Round(gScreenHeight / 2.75)-(h div 2), MessageText);
2835 end;
2837 if IsDrawStat or (gSpectMode = 1) then DrawStat();
2839 if gSpectHUD and (not gChatShow) and (gSpectMode <> SPECT_NONE) then
2840 begin
2841 // Draw spectator GUI
2842 ww := 0;
2843 hh := 0;
2844 e_TextureFontGetSize(gStdFont, ww, hh);
2845 case gSpectMode of
2846 SPECT_STATS:
2847 e_TextureFontPrintEx(0, gScreenHeight - (hh+2)*2, 'MODE: Stats', gStdFont, 255, 255, 255, 1);
2848 SPECT_MAPVIEW:
2849 e_TextureFontPrintEx(0, gScreenHeight - (hh+2)*2, 'MODE: Observe Map', gStdFont, 255, 255, 255, 1);
2850 SPECT_PLAYERS:
2851 e_TextureFontPrintEx(0, gScreenHeight - (hh+2)*2, 'MODE: Watch Players', gStdFont, 255, 255, 255, 1);
2852 end;
2853 e_TextureFontPrintEx(2*ww, gScreenHeight - (hh+2), '< jump >', gStdFont, 255, 255, 255, 1);
2854 if gSpectMode = SPECT_MAPVIEW then
2855 begin
2856 e_TextureFontPrintEx(22*ww, gScreenHeight - (hh+2)*2, '[-]', gStdFont, 255, 255, 255, 1);
2857 e_TextureFontPrintEx(26*ww, gScreenHeight - (hh+2)*2, 'Step ' + IntToStr(gSpectStep), gStdFont, 255, 255, 255, 1);
2858 e_TextureFontPrintEx(34*ww, gScreenHeight - (hh+2)*2, '[+]', gStdFont, 255, 255, 255, 1);
2859 e_TextureFontPrintEx(18*ww, gScreenHeight - (hh+2), '<prev weap>', gStdFont, 255, 255, 255, 1);
2860 e_TextureFontPrintEx(30*ww, gScreenHeight - (hh+2), '<next weap>', gStdFont, 255, 255, 255, 1);
2861 end;
2862 if gSpectMode = SPECT_PLAYERS then
2863 begin
2864 e_TextureFontPrintEx(22*ww, gScreenHeight - (hh+2)*2, 'Player 1', gStdFont, 255, 255, 255, 1);
2865 e_TextureFontPrintEx(20*ww, gScreenHeight - (hh+2), '<left/right>', gStdFont, 255, 255, 255, 1);
2866 if gSpectViewTwo then
2867 begin
2868 e_TextureFontPrintEx(37*ww, gScreenHeight - (hh+2)*2, 'Player 2', gStdFont, 255, 255, 255, 1);
2869 e_TextureFontPrintEx(34*ww, gScreenHeight - (hh+2), '<prev w/next w>', gStdFont, 255, 255, 255, 1);
2870 e_TextureFontPrintEx(52*ww, gScreenHeight - (hh+2)*2, '2x View', gStdFont, 255, 255, 255, 1);
2871 e_TextureFontPrintEx(51*ww, gScreenHeight - (hh+2), '<up/down>', gStdFont, 255, 255, 255, 1);
2872 end
2873 else
2874 begin
2875 e_TextureFontPrintEx(35*ww, gScreenHeight - (hh+2)*2, '2x View', gStdFont, 255, 255, 255, 1);
2876 e_TextureFontPrintEx(34*ww, gScreenHeight - (hh+2), '<up/down>', gStdFont, 255, 255, 255, 1);
2877 end;
2878 end;
2879 end;
2880 end;
2882 if gPause and gGameOn and (g_ActiveWindow = nil) then
2883 begin
2884 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2886 e_CharFont_GetSize(gMenuFont, _lc[I_MENU_PAUSE], w, h);
2887 e_CharFont_Print(gMenuFont, (gScreenWidth div 2)-(w div 2),
2888 (gScreenHeight div 2)-(h div 2), _lc[I_MENU_PAUSE]);
2889 end;
2891 if not gGameOn then
2892 begin
2893 if (gState = STATE_MENU) then
2894 begin
2895 if ((g_ActiveWindow = nil) or (g_ActiveWindow.BackTexture = '')) then
2896 begin
2897 if g_Texture_Get('MENU_BACKGROUND', ID) then
2898 e_DrawSize(ID, 0, 0, 0, False, False, gScreenWidth, gScreenHeight)
2899 else e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
2900 end;
2901 if g_ActiveWindow <> nil then
2902 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2903 end;
2905 if gState = STATE_FOLD then
2906 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 0, 0, 0, EndingGameCounter);
2908 if gState = STATE_INTERCUSTOM then
2909 begin
2910 if gLastMap and (gGameSettings.GameMode = GM_COOP) then
2911 begin
2912 back := 'TEXTURE_endpic';
2913 if not g_Texture_Get(back, ID) then
2914 back := _lc[I_TEXTURE_ENDPIC];
2915 end
2916 else
2917 back := 'INTER';
2919 if g_Texture_Get(back, ID) then
2920 e_DrawSize(ID, 0, 0, 0, False, False, gScreenWidth, gScreenHeight)
2921 else
2922 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
2924 DrawCustomStat();
2926 if g_ActiveWindow <> nil then
2927 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2928 end;
2930 if gState = STATE_INTERSINGLE then
2931 begin
2932 if EndingGameCounter > 0 then
2933 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 0, 0, 0, EndingGameCounter)
2934 else
2935 begin
2936 back := 'INTER';
2938 if g_Texture_Get(back, ID) then
2939 e_DrawSize(ID, 0, 0, 0, False, False, gScreenWidth, gScreenHeight)
2940 else
2941 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
2943 DrawSingleStat();
2945 if g_ActiveWindow <> nil then
2946 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2947 end;
2948 end;
2950 if gState = STATE_ENDPIC then
2951 begin
2952 ID := DWORD(-1);
2953 if not g_Texture_Get('TEXTURE_endpic', ID) then
2954 g_Texture_Get(_lc[I_TEXTURE_ENDPIC], ID);
2956 if ID <> DWORD(-1) then
2957 e_DrawSize(ID, 0, 0, 0, False, False, gScreenWidth, gScreenHeight)
2958 else
2959 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
2961 if g_ActiveWindow <> nil then
2962 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2963 end;
2965 if gState = STATE_SLIST then
2966 begin
2967 if g_Texture_Get('MENU_BACKGROUND', ID) then
2968 begin
2969 e_DrawSize(ID, 0, 0, 0, False, False, gScreenWidth, gScreenHeight);
2970 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2971 end;
2972 g_Serverlist_Draw(slCurrent);
2973 end;
2974 end;
2976 if g_ActiveWindow <> nil then
2977 begin
2978 if gGameOn then
2979 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2980 g_ActiveWindow.Draw();
2981 end;
2983 g_Console_Draw();
2985 if g_debug_Sounds and gGameOn then
2986 begin
2987 for w := 0 to High(e_SoundsArray) do
2988 for h := 0 to e_SoundsArray[w].nRefs do
2989 e_DrawPoint(1, w+100, h+100, 255, 0, 0);
2990 end;
2992 if gShowFPS then
2993 begin
2994 e_TextureFontPrint(0, 0, Format('FPS: %d', [FPS]), gStdFont);
2995 e_TextureFontPrint(0, 16, Format('UPS: %d', [UPS]), gStdFont);
2996 end;
2998 if gGameOn and gShowTime and (gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT]) then
2999 e_TextureFontPrint(gScreenWidth-72, 0,
3000 Format('%d:%.2d:%.2d', [gTime div 1000 div 3600, (gTime div 1000 div 60) mod 60, gTime div 1000 mod 60]),
3001 gStdFont);
3002 end;
3004 procedure g_Game_Quit();
3005 begin
3006 g_Game_StopAllSounds(True);
3007 gMusic.Free();
3008 g_Game_SaveOptions();
3009 g_Game_FreeData();
3010 g_PlayerModel_FreeData();
3011 g_Texture_DeleteAll();
3012 g_Frames_DeleteAll();
3013 g_Menu_Free();
3015 if NetInitDone then g_Net_Free;
3017 // Íàäî óäàëèòü êàðòó ïîñëå òåñòà:
3018 if gMapToDelete <> '' then
3019 g_Game_DeleteTestMap();
3021 gExit := EXIT_QUIT;
3022 PushExitEvent();
3023 end;
3025 procedure g_FatalError(Text: String);
3026 begin
3027 g_Console_Add(Format(_lc[I_FATAL_ERROR], [Text]), True);
3028 e_WriteLog(Format(_lc[I_FATAL_ERROR], [Text]), MSG_WARNING);
3030 gExit := EXIT_SIMPLE;
3031 end;
3033 procedure g_SimpleError(Text: String);
3034 begin
3035 g_Console_Add(Format(_lc[I_SIMPLE_ERROR], [Text]), True);
3036 e_WriteLog(Format(_lc[I_SIMPLE_ERROR], [Text]), MSG_WARNING);
3037 end;
3039 procedure g_Game_SetupScreenSize();
3040 var
3041 d: Single;
3042 begin
3043 // Ðàçìåð ýêðàíîâ èãðîêîâ:
3044 gPlayerScreenSize.X := gScreenWidth-196;
3045 if (gPlayer1 <> nil) and (gPlayer2 <> nil) then
3046 gPlayerScreenSize.Y := gScreenHeight div 2
3047 else
3048 gPlayerScreenSize.Y := gScreenHeight;
3050 // Ðàçìåð çàäíåãî ïëàíà:
3051 if BackID <> DWORD(-1) then
3052 begin
3053 d := SKY_STRETCH;
3055 if (gScreenWidth*d > gMapInfo.Width) or
3056 (gScreenHeight*d > gMapInfo.Height) then
3057 d := 1.0;
3059 gBackSize.X := Round(gScreenWidth*d);
3060 gBackSize.Y := Round(gScreenHeight*d);
3061 end;
3062 end;
3064 procedure g_Game_ChangeResolution(newWidth, newHeight: Word; nowFull, nowMax: Boolean);
3065 begin
3066 g_Window_SetSize(newWidth, newHeight, nowFull);
3067 end;
3069 procedure g_Game_AddPlayer(Team: Byte = TEAM_NONE);
3070 begin
3071 if ((not gGameOn) and (gState <> STATE_INTERCUSTOM))
3072 or (not (gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT])) then
3073 Exit;
3074 if gPlayer1 = nil then
3075 begin
3076 if g_Game_IsClient then
3077 begin
3078 if NetPlrUID1 > -1 then
3079 begin
3080 MC_SEND_CheatRequest(NET_CHEAT_SPECTATE);
3081 gPlayer1 := g_Player_Get(NetPlrUID1);
3082 end;
3083 Exit;
3084 end;
3086 if not (Team in [TEAM_RED, TEAM_BLUE]) then
3087 Team := gPlayer1Settings.Team;
3089 // Ñîçäàíèå ïåðâîãî èãðîêà:
3090 gPlayer1 := g_Player_Get(g_Player_Create(gPlayer1Settings.Model,
3091 gPlayer1Settings.Color,
3092 Team, False));
3093 if gPlayer1 = nil then
3094 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [1]))
3095 else
3096 begin
3097 gPlayer1.Name := gPlayer1Settings.Name;
3098 g_Console_Add(Format(_lc[I_PLAYER_JOIN], [gPlayer1.Name]), True);
3099 if g_Game_IsServer and g_Game_IsNet then
3100 MH_SEND_PlayerCreate(gPlayer1.UID);
3101 gPlayer1.Respawn(False, True);
3103 if g_Game_IsNet and NetUseMaster then
3104 g_Net_Slist_Update;
3105 end;
3107 Exit;
3108 end;
3109 if gPlayer2 = nil then
3110 begin
3111 if g_Game_IsClient then
3112 begin
3113 if NetPlrUID2 > -1 then
3114 gPlayer2 := g_Player_Get(NetPlrUID2);
3115 Exit;
3116 end;
3118 if not (Team in [TEAM_RED, TEAM_BLUE]) then
3119 Team := gPlayer2Settings.Team;
3121 // Ñîçäàíèå âòîðîãî èãðîêà:
3122 gPlayer2 := g_Player_Get(g_Player_Create(gPlayer2Settings.Model,
3123 gPlayer2Settings.Color,
3124 Team, False));
3125 if gPlayer2 = nil then
3126 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [2]))
3127 else
3128 begin
3129 gPlayer2.Name := gPlayer2Settings.Name;
3130 g_Console_Add(Format(_lc[I_PLAYER_JOIN], [gPlayer2.Name]), True);
3131 if g_Game_IsServer and g_Game_IsNet then
3132 MH_SEND_PlayerCreate(gPlayer2.UID);
3133 gPlayer2.Respawn(False, True);
3135 if g_Game_IsNet and NetUseMaster then
3136 g_Net_Slist_Update;
3137 end;
3139 Exit;
3140 end;
3141 end;
3143 procedure g_Game_RemovePlayer();
3144 var
3145 Pl: TPlayer;
3146 begin
3147 if ((not gGameOn) and (gState <> STATE_INTERCUSTOM))
3148 or (not (gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT])) then
3149 Exit;
3150 Pl := gPlayer2;
3151 if Pl <> nil then
3152 begin
3153 if g_Game_IsServer then
3154 begin
3155 Pl.Lives := 0;
3156 Pl.Kill(K_SIMPLEKILL, 0, HIT_DISCON);
3157 g_Console_Add(Format(_lc[I_PLAYER_LEAVE], [Pl.Name]), True);
3158 g_Player_Remove(Pl.UID);
3160 if g_Game_IsNet and NetUseMaster then
3161 g_Net_Slist_Update;
3162 end else
3163 gPlayer2 := nil;
3164 Exit;
3165 end;
3166 Pl := gPlayer1;
3167 if Pl <> nil then
3168 begin
3169 if g_Game_IsServer then
3170 begin
3171 Pl.Lives := 0;
3172 Pl.Kill(K_SIMPLEKILL, 0, HIT_DISCON);
3173 g_Console_Add(Format(_lc[I_PLAYER_LEAVE], [Pl.Name]), True);
3174 g_Player_Remove(Pl.UID);
3176 if g_Game_IsNet and NetUseMaster then
3177 g_Net_Slist_Update;
3178 end else
3179 begin
3180 gPlayer1 := nil;
3181 MC_SEND_CheatRequest(NET_CHEAT_SPECTATE);
3182 end;
3183 Exit;
3184 end;
3185 end;
3187 procedure g_Game_Spectate();
3188 begin
3189 g_Game_RemovePlayer();
3190 if gPlayer1 <> nil then
3191 g_Game_RemovePlayer();
3192 end;
3194 procedure g_Game_SpectateCenterView();
3195 begin
3196 gSpectX := Max(gMapInfo.Width div 2 - gScreenWidth div 2, 0);
3197 gSpectY := Max(gMapInfo.Height div 2 - gScreenHeight div 2, 0);
3198 end;
3200 procedure g_Game_StartSingle(Map: String; TwoPlayers: Boolean; nPlayers: Byte);
3201 var
3202 i, nPl: Integer;
3203 begin
3204 g_Game_Free();
3206 e_WriteLog('Starting singleplayer game...', MSG_NOTIFY);
3208 g_Game_ClearLoading();
3210 // Íàñòðîéêè èãðû:
3211 FillByte(gGameSettings, SizeOf(TGameSettings), 0);
3212 gAimLine := False;
3213 gShowMap := False;
3214 gGameSettings.GameType := GT_SINGLE;
3215 gGameSettings.MaxLives := 0;
3216 gGameSettings.Options := gGameSettings.Options + GAME_OPTION_ALLOWEXIT;
3217 gGameSettings.Options := gGameSettings.Options + GAME_OPTION_MONSTERS;
3218 gGameSettings.Options := gGameSettings.Options + GAME_OPTION_BOTVSMONSTER;
3219 gSwitchGameMode := GM_SINGLE;
3221 g_Game_ExecuteEvent('ongamestart');
3223 // Óñòàíîâêà ðàçìåðîâ îêîí èãðîêîâ:
3224 g_Game_SetupScreenSize();
3226 // Ñîçäàíèå ïåðâîãî èãðîêà:
3227 gPlayer1 := g_Player_Get(g_Player_Create(gPlayer1Settings.Model,
3228 gPlayer1Settings.Color,
3229 gPlayer1Settings.Team, False));
3230 if gPlayer1 = nil then
3231 begin
3232 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [1]));
3233 Exit;
3234 end;
3236 gPlayer1.Name := gPlayer1Settings.Name;
3237 nPl := 1;
3239 // Ñîçäàíèå âòîðîãî èãðîêà, åñëè åñòü:
3240 if TwoPlayers then
3241 begin
3242 gPlayer2 := g_Player_Get(g_Player_Create(gPlayer2Settings.Model,
3243 gPlayer2Settings.Color,
3244 gPlayer2Settings.Team, False));
3245 if gPlayer2 = nil then
3246 begin
3247 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [2]));
3248 Exit;
3249 end;
3251 gPlayer2.Name := gPlayer2Settings.Name;
3252 Inc(nPl);
3253 end;
3255 // Çàãðóçêà è çàïóñê êàðòû:
3256 if not g_Game_StartMap(MAP, True) then
3257 begin
3258 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [gGameSettings.WAD + ':\' + MAP]));
3259 Exit;
3260 end;
3262 // Íàñòðîéêè èãðîêîâ è áîòîâ:
3263 g_Player_Init();
3265 // Ñîçäàåì áîòîâ:
3266 for i := nPl+1 to nPlayers do
3267 g_Player_Create(STD_PLAYER_MODEL, _RGB(0, 0, 0), 0, True);
3268 end;
3270 procedure g_Game_StartCustom(Map: String; GameMode: Byte;
3271 TimeLimit, GoalLimit: Word;
3272 MaxLives: Byte;
3273 Options: LongWord; nPlayers: Byte);
3274 var
3275 i, nPl: Integer;
3276 begin
3277 g_Game_Free();
3279 e_WriteLog('Starting custom game...', MSG_NOTIFY);
3281 g_Game_ClearLoading();
3283 // Íàñòðîéêè èãðû:
3284 gGameSettings.GameType := GT_CUSTOM;
3285 gGameSettings.GameMode := GameMode;
3286 gSwitchGameMode := GameMode;
3287 gGameSettings.TimeLimit := TimeLimit;
3288 gGameSettings.GoalLimit := GoalLimit;
3289 gGameSettings.MaxLives := IfThen(GameMode = GM_CTF, 0, MaxLives);
3290 gGameSettings.Options := Options;
3292 gCoopTotalMonstersKilled := 0;
3293 gCoopTotalSecretsFound := 0;
3294 gCoopTotalMonsters := 0;
3295 gCoopTotalSecrets := 0;
3296 gAimLine := False;
3297 gShowMap := False;
3299 g_Game_ExecuteEvent('ongamestart');
3301 // Óñòàíîâêà ðàçìåðîâ îêîí èãðîêîâ:
3302 g_Game_SetupScreenSize();
3304 // Ðåæèì íàáëþäàòåëÿ:
3305 if nPlayers = 0 then
3306 begin
3307 gPlayer1 := nil;
3308 gPlayer2 := nil;
3309 end;
3311 nPl := 0;
3312 if nPlayers >= 1 then
3313 begin
3314 // Ñîçäàíèå ïåðâîãî èãðîêà:
3315 gPlayer1 := g_Player_Get(g_Player_Create(gPlayer1Settings.Model,
3316 gPlayer1Settings.Color,
3317 gPlayer1Settings.Team, False));
3318 if gPlayer1 = nil then
3319 begin
3320 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [1]));
3321 Exit;
3322 end;
3324 gPlayer1.Name := gPlayer1Settings.Name;
3325 Inc(nPl);
3326 end;
3328 if nPlayers >= 2 then
3329 begin
3330 // Ñîçäàíèå âòîðîãî èãðîêà:
3331 gPlayer2 := g_Player_Get(g_Player_Create(gPlayer2Settings.Model,
3332 gPlayer2Settings.Color,
3333 gPlayer2Settings.Team, False));
3334 if gPlayer2 = nil then
3335 begin
3336 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [2]));
3337 Exit;
3338 end;
3340 gPlayer2.Name := gPlayer2Settings.Name;
3341 Inc(nPl);
3342 end;
3344 // Çàãðóçêà è çàïóñê êàðòû:
3345 if not g_Game_StartMap(Map, True) then
3346 begin
3347 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Map]));
3348 Exit;
3349 end;
3351 // Íåò òî÷åê ïîÿâëåíèÿ:
3352 if (g_Map_GetPointCount(RESPAWNPOINT_PLAYER1) +
3353 g_Map_GetPointCount(RESPAWNPOINT_PLAYER2) +
3354 g_Map_GetPointCount(RESPAWNPOINT_DM) +
3355 g_Map_GetPointCount(RESPAWNPOINT_RED)+
3356 g_Map_GetPointCount(RESPAWNPOINT_BLUE)) < 1 then
3357 begin
3358 g_FatalError(_lc[I_GAME_ERROR_GET_SPAWN]);
3359 Exit;
3360 end;
3362 // Íàñòðîéêè èãðîêîâ è áîòîâ:
3363 g_Player_Init();
3365 // Ñîçäàåì áîòîâ:
3366 for i := nPl+1 to nPlayers do
3367 g_Player_Create(STD_PLAYER_MODEL, _RGB(0, 0, 0), 0, True);
3368 end;
3370 procedure g_Game_StartServer(Map: String; GameMode: Byte;
3371 TimeLimit, GoalLimit: Word; MaxLives: Byte;
3372 Options: LongWord; nPlayers: Byte;
3373 IPAddr: LongWord; Port: Word);
3374 begin
3375 g_Game_Free();
3377 e_WriteLog('Starting net game (server)...', MSG_NOTIFY);
3379 g_Game_ClearLoading();
3381 // Íàñòðîéêè èãðû:
3382 gGameSettings.GameType := GT_SERVER;
3383 gGameSettings.GameMode := GameMode;
3384 gSwitchGameMode := GameMode;
3385 gGameSettings.TimeLimit := TimeLimit;
3386 gGameSettings.GoalLimit := GoalLimit;
3387 gGameSettings.MaxLives := IfThen(GameMode = GM_CTF, 0, MaxLives);
3388 gGameSettings.Options := Options;
3390 gCoopTotalMonstersKilled := 0;
3391 gCoopTotalSecretsFound := 0;
3392 gCoopTotalMonsters := 0;
3393 gCoopTotalSecrets := 0;
3394 gAimLine := False;
3395 gShowMap := False;
3397 g_Game_ExecuteEvent('ongamestart');
3399 // Óñòàíîâêà ðàçìåðîâ îêíà èãðîêà
3400 g_Game_SetupScreenSize();
3402 // Ðåæèì íàáëþäàòåëÿ:
3403 if nPlayers = 0 then
3404 begin
3405 gPlayer1 := nil;
3406 gPlayer2 := nil;
3407 end;
3409 if nPlayers >= 1 then
3410 begin
3411 // Ñîçäàíèå ïåðâîãî èãðîêà:
3412 gPlayer1 := g_Player_Get(g_Player_Create(gPlayer1Settings.Model,
3413 gPlayer1Settings.Color,
3414 gPlayer1Settings.Team, False));
3415 if gPlayer1 = nil then
3416 begin
3417 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [1]));
3418 Exit;
3419 end;
3421 gPlayer1.Name := gPlayer1Settings.Name;
3422 end;
3424 if nPlayers >= 2 then
3425 begin
3426 // Ñîçäàíèå âòîðîãî èãðîêà:
3427 gPlayer2 := g_Player_Get(g_Player_Create(gPlayer2Settings.Model,
3428 gPlayer2Settings.Color,
3429 gPlayer2Settings.Team, False));
3430 if gPlayer2 = nil then
3431 begin
3432 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [2]));
3433 Exit;
3434 end;
3436 gPlayer2.Name := gPlayer2Settings.Name;
3437 end;
3439 // Ñòàðòóåì ñåðâåð
3440 if not g_Net_Host(IPAddr, Port, NetMaxClients) then
3441 begin
3442 g_FatalError(_lc[I_NET_MSG] + _lc[I_NET_ERR_HOST]);
3443 Exit;
3444 end;
3446 g_Net_Slist_Set(NetSlistIP, NetSlistPort);
3448 // Çàãðóçêà è çàïóñê êàðòû:
3449 if not g_Game_StartMap(Map, True) then
3450 begin
3451 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Map]));
3452 Exit;
3453 end;
3455 // Íåò òî÷åê ïîÿâëåíèÿ:
3456 if (g_Map_GetPointCount(RESPAWNPOINT_PLAYER1) +
3457 g_Map_GetPointCount(RESPAWNPOINT_PLAYER2) +
3458 g_Map_GetPointCount(RESPAWNPOINT_DM) +
3459 g_Map_GetPointCount(RESPAWNPOINT_RED)+
3460 g_Map_GetPointCount(RESPAWNPOINT_BLUE)) < 1 then
3461 begin
3462 g_FatalError(_lc[I_GAME_ERROR_GET_SPAWN]);
3463 Exit;
3464 end;
3466 // Íàñòðîéêè èãðîêîâ è áîòîâ:
3467 g_Player_Init();
3469 NetState := NET_STATE_GAME;
3470 end;
3472 procedure g_Game_StartClient(Addr: String; Port: Word; PW: String);
3473 var
3474 Map: String;
3475 WadName: string;
3476 Ptr: Pointer;
3477 T: Cardinal;
3478 MID: Byte;
3479 State: Byte;
3480 OuterLoop: Boolean;
3481 newResPath: string;
3482 begin
3483 g_Game_Free();
3485 State := 0;
3486 e_WriteLog('Starting net game (client)...', MSG_NOTIFY);
3487 e_WriteLog('NET: Trying to connect to ' + Addr + ':' + IntToStr(Port) + '...', MSG_NOTIFY);
3489 g_Game_ClearLoading();
3491 // Íàñòðîéêè èãðû:
3492 gGameSettings.GameType := GT_CLIENT;
3494 gCoopTotalMonstersKilled := 0;
3495 gCoopTotalSecretsFound := 0;
3496 gCoopTotalMonsters := 0;
3497 gCoopTotalSecrets := 0;
3498 gAimLine := False;
3499 gShowMap := False;
3501 g_Game_ExecuteEvent('ongamestart');
3503 // Óñòàíîâêà ðàçìåðîâ îêîí èãðîêîâ:
3504 g_Game_SetupScreenSize();
3506 NetState := NET_STATE_AUTH;
3508 g_Game_SetLoadingText(_lc[I_LOAD_CONNECT], 0, False);
3509 // Ñòàðòóåì êëèåíò
3510 if not g_Net_Connect(Addr, Port) then
3511 begin
3512 g_FatalError(_lc[I_NET_MSG] + _lc[I_NET_ERR_CONN]);
3513 NetState := NET_STATE_NONE;
3514 Exit;
3515 end;
3517 g_Game_SetLoadingText(_lc[I_LOAD_SEND_INFO], 0, False);
3518 MC_SEND_Info(PW);
3519 g_Game_SetLoadingText(_lc[I_LOAD_WAIT_INFO], 0, False);
3521 OuterLoop := True;
3522 while OuterLoop do
3523 begin
3524 while (enet_host_service(NetHost, @NetEvent, 0) > 0) do
3525 begin
3526 if (NetEvent.kind = ENET_EVENT_TYPE_RECEIVE) then
3527 begin
3528 Ptr := NetEvent.packet^.data;
3529 e_Raw_Seek(0);
3531 MID := e_Raw_Read_Byte(Ptr);
3533 if (MID = NET_MSG_INFO) and (State = 0) then
3534 begin
3535 NetMyID := e_Raw_Read_Byte(Ptr);
3536 NetPlrUID1 := e_Raw_Read_Word(Ptr);
3538 WadName := e_Raw_Read_String(Ptr);
3539 Map := e_Raw_Read_String(Ptr);
3541 gWADHash := e_Raw_Read_MD5(Ptr);
3543 gGameSettings.GameMode := e_Raw_Read_Byte(Ptr);
3544 gSwitchGameMode := gGameSettings.GameMode;
3545 gGameSettings.GoalLimit := e_Raw_Read_Word(Ptr);
3546 gGameSettings.TimeLimit := e_Raw_Read_Word(Ptr);
3547 gGameSettings.MaxLives := e_Raw_Read_Byte(Ptr);
3548 gGameSettings.Options := e_Raw_Read_LongWord(Ptr);
3549 T := e_Raw_Read_LongWord(Ptr);
3551 newResPath := g_Res_SearchSameWAD(MapsDir, WadName, gWADHash);
3552 if newResPath = '' then
3553 begin
3554 g_Game_SetLoadingText(_lc[I_LOAD_DL_RES], 0, False);
3555 newResPath := g_Res_DownloadWAD(WadName);
3556 if newResPath = '' then
3557 begin
3558 g_FatalError(_lc[I_NET_ERR_HASH]);
3559 enet_packet_destroy(NetEvent.packet);
3560 NetState := NET_STATE_NONE;
3561 Exit;
3562 end;
3563 end;
3564 newResPath := ExtractRelativePath(MapsDir, newResPath);
3566 gPlayer1 := g_Player_Get(g_Player_Create(gPlayer1Settings.Model,
3567 gPlayer1Settings.Color,
3568 gPlayer1Settings.Team, False));
3570 if gPlayer1 = nil then
3571 begin
3572 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [1]));
3574 enet_packet_destroy(NetEvent.packet);
3575 NetState := NET_STATE_NONE;
3576 Exit;
3577 end;
3579 gPlayer1.Name := gPlayer1Settings.Name;
3580 gPlayer1.UID := NetPlrUID1;
3581 gPlayer1.Reset(True);
3583 if not g_Game_StartMap(newResPath + ':\' + Map, True) then
3584 begin
3585 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [WadName + ':\' + Map]));
3587 enet_packet_destroy(NetEvent.packet);
3588 NetState := NET_STATE_NONE;
3589 Exit;
3590 end;
3592 gTime := T;
3594 State := 1;
3595 OuterLoop := False;
3596 enet_packet_destroy(NetEvent.packet);
3597 break;
3598 end
3599 else
3600 enet_packet_destroy(NetEvent.packet);
3601 end
3602 else
3603 if (NetEvent.kind = ENET_EVENT_TYPE_DISCONNECT) then
3604 begin
3605 State := 0;
3606 if (NetEvent.data <= NET_DISC_MAX) then
3607 g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_ERR_CONN] + ' ' +
3608 _lc[TStrings_Locale(Cardinal(I_NET_DISC_NONE) + NetEvent.data)], True);
3609 OuterLoop := False;
3610 Break;
3611 end;
3612 end;
3614 ProcessLoading();
3616 e_PollInput();
3618 if e_KeyPressed(IK_ESCAPE) or e_KeyPressed(IK_SPACE) then
3619 begin
3620 State := 0;
3621 break;
3622 end;
3623 end;
3625 if State <> 1 then
3626 begin
3627 g_FatalError(_lc[I_NET_MSG] + _lc[I_NET_ERR_CONN]);
3628 NetState := NET_STATE_NONE;
3629 Exit;
3630 end;
3632 gLMSRespawn := LMS_RESPAWN_NONE;
3633 gLMSRespawnTime := 0;
3635 g_Player_Init();
3636 NetState := NET_STATE_GAME;
3637 MC_SEND_FullStateRequest;
3638 e_WriteLog('NET: Connection successful.', MSG_NOTIFY);
3639 end;
3641 procedure g_Game_SaveOptions();
3642 begin
3643 g_Options_Write_Video(GameDir+'/'+CONFIG_FILENAME);
3644 end;
3646 procedure g_Game_ChangeMap(MapPath: String);
3647 var
3648 Force: Boolean;
3649 begin
3650 g_Game_ClearLoading();
3652 Force := gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF];
3653 // Åñëè óðîâåíü çàâåðøèëñÿ ïî òðèããåðó Âûõîä, íå î÷èùàòü èíâåíòàðü
3654 if gExitByTrigger then
3655 begin
3656 Force := False;
3657 gExitByTrigger := False;
3658 end;
3659 if not g_Game_StartMap(MapPath, Force) then
3660 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [MapPath]));
3661 end;
3663 procedure g_Game_Restart();
3664 var
3665 Map: string;
3666 begin
3667 if g_Game_IsClient then
3668 Exit;
3669 map := g_ExtractFileName(gMapInfo.Map);
3671 MessageTime := 0;
3672 gGameOn := False;
3673 g_Game_ClearLoading();
3674 g_Game_StartMap(Map, True);
3675 end;
3677 function g_Game_StartMap(Map: String; Force: Boolean = False): Boolean;
3678 var
3679 NewWAD, ResName: String;
3680 I: Integer;
3681 begin
3682 g_Map_Free();
3683 g_Player_RemoveAllCorpses();
3685 if (not g_Game_IsClient) and
3686 (gSwitchGameMode <> gGameSettings.GameMode) and
3687 (gGameSettings.GameMode <> GM_SINGLE) then
3688 begin
3689 if gSwitchGameMode = GM_CTF then
3690 gGameSettings.MaxLives := 0;
3691 gGameSettings.GameMode := gSwitchGameMode;
3692 Force := True;
3693 end else
3694 gSwitchGameMode := gGameSettings.GameMode;
3696 g_Player_ResetTeams();
3698 if Pos(':\', Map) > 0 then
3699 begin
3700 NewWAD := g_ExtractWadName(Map);
3701 ResName := g_ExtractFileName(Map);
3702 if g_Game_IsServer then
3703 begin
3704 gWADHash := MD5File(MapsDir + NewWAD);
3705 g_Game_LoadWAD(NewWAD);
3706 end else
3707 // hash recieved in MC_RECV_GameEvent -> NET_EV_MAPSTART
3708 g_Game_ClientWAD(NewWAD, gWADHash);
3709 end else
3710 ResName := Map;
3712 Result := g_Map_Load(MapsDir + gGameSettings.WAD + ':\' + ResName);
3713 if Result then
3714 begin
3715 g_Player_ResetAll(Force or gLastMap, gGameSettings.GameType = GT_SINGLE);
3717 gState := STATE_NONE;
3718 g_ActiveWindow := nil;
3719 gGameOn := True;
3721 DisableCheats();
3722 ResetTimer();
3724 if gGameSettings.GameMode = GM_CTF then
3725 begin
3726 g_Map_ResetFlag(FLAG_RED);
3727 g_Map_ResetFlag(FLAG_BLUE);
3728 // CTF, à ôëàãîâ íåò:
3729 if not g_Map_HaveFlagPoints() then
3730 g_SimpleError(_lc[I_GAME_ERROR_CTF]);
3731 end;
3732 end
3733 else
3734 begin
3735 gState := STATE_MENU;
3736 gGameOn := False;
3737 end;
3739 gExit := 0;
3740 gPause := False;
3741 gTime := 0;
3742 NetTimeToUpdate := 1;
3743 NetTimeToReliable := 0;
3744 NetTimeToMaster := NetMasterRate;
3745 gLMSRespawn := LMS_RESPAWN_NONE;
3746 gLMSRespawnTime := 0;
3747 gMissionFailed := False;
3748 gNextMap := '';
3750 gCoopMonstersKilled := 0;
3751 gCoopSecretsFound := 0;
3753 gVoteInProgress := False;
3754 gVotePassed := False;
3755 gVoteCount := 0;
3756 gVoted := False;
3758 gStatsOff := False;
3760 if not gGameOn then Exit;
3762 g_Game_SpectateCenterView();
3764 if (gGameSettings.MaxLives > 0) and (gGameSettings.WarmupTime > 0) then
3765 begin
3766 gLMSRespawn := LMS_RESPAWN_WARMUP;
3767 gLMSRespawnTime := gTime + gGameSettings.WarmupTime*1000;
3768 gLMSSoftSpawn := True;
3769 if NetMode = NET_SERVER then
3770 MH_SEND_GameEvent(NET_EV_LMS_WARMUP, (gLMSRespawnTime - gTime) div 1000)
3771 else
3772 g_Console_Add(Format(_lc[I_MSG_WARMUP_START], [(gLMSRespawnTime - gTime) div 1000]), True);
3773 end;
3775 if NetMode = NET_SERVER then
3776 begin
3777 MH_SEND_GameEvent(NET_EV_MAPSTART, gGameSettings.GameMode, Map);
3779 // Ìàñòåðñåðâåð
3780 if NetUseMaster then
3781 begin
3782 if (NetMHost = nil) or (NetMPeer = nil) then
3783 if not g_Net_Slist_Connect then
3784 g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_SLIST_ERROR]);
3786 g_Net_Slist_Update;
3787 end;
3789 if NetClients <> nil then
3790 for I := 0 to High(NetClients) do
3791 if NetClients[I].Used then
3792 begin
3793 NetClients[I].Voted := False;
3794 if NetClients[I].RequestedFullUpdate then
3795 begin
3796 MH_SEND_Everything((NetClients[I].State = NET_STATE_AUTH), I);
3797 NetClients[I].RequestedFullUpdate := False;
3798 end;
3799 end;
3801 g_Net_UnbanNonPermHosts();
3802 end;
3804 if gLastMap then
3805 begin
3806 gCoopTotalMonstersKilled := 0;
3807 gCoopTotalSecretsFound := 0;
3808 gCoopTotalMonsters := 0;
3809 gCoopTotalSecrets := 0;
3810 gLastMap := False;
3811 end;
3813 g_Game_ExecuteEvent('onmapstart');
3814 end;
3816 procedure SetFirstLevel();
3817 begin
3818 gNextMap := '';
3820 MapList := g_Map_GetMapsList(MapsDir + gGameSettings.WAD);
3821 if MapList = nil then
3822 Exit;
3824 SortSArray(MapList);
3825 gNextMap := MapList[Low(MapList)];
3827 MapList := nil;
3828 end;
3830 procedure g_Game_ExitLevel(Map: Char16);
3831 begin
3832 gNextMap := Map;
3834 gCoopTotalMonstersKilled := gCoopTotalMonstersKilled + gCoopMonstersKilled;
3835 gCoopTotalSecretsFound := gCoopTotalSecretsFound + gCoopSecretsFound;
3836 gCoopTotalMonsters := gCoopTotalMonsters + gTotalMonsters;
3837 gCoopTotalSecrets := gCoopTotalSecrets + gSecretsCount;
3839 // Âûøëè â âûõîä â Îäèíî÷íîé èãðå:
3840 if gGameSettings.GameType = GT_SINGLE then
3841 gExit := EXIT_ENDLEVELSINGLE
3842 else // Âûøëè â âûõîä â Ñâîåé èãðå
3843 begin
3844 gExit := EXIT_ENDLEVELCUSTOM;
3845 if gGameSettings.GameMode = GM_COOP then
3846 g_Player_RememberAll;
3848 if not g_Map_Exist(MapsDir + gGameSettings.WAD + ':\' + gNextMap) then
3849 begin
3850 gLastMap := True;
3851 if gGameSettings.GameMode = GM_COOP then
3852 gStatsOff := True;
3854 gStatsPressed := True;
3855 gNextMap := 'MAP01';
3857 if not g_Map_Exist(MapsDir + gGameSettings.WAD + ':\' + gNextMap) then
3858 g_Game_NextLevel;
3860 if g_Game_IsNet then
3861 begin
3862 MH_SEND_GameStats();
3863 MH_SEND_CoopStats();
3864 end;
3865 end;
3866 end;
3867 end;
3869 procedure g_Game_RestartLevel();
3870 var
3871 Map: string;
3872 begin
3873 if gGameSettings.GameMode = GM_SINGLE then
3874 begin
3875 g_Game_Restart();
3876 Exit;
3877 end;
3878 gExit := EXIT_ENDLEVELCUSTOM;
3879 Map := g_ExtractFileName(gMapInfo.Map);
3880 gNextMap := Map;
3881 end;
3883 procedure g_Game_ClientWAD(NewWAD: String; WHash: TMD5Digest);
3884 var
3885 gWAD: String;
3886 begin
3887 if LowerCase(NewWAD) = LowerCase(gGameSettings.WAD) then
3888 Exit;
3889 if not g_Game_IsClient then
3890 Exit;
3891 gWAD := g_Res_SearchSameWAD(MapsDir, ExtractFileName(NewWAD), WHash);
3892 if gWAD = '' then
3893 begin
3894 g_Game_SetLoadingText(_lc[I_LOAD_DL_RES], 0, False);
3895 gWAD := g_Res_DownloadWAD(ExtractFileName(NewWAD));
3896 if gWAD = '' then
3897 begin
3898 g_Game_Free();
3899 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_WAD], [ExtractFileName(NewWAD)]));
3900 Exit;
3901 end;
3902 end;
3903 NewWAD := ExtractRelativePath(MapsDir, gWAD);
3904 g_Game_LoadWAD(NewWAD);
3905 end;
3907 procedure g_Game_RestartRound(NoMapRestart: Boolean = False);
3908 var
3909 i, n, nb, nr: Integer;
3910 begin
3911 if not g_Game_IsServer then Exit;
3912 if gLMSRespawn = LMS_RESPAWN_NONE then Exit;
3913 gLMSRespawn := LMS_RESPAWN_NONE;
3914 gLMSRespawnTime := 0;
3915 MessageTime := 0;
3917 if (gGameSettings.GameMode = GM_COOP) and not NoMapRestart then
3918 begin
3919 gMissionFailed := True;
3920 g_Game_RestartLevel;
3921 Exit;
3922 end;
3924 n := 0; nb := 0; nr := 0;
3925 for i := Low(gPlayers) to High(gPlayers) do
3926 if (gPlayers[i] <> nil) and
3927 ((not gPlayers[i].FSpectator) or gPlayers[i].FWantsInGame or
3928 (gPlayers[i] is TBot)) then
3929 begin
3930 Inc(n);
3931 if gPlayers[i].Team = TEAM_RED then Inc(nr)
3932 else if gPlayers[i].Team = TEAM_BLUE then Inc(nb)
3933 end;
3935 if (n < 2) or ((gGameSettings.GameMode = GM_TDM) and ((nr = 0) or (nb = 0))) then
3936 begin
3937 // wait a second until the fuckers finally decide to join
3938 gLMSRespawn := LMS_RESPAWN_WARMUP;
3939 gLMSRespawnTime := gTime + 1000;
3940 gLMSSoftSpawn := NoMapRestart;
3941 Exit;
3942 end;
3944 g_Player_RemoveAllCorpses;
3945 g_Game_Message(_lc[I_MESSAGE_LMS_START], 144);
3946 if g_Game_IsNet then
3947 MH_SEND_GameEvent(NET_EV_LMS_START);
3949 for i := Low(gPlayers) to High(gPlayers) do
3950 begin
3951 if gPlayers[i] = nil then continue;
3952 if gPlayers[i] is TBot then gPlayers[i].FWantsInGame := True;
3953 // don't touch normal spectators
3954 if gPlayers[i].FSpectator and not gPlayers[i].FWantsInGame then
3955 begin
3956 gPlayers[i].FNoRespawn := True;
3957 gPlayers[i].Lives := 0;
3958 if g_Game_IsNet then
3959 MH_SEND_PlayerStats(gPlayers[I].UID);
3960 continue;
3961 end;
3962 gPlayers[i].FNoRespawn := False;
3963 gPlayers[i].Lives := gGameSettings.MaxLives;
3964 gPlayers[i].Respawn(False, True);
3965 if gGameSettings.GameMode = GM_COOP then
3966 begin
3967 gPlayers[i].Frags := 0;
3968 gPlayers[i].RecallState;
3969 end;
3970 if (gPlayer1 = nil) and (gLMSPID1 > 0) then
3971 gPlayer1 := g_Player_Get(gLMSPID1);
3972 if (gPlayer2 = nil) and (gLMSPID2 > 0) then
3973 gPlayer2 := g_Player_Get(gLMSPID2);
3974 end;
3976 for i := Low(gItems) to High(gItems) do
3977 begin
3978 if gItems[i].Respawnable then
3979 begin
3980 gItems[i].QuietRespawn := True;
3981 gItems[i].RespawnTime := 0;
3982 end
3983 else
3984 begin
3985 g_Items_Remove(i);
3986 if g_Game_IsNet then MH_SEND_ItemDestroy(True, i);
3987 end;
3988 end;
3990 for i := Low(gMonsters) to High(gMonsters) do
3991 begin
3992 if (gMonsters[i] <> nil) and not gMonsters[i].FNoRespawn then
3993 gMonsters[i].Respawn;
3994 end;
3996 gLMSSoftSpawn := False;
3997 end;
3999 function g_Game_GetFirstMap(WAD: String): String;
4000 begin
4001 Result := '';
4003 MapList := g_Map_GetMapsList(WAD);
4004 if MapList = nil then
4005 Exit;
4007 SortSArray(MapList);
4008 Result := MapList[Low(MapList)];
4010 if not g_Map_Exist(WAD + ':\' + Result) then
4011 Result := '';
4013 MapList := nil;
4014 end;
4016 function g_Game_GetNextMap(): String;
4017 var
4018 I: Integer;
4019 Map: string;
4020 begin
4021 Result := '';
4023 MapList := g_Map_GetMapsList(MapsDir + gGameSettings.WAD);
4024 if MapList = nil then
4025 Exit;
4027 Map := g_ExtractFileName(gMapInfo.Map);
4029 SortSArray(MapList);
4030 MapIndex := -255;
4031 for I := Low(MapList) to High(MapList) do
4032 if Map = MapList[I] then
4033 begin
4034 MapIndex := I;
4035 Break;
4036 end;
4038 if MapIndex <> -255 then
4039 begin
4040 if MapIndex = High(MapList) then
4041 Result := MapList[Low(MapList)]
4042 else
4043 Result := MapList[MapIndex + 1];
4045 if not g_Map_Exist(MapsDir + gGameSettings.WAD + ':\' + Result) then Result := Map;
4046 end;
4048 MapList := nil;
4049 end;
4051 procedure g_Game_NextLevel();
4052 begin
4053 if gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF, GM_COOP] then
4054 gExit := EXIT_ENDLEVELCUSTOM
4055 else
4056 begin
4057 gExit := EXIT_ENDLEVELSINGLE;
4058 Exit;
4059 end;
4061 if gNextMap <> '' then Exit;
4062 gNextMap := g_Game_GetNextMap();
4063 end;
4065 function g_Game_IsTestMap(): Boolean;
4066 begin
4067 result := StrEquCI1251(TEST_MAP_NAME, g_ExtractFileName(gMapInfo.Map));
4068 end;
4070 procedure g_Game_DeleteTestMap();
4071 var
4072 a: Integer;
4073 MapName: Char16;
4074 WadName: string;
4076 WAD: TWADFile;
4077 MapList: SArray;
4078 time: Integer;
4080 begin
4081 a := Pos('.wad:\', gMapToDelete);
4082 if a = 0 then
4083 Exit;
4085 // Âûäåëÿåì èìÿ wad-ôàéëà è èìÿ êàðòû:
4086 WadName := Copy(gMapToDelete, 1, a + 3);
4087 Delete(gMapToDelete, 1, a + 5);
4088 gMapToDelete := UpperCase(gMapToDelete);
4089 MapName := '';
4090 CopyMemory(@MapName[0], @gMapToDelete[1], Min(16, Length(gMapToDelete)));
4093 // Èìÿ êàðòû íå ñòàíäàðòíîå òåñòîâîå:
4094 if MapName <> TEST_MAP_NAME then
4095 Exit;
4097 if not gTempDelete then
4098 begin
4099 time := g_GetFileTime(WadName);
4100 WAD := TWADFile.Create();
4102 // ×èòàåì Wad-ôàéë:
4103 if not WAD.ReadFile(WadName) then
4104 begin // Íåò òàêîãî WAD-ôàéëà
4105 WAD.Free();
4106 Exit;
4107 end;
4109 // Ñîñòàâëÿåì ñïèñîê êàðò è èùåì íóæíóþ:
4110 WAD.CreateImage();
4111 MapList := WAD.GetResourcesList('');
4113 if MapList <> nil then
4114 for a := 0 to High(MapList) do
4115 if MapList[a] = MapName then
4116 begin
4117 // Óäàëÿåì è ñîõðàíÿåì:
4118 WAD.RemoveResource('', MapName);
4119 WAD.SaveTo(WadName);
4120 Break;
4121 end;
4123 WAD.Free();
4124 g_SetFileTime(WadName, time);
4125 end else
4127 if gTempDelete then DeleteFile(WadName);
4128 end;
4130 procedure GameCVars(P: SArray);
4131 var
4132 a, b: Integer;
4133 stat: TPlayerStatArray;
4134 cmd, s: string;
4135 config: TConfig;
4136 begin
4137 stat := nil;
4138 cmd := LowerCase(P[0]);
4139 if cmd = 'r_showfps' then
4140 begin
4141 if (Length(P) > 1) and
4142 ((P[1] = '1') or (P[1] = '0')) then
4143 gShowFPS := (P[1][1] = '1');
4145 if gShowFPS then
4146 g_Console_Add(_lc[I_MSG_SHOW_FPS_ON])
4147 else
4148 g_Console_Add(_lc[I_MSG_SHOW_FPS_OFF]);
4149 end
4150 else if (cmd = 'g_friendlyfire') and not g_Game_IsClient then
4151 begin
4152 with gGameSettings do
4153 begin
4154 if (Length(P) > 1) and
4155 ((P[1] = '1') or (P[1] = '0')) then
4156 begin
4157 if (P[1][1] = '1') then
4158 Options := Options or GAME_OPTION_TEAMDAMAGE
4159 else
4160 Options := Options and (not GAME_OPTION_TEAMDAMAGE);
4161 end;
4163 if (LongBool(Options and GAME_OPTION_TEAMDAMAGE)) then
4164 g_Console_Add(_lc[I_MSG_FRIENDLY_FIRE_ON])
4165 else
4166 g_Console_Add(_lc[I_MSG_FRIENDLY_FIRE_OFF]);
4168 if g_Game_IsNet then MH_SEND_GameSettings;
4169 end;
4170 end
4171 else if (cmd = 'g_weaponstay') and not g_Game_IsClient then
4172 begin
4173 with gGameSettings do
4174 begin
4175 if (Length(P) > 1) and
4176 ((P[1] = '1') or (P[1] = '0')) then
4177 begin
4178 if (P[1][1] = '1') then
4179 Options := Options or GAME_OPTION_WEAPONSTAY
4180 else
4181 Options := Options and (not GAME_OPTION_WEAPONSTAY);
4182 end;
4184 if (LongBool(Options and GAME_OPTION_WEAPONSTAY)) then
4185 g_Console_Add(_lc[I_MSG_WEAPONSTAY_ON])
4186 else
4187 g_Console_Add(_lc[I_MSG_WEAPONSTAY_OFF]);
4189 if g_Game_IsNet then MH_SEND_GameSettings;
4190 end;
4191 end
4192 else if cmd = 'g_gamemode' then
4193 begin
4194 a := g_Game_TextToMode(P[1]);
4195 if a = GM_SINGLE then a := GM_COOP;
4196 if (Length(P) > 1) and (a <> GM_NONE) and (not g_Game_IsClient) then
4197 begin
4198 gSwitchGameMode := a;
4199 if (gGameOn and (gGameSettings.GameMode = GM_SINGLE)) or
4200 (gState = STATE_INTERSINGLE) then
4201 gSwitchGameMode := GM_SINGLE;
4202 if not gGameOn then
4203 gGameSettings.GameMode := gSwitchGameMode;
4204 end;
4205 if gSwitchGameMode = gGameSettings.GameMode then
4206 g_Console_Add(Format(_lc[I_MSG_GAMEMODE_CURRENT],
4207 [g_Game_ModeToText(gGameSettings.GameMode)]))
4208 else
4209 g_Console_Add(Format(_lc[I_MSG_GAMEMODE_CHANGE],
4210 [g_Game_ModeToText(gGameSettings.GameMode),
4211 g_Game_ModeToText(gSwitchGameMode)]));
4212 end
4213 else if (cmd = 'g_allow_exit') and not g_Game_IsClient then
4214 begin
4215 with gGameSettings do
4216 begin
4217 if (Length(P) > 1) and
4218 ((P[1] = '1') or (P[1] = '0')) then
4219 begin
4220 if (P[1][1] = '1') then
4221 Options := Options or GAME_OPTION_ALLOWEXIT
4222 else
4223 Options := Options and (not GAME_OPTION_ALLOWEXIT);
4224 end;
4226 if (LongBool(Options and GAME_OPTION_ALLOWEXIT)) then
4227 g_Console_Add(_lc[I_MSG_ALLOWEXIT_ON])
4228 else
4229 g_Console_Add(_lc[I_MSG_ALLOWEXIT_OFF]);
4230 g_Console_Add(_lc[I_MSG_ONMAPCHANGE]);
4232 if g_Game_IsNet then MH_SEND_GameSettings;
4233 end;
4234 end
4235 else if (cmd = 'g_allow_monsters') and not g_Game_IsClient then
4236 begin
4237 with gGameSettings do
4238 begin
4239 if (Length(P) > 1) and
4240 ((P[1] = '1') or (P[1] = '0')) then
4241 begin
4242 if (P[1][1] = '1') then
4243 Options := Options or GAME_OPTION_MONSTERS
4244 else
4245 Options := Options and (not GAME_OPTION_MONSTERS);
4246 end;
4248 if (LongBool(Options and GAME_OPTION_MONSTERS)) then
4249 g_Console_Add(_lc[I_MSG_ALLOWMON_ON])
4250 else
4251 g_Console_Add(_lc[I_MSG_ALLOWMON_OFF]);
4252 g_Console_Add(_lc[I_MSG_ONMAPCHANGE]);
4254 if g_Game_IsNet then MH_SEND_GameSettings;
4255 end;
4256 end
4257 else if (cmd = 'g_bot_vsplayers') and not g_Game_IsClient then
4258 begin
4259 with gGameSettings do
4260 begin
4261 if (Length(P) > 1) and
4262 ((P[1] = '1') or (P[1] = '0')) then
4263 begin
4264 if (P[1][1] = '1') then
4265 Options := Options or GAME_OPTION_BOTVSPLAYER
4266 else
4267 Options := Options and (not GAME_OPTION_BOTVSPLAYER);
4268 end;
4270 if (LongBool(Options and GAME_OPTION_BOTVSPLAYER)) then
4271 g_Console_Add(_lc[I_MSG_BOTSVSPLAYERS_ON])
4272 else
4273 g_Console_Add(_lc[I_MSG_BOTSVSPLAYERS_OFF]);
4275 if g_Game_IsNet then MH_SEND_GameSettings;
4276 end;
4277 end
4278 else if (cmd = 'g_bot_vsmonsters') and not g_Game_IsClient then
4279 begin
4280 with gGameSettings do
4281 begin
4282 if (Length(P) > 1) and
4283 ((P[1] = '1') or (P[1] = '0')) then
4284 begin
4285 if (P[1][1] = '1') then
4286 Options := Options or GAME_OPTION_BOTVSMONSTER
4287 else
4288 Options := Options and (not GAME_OPTION_BOTVSMONSTER);
4289 end;
4291 if (LongBool(Options and GAME_OPTION_BOTVSMONSTER)) then
4292 g_Console_Add(_lc[I_MSG_BOTSVSMONSTERS_ON])
4293 else
4294 g_Console_Add(_lc[I_MSG_BOTSVSMONSTERS_OFF]);
4296 if g_Game_IsNet then MH_SEND_GameSettings;
4297 end;
4298 end
4299 else if (cmd = 'g_warmuptime') and not g_Game_IsClient then
4300 begin
4301 if Length(P) > 1 then
4302 begin
4303 if StrToIntDef(P[1], gGameSettings.WarmupTime) = 0 then
4304 gGameSettings.WarmupTime := 30
4305 else
4306 gGameSettings.WarmupTime := StrToIntDef(P[1], gGameSettings.WarmupTime);
4307 end;
4309 g_Console_Add(Format(_lc[I_MSG_WARMUP],
4310 [gGameSettings.WarmupTime]));
4311 g_Console_Add(_lc[I_MSG_ONMAPCHANGE]);
4312 end
4313 else if cmd = 'net_interp' then
4314 begin
4315 if (Length(P) > 1) then
4316 NetInterpLevel := StrToIntDef(P[1], NetInterpLevel);
4318 g_Console_Add('net_interp = ' + IntToStr(NetInterpLevel));
4319 config := TConfig.CreateFile(GameDir+'/'+CONFIG_FILENAME);
4320 config.WriteInt('Client', 'InterpolationSteps', NetInterpLevel);
4321 config.SaveFile(GameDir+'/'+CONFIG_FILENAME);
4322 config.Free();
4323 end
4324 else if cmd = 'net_forceplayerupdate' then
4325 begin
4326 if (Length(P) > 1) and
4327 ((P[1] = '1') or (P[1] = '0')) then
4328 NetForcePlayerUpdate := (P[1][1] = '1');
4330 if NetForcePlayerUpdate then
4331 g_Console_Add('net_forceplayerupdate = 1')
4332 else
4333 g_Console_Add('net_forceplayerupdate = 0');
4334 config := TConfig.CreateFile(GameDir+'/'+CONFIG_FILENAME);
4335 config.WriteBool('Client', 'ForcePlayerUpdate', NetForcePlayerUpdate);
4336 config.SaveFile(GameDir+'/'+CONFIG_FILENAME);
4337 config.Free();
4338 end
4339 else if cmd = 'net_predictself' then
4340 begin
4341 if (Length(P) > 1) and
4342 ((P[1] = '1') or (P[1] = '0')) then
4343 NetPredictSelf := (P[1][1] = '1');
4345 if NetPredictSelf then
4346 g_Console_Add('net_predictself = 1')
4347 else
4348 g_Console_Add('net_predictself = 0');
4349 config := TConfig.CreateFile(GameDir+'/'+CONFIG_FILENAME);
4350 config.WriteBool('Client', 'PredictSelf', NetPredictSelf);
4351 config.SaveFile(GameDir+'/'+CONFIG_FILENAME);
4352 config.Free();
4353 end
4354 else if cmd = 'sv_name' then
4355 begin
4356 if (Length(P) > 1) and (Length(P[1]) > 0) then
4357 begin
4358 NetServerName := P[1];
4359 if Length(NetServerName) > 64 then
4360 SetLength(NetServerName, 64);
4361 if g_Game_IsServer and g_Game_IsNet and NetUseMaster then
4362 g_Net_Slist_Update;
4363 end;
4365 g_Console_Add(cmd + ' = "' + NetServerName + '"');
4366 end
4367 else if cmd = 'sv_passwd' then
4368 begin
4369 if (Length(P) > 1) and (Length(P[1]) > 0) then
4370 begin
4371 NetPassword := P[1];
4372 if Length(NetPassword) > 24 then
4373 SetLength(NetPassword, 24);
4374 if g_Game_IsServer and g_Game_IsNet and NetUseMaster then
4375 g_Net_Slist_Update;
4376 end;
4378 g_Console_Add(cmd + ' = "' + AnsiLowerCase(NetPassword) + '"');
4379 end
4380 else if cmd = 'sv_maxplrs' then
4381 begin
4382 if (Length(P) > 1) then
4383 begin
4384 NetMaxClients := Min(Max(StrToIntDef(P[1], NetMaxClients), 1), NET_MAXCLIENTS);
4385 if g_Game_IsServer and g_Game_IsNet then
4386 begin
4387 b := 0;
4388 for a := 0 to High(NetClients) do
4389 if NetClients[a].Used then
4390 begin
4391 Inc(b);
4392 if b > NetMaxClients then
4393 begin
4394 s := g_Player_Get(NetClients[a].Player).Name;
4395 enet_peer_disconnect(NetClients[a].Peer, NET_DISC_FULL);
4396 g_Console_Add(Format(_lc[I_PLAYER_KICK], [s]));
4397 MH_SEND_GameEvent(NET_EV_PLAYER_KICK, 0, s);
4398 end;
4399 end;
4400 if NetUseMaster then
4401 g_Net_Slist_Update;
4402 end;
4403 end;
4405 g_Console_Add(cmd + ' = ' + IntToStr(NetMaxClients));
4406 end
4407 else if cmd = 'sv_public' then
4408 begin
4409 if (Length(P) > 1) then
4410 begin
4411 NetUseMaster := StrToIntDef(P[1], Byte(NetUseMaster)) > 0;
4412 if g_Game_IsServer and g_Game_IsNet then
4413 if NetUseMaster then
4414 begin
4415 if NetMPeer = nil then
4416 if not g_Net_Slist_Connect() then
4417 g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_SLIST_ERROR]);
4418 g_Net_Slist_Update();
4419 end
4420 else
4421 if NetMPeer <> nil then
4422 g_Net_Slist_Disconnect();
4423 end;
4425 g_Console_Add(cmd + ' = ' + IntToStr(Byte(NetUseMaster)));
4426 end
4427 else if cmd = 'sv_intertime' then
4428 begin
4429 if (Length(P) > 1) then
4430 gDefInterTime := Min(Max(StrToIntDef(P[1], gDefInterTime), -1), 120);
4432 g_Console_Add(cmd + ' = ' + IntToStr(gDefInterTime));
4433 end
4434 else if cmd = 'p1_name' then
4435 begin
4436 if (Length(P) > 1) and gGameOn then
4437 begin
4438 if g_Game_IsClient then
4439 begin
4440 gPlayer1Settings.Name := b_Text_Unformat(P[1]);
4441 MC_SEND_PlayerSettings;
4442 end
4443 else
4444 if gPlayer1 <> nil then
4445 begin
4446 gPlayer1.Name := b_Text_Unformat(P[1]);
4447 if g_Game_IsNet then MH_SEND_PlayerSettings(gPlayer1.UID);
4448 end
4449 else
4450 gPlayer1Settings.Name := b_Text_Unformat(P[1]);
4451 end;
4452 end
4453 else if cmd = 'p2_name' then
4454 begin
4455 if (Length(P) > 1) and gGameOn then
4456 begin
4457 if g_Game_IsClient then
4458 begin
4459 gPlayer2Settings.Name := b_Text_Unformat(P[1]);
4460 MC_SEND_PlayerSettings;
4461 end
4462 else
4463 if gPlayer2 <> nil then
4464 begin
4465 gPlayer2.Name := b_Text_Unformat(P[1]);
4466 if g_Game_IsNet then MH_SEND_PlayerSettings(gPlayer2.UID);
4467 end
4468 else
4469 gPlayer2Settings.Name := b_Text_Unformat(P[1]);
4470 end;
4471 end
4472 else if cmd = 'p1_color' then
4473 begin
4474 if Length(P) > 3 then
4475 if g_Game_IsClient then
4476 begin
4477 gPlayer1Settings.Color := _RGB(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4478 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4479 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4480 MC_SEND_PlayerSettings;
4481 end
4482 else
4483 if gPlayer1 <> nil then
4484 begin
4485 gPlayer1.Model.SetColor(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4486 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4487 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4488 if g_Game_IsNet then MH_SEND_PlayerSettings(gPlayer1.UID);
4489 end
4490 else
4491 gPlayer1Settings.Color := _RGB(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4492 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4493 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4494 end
4495 else if (cmd = 'p2_color') and not g_Game_IsNet then
4496 begin
4497 if Length(P) > 3 then
4498 if g_Game_IsClient then
4499 begin
4500 gPlayer2Settings.Color := _RGB(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4501 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4502 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4503 MC_SEND_PlayerSettings;
4504 end
4505 else
4506 if gPlayer2 <> nil then
4507 begin
4508 gPlayer2.Model.SetColor(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4509 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4510 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4511 if g_Game_IsNet then MH_SEND_PlayerSettings(gPlayer2.UID);
4512 end
4513 else
4514 gPlayer2Settings.Color := _RGB(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4515 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4516 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4517 end
4518 else if gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT] then
4519 begin
4520 if cmd = 'r_showtime' then
4521 begin
4522 if (Length(P) > 1) and
4523 ((P[1] = '1') or (P[1] = '0')) then
4524 gShowTime := (P[1][1] = '1');
4526 if gShowTime then
4527 g_Console_Add(_lc[I_MSG_TIME_ON])
4528 else
4529 g_Console_Add(_lc[I_MSG_TIME_OFF]);
4530 end
4531 else if cmd = 'r_showscore' then
4532 begin
4533 if (Length(P) > 1) and
4534 ((P[1] = '1') or (P[1] = '0')) then
4535 gShowGoals := (P[1][1] = '1');
4537 if gShowGoals then
4538 g_Console_Add(_lc[I_MSG_SCORE_ON])
4539 else
4540 g_Console_Add(_lc[I_MSG_SCORE_OFF]);
4541 end
4542 else if cmd = 'r_showstat' then
4543 begin
4544 if (Length(P) > 1) and
4545 ((P[1] = '1') or (P[1] = '0')) then
4546 gShowStat := (P[1][1] = '1');
4548 if gShowStat then
4549 g_Console_Add(_lc[I_MSG_STATS_ON])
4550 else
4551 g_Console_Add(_lc[I_MSG_STATS_OFF]);
4552 end
4553 else if cmd = 'r_showkillmsg' then
4554 begin
4555 if (Length(P) > 1) and
4556 ((P[1] = '1') or (P[1] = '0')) then
4557 gShowKillMsg := (P[1][1] = '1');
4559 if gShowKillMsg then
4560 g_Console_Add(_lc[I_MSG_KILL_MSGS_ON])
4561 else
4562 g_Console_Add(_lc[I_MSG_KILL_MSGS_OFF]);
4563 end
4564 else if cmd = 'r_showlives' then
4565 begin
4566 if (Length(P) > 1) and
4567 ((P[1] = '1') or (P[1] = '0')) then
4568 gShowLives := (P[1][1] = '1');
4570 if gShowLives then
4571 g_Console_Add(_lc[I_MSG_LIVES_ON])
4572 else
4573 g_Console_Add(_lc[I_MSG_LIVES_OFF]);
4574 end
4575 else if cmd = 'r_showspect' then
4576 begin
4577 if (Length(P) > 1) and
4578 ((P[1] = '1') or (P[1] = '0')) then
4579 gSpectHUD := (P[1][1] = '1');
4581 if gSpectHUD then
4582 g_Console_Add(_lc[I_MSG_SPECT_HUD_ON])
4583 else
4584 g_Console_Add(_lc[I_MSG_SPECT_HUD_OFF]);
4585 end
4586 else if cmd = 'r_showping' then
4587 begin
4588 if (Length(P) > 1) and
4589 ((P[1] = '1') or (P[1] = '0')) then
4590 gShowPing := (P[1][1] = '1');
4592 if gShowPing then
4593 g_Console_Add(_lc[I_MSG_PING_ON])
4594 else
4595 g_Console_Add(_lc[I_MSG_PING_OFF]);
4596 end
4597 else if (cmd = 'g_scorelimit') and not g_Game_IsClient then
4598 begin
4599 if Length(P) > 1 then
4600 begin
4601 if StrToIntDef(P[1], gGameSettings.GoalLimit) = 0 then
4602 gGameSettings.GoalLimit := 0
4603 else
4604 begin
4605 b := 0;
4607 if gGameSettings.GameMode = GM_DM then
4608 begin // DM
4609 stat := g_Player_GetStats();
4610 if stat <> nil then
4611 for a := 0 to High(stat) do
4612 if stat[a].Frags > b then
4613 b := stat[a].Frags;
4614 end
4615 else // TDM/CTF
4616 b := Max(gTeamStat[TEAM_RED].Goals, gTeamStat[TEAM_BLUE].Goals);
4618 gGameSettings.GoalLimit := Max(StrToIntDef(P[1], gGameSettings.GoalLimit), b);
4619 end;
4621 if g_Game_IsNet then MH_SEND_GameSettings;
4622 end;
4624 g_Console_Add(Format(_lc[I_MSG_SCORE_LIMIT], [gGameSettings.GoalLimit]));
4625 end
4626 else if (cmd = 'g_timelimit') and not g_Game_IsClient then
4627 begin
4628 if (Length(P) > 1) and (StrToIntDef(P[1], -1) >= 0) then
4629 gGameSettings.TimeLimit := StrToIntDef(P[1], -1);
4631 g_Console_Add(Format(_lc[I_MSG_TIME_LIMIT],
4632 [gGameSettings.TimeLimit div 3600,
4633 (gGameSettings.TimeLimit div 60) mod 60,
4634 gGameSettings.TimeLimit mod 60]));
4635 if g_Game_IsNet then MH_SEND_GameSettings;
4636 end
4637 else if (cmd = 'g_maxlives') and not g_Game_IsClient then
4638 begin
4639 if Length(P) > 1 then
4640 begin
4641 if StrToIntDef(P[1], gGameSettings.MaxLives) = 0 then
4642 gGameSettings.MaxLives := 0
4643 else
4644 begin
4645 b := 0;
4646 stat := g_Player_GetStats();
4647 if stat <> nil then
4648 for a := 0 to High(stat) do
4649 if stat[a].Lives > b then
4650 b := stat[a].Lives;
4651 gGameSettings.MaxLives :=
4652 Max(StrToIntDef(P[1], gGameSettings.MaxLives), b);
4653 end;
4654 end;
4656 g_Console_Add(Format(_lc[I_MSG_LIVES],
4657 [gGameSettings.MaxLives]));
4658 if g_Game_IsNet then MH_SEND_GameSettings;
4659 end;
4660 end;
4661 end;
4663 procedure DebugCommands(P: SArray);
4664 var
4665 a, b: Integer;
4666 cmd: string;
4667 //pt: TPoint;
4668 begin
4669 // Êîìàíäû îòëàäî÷íîãî ðåæèìà:
4670 if gDebugMode then
4671 begin
4672 cmd := LowerCase(P[0]);
4673 if cmd = 'd_window' then
4674 begin
4675 g_Console_Add(Format('gWinPosX = %d, gWinPosY %d', [gWinPosX, gWinPosY]));
4676 g_Console_Add(Format('gWinRealPosX = %d, gWinRealPosY %d', [gWinRealPosX, gWinRealPosY]));
4677 g_Console_Add(Format('gScreenWidth = %d, gScreenHeight = %d', [gScreenWidth, gScreenHeight]));
4678 g_Console_Add(Format('gWinSizeX = %d, gWinSizeY = %d', [gWinSizeX, gWinSizeY]));
4679 g_Console_Add(Format('Frame X = %d, Y = %d, Caption Y = %d', [gWinFrameX, gWinFrameY, gWinCaption]));
4680 end
4681 else if cmd = 'd_sounds' then
4682 begin
4683 if (Length(P) > 1) and
4684 ((P[1] = '1') or (P[1] = '0')) then
4685 g_Debug_Sounds := (P[1][1] = '1');
4687 g_Console_Add(Format('d_sounds is %d', [Byte(g_Debug_Sounds)]));
4688 end
4689 else if cmd = 'd_frames' then
4690 begin
4691 if (Length(P) > 1) and
4692 ((P[1] = '1') or (P[1] = '0')) then
4693 g_Debug_Frames := (P[1][1] = '1');
4695 g_Console_Add(Format('d_frames is %d', [Byte(g_Debug_Frames)]));
4696 end
4697 else if cmd = 'd_winmsg' then
4698 begin
4699 if (Length(P) > 1) and
4700 ((P[1] = '1') or (P[1] = '0')) then
4701 g_Debug_WinMsgs := (P[1][1] = '1');
4703 g_Console_Add(Format('d_winmsg is %d', [Byte(g_Debug_WinMsgs)]));
4704 end
4705 else if (cmd = 'd_monoff') and not g_Game_IsNet then
4706 begin
4707 if (Length(P) > 1) and
4708 ((P[1] = '1') or (P[1] = '0')) then
4709 g_Debug_MonsterOff := (P[1][1] = '1');
4711 g_Console_Add(Format('d_monoff is %d', [Byte(g_debug_MonsterOff)]));
4712 end
4713 else if (cmd = 'd_botoff') and not g_Game_IsNet then
4714 begin
4715 if Length(P) > 1 then
4716 case P[1][1] of
4717 '0': g_debug_BotAIOff := 0;
4718 '1': g_debug_BotAIOff := 1;
4719 '2': g_debug_BotAIOff := 2;
4720 '3': g_debug_BotAIOff := 3;
4721 end;
4723 g_Console_Add(Format('d_botoff is %d', [g_debug_BotAIOff]));
4724 end
4725 else if cmd = 'd_monster' then
4726 begin
4727 if gGameOn and (gPlayer1 <> nil) and (gPlayer1.Live) and (not g_Game_IsNet) then
4728 if Length(P) < 2 then
4729 begin
4730 g_Console_Add(cmd + ' [ID | Name] [behaviour]');
4731 g_Console_Add('ID | Name');
4732 for b := MONSTER_DEMON to MONSTER_MAN do
4733 g_Console_Add(Format('%2d | %s', [b, g_Monsters_GetNameByID(b)]));
4734 end else
4735 begin
4736 a := StrToIntDef(P[1], 0);
4737 if (a < MONSTER_DEMON) or (a > MONSTER_MAN) then
4738 a := g_Monsters_GetIDByName(P[1]);
4740 if (a < MONSTER_DEMON) or (a > MONSTER_MAN) then
4741 g_Console_Add(Format(_lc[I_MSG_NO_MONSTER], [P[1]]))
4742 else
4743 begin
4744 with gPlayer1.Obj do
4745 b := g_Monsters_Create(a,
4746 X + Rect.X + (Rect.Width div 2),
4747 Y + Rect.Y + Rect.Height,
4748 gPlayer1.Direction, True);
4749 if (Length(P) > 2) and (b >= 0) then
4750 gMonsters[b].MonsterBehaviour := Min(Max(StrToIntDef(P[2], BH_NORMAL), BH_NORMAL), BH_GOOD);
4751 end;
4752 end;
4753 end
4754 else if (cmd = 'd_health') then
4755 begin
4756 if (Length(P) > 1) and
4757 ((P[1] = '1') or (P[1] = '0')) then
4758 g_debug_HealthBar := (P[1][1] = '1');
4760 g_Console_Add(Format('d_health is %d', [Byte(g_debug_HealthBar)]));
4761 end
4762 else if (cmd = 'd_player') then
4763 begin
4764 if (Length(P) > 1) and
4765 ((P[1] = '1') or (P[1] = '0')) then
4766 g_debug_Player := (P[1][1] = '1');
4768 g_Console_Add(Format(cmd + ' is %d', [Byte(g_Debug_Player)]));
4769 end
4770 else if (cmd = 'd_joy') then
4771 begin
4772 for a := 1 to 8 do
4773 g_Console_Add(e_JoystickStateToString(a));
4774 end;
4775 end
4776 else
4777 g_Console_Add(_lc[I_MSG_NOT_DEBUG]);
4778 end;
4781 procedure GameCheats(P: SArray);
4782 var
4783 cmd: string;
4784 f, a: Integer;
4785 plr: TPlayer;
4786 begin
4787 if (not gGameOn) or (not gCheats) or ((gGameSettings.GameType <> GT_SINGLE) and
4788 (gGameSettings.GameMode <> GM_COOP) and (not gDebugMode)) or g_Game_IsNet then
4789 begin
4790 g_Console_Add('not available');
4791 exit;
4792 end;
4793 plr := gPlayer1;
4794 if plr = nil then
4795 begin
4796 g_Console_Add('where is the player?!');
4797 exit;
4798 end;
4799 cmd := LowerCase(P[0]);
4800 // god
4801 if cmd = 'god' then
4802 begin
4803 plr.GodMode := not plr.GodMode;
4804 if plr.GodMode then g_Console_Add('player is godlike now') else g_Console_Add('player is mortal now');
4805 exit;
4806 end;
4807 // give <health|exit|weapons|air|suit|jetpack|berserk|all>
4808 if cmd = 'give' then
4809 begin
4810 if length(P) < 2 then begin g_Console_Add('give what?!'); exit; end;
4811 for f := 1 to High(P) do
4812 begin
4813 cmd := LowerCase(P[f]);
4814 if cmd = 'health' then begin plr.RestoreHealthArmor(); g_Console_Add('player feels himself better'); continue; end;
4815 if (cmd = 'all') or (cmd = 'weapons') then begin plr.AllRulez(False); g_Console_Add('player got the gifts'); continue; end;
4816 if cmd = 'exit' then
4817 begin
4818 if gTriggers <> nil then
4819 begin
4820 for a := 0 to High(gTriggers) do
4821 begin
4822 if gTriggers[a].TriggerType = TRIGGER_EXIT then
4823 begin
4824 g_Console_Add('player left the map');
4825 gExitByTrigger := True;
4826 g_Game_ExitLevel(gTriggers[a].Data.MapName);
4827 break;
4828 end;
4829 end;
4830 end;
4831 continue;
4832 end;
4833 if cmd = 'air' then begin plr.GiveItem(ITEM_OXYGEN); g_Console_Add('player got some air'); continue; end;
4834 if cmd = 'jetpack' then begin plr.GiveItem(ITEM_JETPACK); g_Console_Add('player got jetpack'); continue; end;
4835 if cmd = 'suit' then begin plr.GiveItem(ITEM_SUIT); g_Console_Add('player got envirosuit'); continue; end;
4836 if cmd = 'berserk' then begin plr.GiveItem(ITEM_MEDKIT_BLACK); g_Console_Add('player got berserk pack'); continue; end;
4837 g_Console_Add('i don''t know how to give '''+cmd+'''!');
4838 end;
4839 exit;
4840 end;
4841 // open
4842 if cmd = 'open' then
4843 begin
4844 g_Console_Add('player activated sesame');
4845 g_Triggers_OpenAll();
4846 exit;
4847 end;
4848 // fly
4849 if cmd = 'fly' then
4850 begin
4851 gFly := not gFly;
4852 if gFly then g_Console_Add('player feels himself lighter') else g_Console_Add('player lost his wings');
4853 exit;
4854 end;
4855 // noclip
4856 if cmd = 'noclip' then
4857 begin
4858 plr.SwitchNoClip;
4859 g_Console_Add('wall hardeness adjusted');
4860 exit;
4861 end;
4862 // notarget
4863 if cmd = 'notarget' then
4864 begin
4865 plr.NoTarget := not plr.NoTarget;
4866 if plr.NoTarget then g_Console_Add('player hides in shadows') else g_Console_Add('player is brave again');
4867 exit;
4868 end;
4869 // noreload
4870 if cmd = 'noreload' then
4871 begin
4872 plr.NoReload := not plr.NoReload;
4873 if plr.NoReload then g_Console_Add('player is action hero now') else g_Console_Add('player is ordinary man now');
4874 exit;
4875 end;
4876 // speedy
4877 if cmd = 'speedy' then
4878 begin
4879 MAX_RUNVEL := 32-MAX_RUNVEL;
4880 g_Console_Add('speed adjusted');
4881 exit;
4882 end;
4883 // jumpy
4884 if cmd = 'jumpy' then
4885 begin
4886 VEL_JUMP := 30-VEL_JUMP;
4887 g_Console_Add('jump height adjusted');
4888 exit;
4889 end;
4890 // automap
4891 if cmd = 'automap' then
4892 begin
4893 gShowMap := not gShowMap;
4894 if gShowMap then g_Console_Add('player gains second sight') else g_Console_Add('player lost second sight');
4895 exit;
4896 end;
4897 // aimline
4898 if cmd = 'aimline' then
4899 begin
4900 gAimLine := not gAimLine;
4901 if gAimLine then g_Console_Add('player gains laser sight') else g_Console_Add('player lost laser sight');
4902 exit;
4903 end;
4904 end;
4906 procedure GameCommands(P: SArray);
4907 var
4908 a, b: Integer;
4909 s, pw: String;
4910 chstr: string;
4911 cmd: string;
4912 pl: pTNetClient = nil;
4913 plr: TPlayer;
4914 prt: Word;
4915 nm: Boolean;
4916 listen: LongWord;
4917 begin
4918 // Îáùèå êîìàíäû:
4919 cmd := LowerCase(P[0]);
4920 chstr := '';
4921 if (cmd = 'quit') or
4922 (cmd = 'exit') then
4923 begin
4924 g_Game_Free();
4925 g_Game_Quit();
4926 Exit;
4927 end
4928 else if cmd = 'pause' then
4929 begin
4930 if (g_ActiveWindow = nil) then
4931 g_Game_Pause(not gPause);
4932 end
4933 else if cmd = 'endgame' then
4934 gExit := EXIT_SIMPLE
4935 else if cmd = 'restart' then
4936 begin
4937 if gGameOn or (gState in [STATE_INTERSINGLE, STATE_INTERCUSTOM]) then
4938 begin
4939 if g_Game_IsClient then
4940 begin
4941 g_Console_Add(_lc[I_MSG_SERVERONLY]);
4942 Exit;
4943 end;
4944 g_Game_Restart();
4945 end else
4946 g_Console_Add(_lc[I_MSG_NOT_GAME]);
4947 end
4948 else if cmd = 'kick' then
4949 begin
4950 if g_Game_IsServer then
4951 begin
4952 if Length(P) < 2 then
4953 begin
4954 g_Console_Add('kick <name>');
4955 Exit;
4956 end;
4957 if P[1] = '' then
4958 begin
4959 g_Console_Add('kick <name>');
4960 Exit;
4961 end;
4963 if g_Game_IsNet then
4964 pl := g_Net_Client_ByName(P[1]);
4965 if (pl <> nil) then
4966 begin
4967 s := g_Net_ClientName_ByID(pl^.ID);
4968 enet_peer_disconnect(pl^.Peer, NET_DISC_KICK);
4969 g_Console_Add(Format(_lc[I_PLAYER_KICK], [s]));
4970 MH_SEND_GameEvent(NET_EV_PLAYER_KICK, 0, s);
4971 if NetUseMaster then
4972 g_Net_Slist_Update;
4973 end else if gPlayers <> nil then
4974 for a := Low(gPlayers) to High(gPlayers) do
4975 if gPlayers[a] <> nil then
4976 if Copy(LowerCase(gPlayers[a].Name), 1, Length(P[1])) = LowerCase(P[1]) then
4977 begin
4978 // Íå îòêëþ÷àòü îñíîâíûõ èãðîêîâ â ñèíãëå
4979 if not(gPlayers[a] is TBot) and (gGameSettings.GameType = GT_SINGLE) then
4980 continue;
4981 gPlayers[a].Lives := 0;
4982 gPlayers[a].Kill(K_SIMPLEKILL, 0, HIT_DISCON);
4983 g_Console_Add(Format(_lc[I_PLAYER_LEAVE], [gPlayers[a].Name]), True);
4984 g_Player_Remove(gPlayers[a].UID);
4985 if NetUseMaster then
4986 g_Net_Slist_Update;
4987 // Åñëè íå ïåðåìåøàòü, ïðè äîáàâëåíèè íîâûõ áîòîâ ïîÿâÿòñÿ ñòàðûå
4988 g_Bot_MixNames();
4989 end;
4990 end else
4991 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
4992 end
4993 else if cmd = 'kick_id' then
4994 begin
4995 if g_Game_IsServer and g_Game_IsNet then
4996 begin
4997 if Length(P) < 2 then
4998 begin
4999 g_Console_Add('kick_id <client ID>');
5000 Exit;
5001 end;
5002 if P[1] = '' then
5003 begin
5004 g_Console_Add('kick_id <client ID>');
5005 Exit;
5006 end;
5008 a := StrToIntDef(P[1], 0);
5009 if (NetClients <> nil) and (a <= High(NetClients)) then
5010 begin
5011 if NetClients[a].Used and (NetClients[a].Peer <> nil) then
5012 begin
5013 s := g_Net_ClientName_ByID(NetClients[a].ID);
5014 enet_peer_disconnect(NetClients[a].Peer, NET_DISC_KICK);
5015 g_Console_Add(Format(_lc[I_PLAYER_KICK], [s]));
5016 MH_SEND_GameEvent(NET_EV_PLAYER_KICK, 0, s);
5017 if NetUseMaster then
5018 g_Net_Slist_Update;
5019 end;
5020 end;
5021 end else
5022 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5023 end
5024 else if cmd = 'ban' then
5025 begin
5026 if g_Game_IsServer and g_Game_IsNet then
5027 begin
5028 if Length(P) < 2 then
5029 begin
5030 g_Console_Add('ban <name>');
5031 Exit;
5032 end;
5033 if P[1] = '' then
5034 begin
5035 g_Console_Add('ban <name>');
5036 Exit;
5037 end;
5039 pl := g_Net_Client_ByName(P[1]);
5040 if (pl <> nil) then
5041 begin
5042 s := g_Net_ClientName_ByID(pl^.ID);
5043 g_Net_BanHost(pl^.Peer^.address.host, False);
5044 enet_peer_disconnect(pl^.Peer, NET_DISC_TEMPBAN);
5045 g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
5046 MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
5047 if NetUseMaster then
5048 g_Net_Slist_Update;
5049 end else
5050 g_Console_Add(Format(_lc[I_NET_ERR_NAME404], [P[1]]));
5051 end else
5052 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5053 end
5054 else if cmd = 'ban_id' then
5055 begin
5056 if g_Game_IsServer and g_Game_IsNet then
5057 begin
5058 if Length(P) < 2 then
5059 begin
5060 g_Console_Add('ban_id <client ID>');
5061 Exit;
5062 end;
5063 if P[1] = '' then
5064 begin
5065 g_Console_Add('ban_id <client ID>');
5066 Exit;
5067 end;
5069 a := StrToIntDef(P[1], 0);
5070 if (NetClients <> nil) and (a <= High(NetClients)) then
5071 if NetClients[a].Used and (NetClients[a].Peer <> nil) then
5072 begin
5073 s := g_Net_ClientName_ByID(NetClients[a].ID);
5074 g_Net_BanHost(NetClients[a].Peer^.address.host, False);
5075 enet_peer_disconnect(NetClients[a].Peer, NET_DISC_TEMPBAN);
5076 g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
5077 MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
5078 if NetUseMaster then
5079 g_Net_Slist_Update;
5080 end;
5081 end else
5082 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5083 end
5084 else if cmd = 'permban' then
5085 begin
5086 if g_Game_IsServer and g_Game_IsNet then
5087 begin
5088 if Length(P) < 2 then
5089 begin
5090 g_Console_Add('permban <name>');
5091 Exit;
5092 end;
5093 if P[1] = '' then
5094 begin
5095 g_Console_Add('permban <name>');
5096 Exit;
5097 end;
5099 pl := g_Net_Client_ByName(P[1]);
5100 if (pl <> nil) then
5101 begin
5102 s := g_Net_ClientName_ByID(pl^.ID);
5103 g_Net_BanHost(pl^.Peer^.address.host);
5104 enet_peer_disconnect(pl^.Peer, NET_DISC_BAN);
5105 g_Net_SaveBanList();
5106 g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
5107 MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
5108 if NetUseMaster then
5109 g_Net_Slist_Update;
5110 end else
5111 g_Console_Add(Format(_lc[I_NET_ERR_NAME404], [P[1]]));
5112 end else
5113 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5114 end
5115 else if cmd = 'permban_id' then
5116 begin
5117 if g_Game_IsServer and g_Game_IsNet then
5118 begin
5119 if Length(P) < 2 then
5120 begin
5121 g_Console_Add('permban_id <client ID>');
5122 Exit;
5123 end;
5124 if P[1] = '' then
5125 begin
5126 g_Console_Add('permban_id <client ID>');
5127 Exit;
5128 end;
5130 a := StrToIntDef(P[1], 0);
5131 if (NetClients <> nil) and (a <= High(NetClients)) then
5132 if NetClients[a].Used and (NetClients[a].Peer <> nil) then
5133 begin
5134 s := g_Net_ClientName_ByID(NetClients[a].ID);
5135 g_Net_BanHost(NetClients[a].Peer^.address.host);
5136 enet_peer_disconnect(NetClients[a].Peer, NET_DISC_BAN);
5137 g_Net_SaveBanList();
5138 g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
5139 MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
5140 if NetUseMaster then
5141 g_Net_Slist_Update;
5142 end;
5143 end else
5144 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5145 end
5146 else if cmd = 'unban' then
5147 begin
5148 if g_Game_IsServer and g_Game_IsNet then
5149 begin
5150 if Length(P) < 2 then
5151 begin
5152 g_Console_Add('unban <IP Address>');
5153 Exit;
5154 end;
5155 if P[1] = '' then
5156 begin
5157 g_Console_Add('unban <IP Address>');
5158 Exit;
5159 end;
5161 if g_Net_UnbanHost(P[1]) then
5162 begin
5163 g_Console_Add(Format(_lc[I_MSG_UNBAN_OK], [P[1]]));
5164 g_Net_SaveBanList();
5165 end else
5166 g_Console_Add(Format(_lc[I_MSG_UNBAN_FAIL], [P[1]]));
5167 end else
5168 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5169 end
5170 else if cmd = 'clientlist' then
5171 begin
5172 if g_Game_IsServer and g_Game_IsNet then
5173 begin
5174 b := 0;
5175 if NetClients <> nil then
5176 for a := Low(NetClients) to High(NetClients) do
5177 if NetClients[a].Used and (NetClients[a].Peer <> nil) then
5178 begin
5179 plr := g_Player_Get(NetClients[a].Player);
5180 if plr = nil then continue;
5181 Inc(b);
5182 g_Console_Add(Format('#%2d: %-15s | %s', [a,
5183 IpToStr(NetClients[a].Peer^.address.host), plr.Name]));
5184 end;
5185 if b = 0 then
5186 g_Console_Add(_lc[I_MSG_NOCLIENTS]);
5187 end else
5188 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5189 end
5190 else if cmd = 'connect' then
5191 begin
5192 if (NetMode = NET_NONE) then
5193 begin
5194 if Length(P) < 2 then
5195 begin
5196 g_Console_Add('connect <IP> [port] [password]');
5197 Exit;
5198 end;
5199 if P[1] = '' then
5200 begin
5201 g_Console_Add('connect <IP> [port] [password]');
5202 Exit;
5203 end;
5205 if Length(P) > 2 then
5206 prt := StrToIntDef(P[2], 25666)
5207 else
5208 prt := 25666;
5210 if Length(P) > 3 then
5211 pw := P[3]
5212 else
5213 pw := '';
5215 g_Game_StartClient(P[1], prt, pw);
5216 end;
5217 end
5218 else if cmd = 'disconnect' then
5219 begin
5220 if (NetMode = NET_CLIENT) then
5221 g_Net_Disconnect();
5222 end
5223 else if cmd = 'reconnect' then
5224 begin
5225 if (NetMode = NET_SERVER) then
5226 Exit;
5228 if (NetMode = NET_CLIENT) then
5229 begin
5230 g_Net_Disconnect();
5231 gExit := EXIT_SIMPLE;
5232 EndGame;
5233 end;
5235 //TODO: Use last successful password to reconnect, instead of ''
5236 g_Game_StartClient(NetClientIP, NetClientPort, '');
5237 end
5238 else if (cmd = 'addbot') or
5239 (cmd = 'bot_add') then
5240 begin
5241 if Length(P) > 1 then
5242 g_Bot_Add(TEAM_NONE, StrToIntDef(P[1], 2))
5243 else
5244 g_Bot_Add(TEAM_NONE, 2);
5245 end
5246 else if cmd = 'bot_addlist' then
5247 begin
5248 if Length(P) > 1 then
5249 if Length(P) = 2 then
5250 g_Bot_AddList(TEAM_NONE, P[1], StrToIntDef(P[1], -1))
5251 else
5252 g_Bot_AddList(IfThen(P[2] = 'red', TEAM_RED, TEAM_BLUE), P[1], StrToIntDef(P[1], -1));
5253 end
5254 else if cmd = 'bot_removeall' then
5255 g_Bot_RemoveAll()
5256 else if cmd = 'chat' then
5257 begin
5258 if g_Game_IsNet then
5259 begin
5260 if Length(P) > 1 then
5261 begin
5262 for a := 1 to High(P) do
5263 chstr := chstr + P[a] + ' ';
5265 if Length(chstr) > 200 then SetLength(chstr, 200);
5267 if Length(chstr) < 1 then
5268 begin
5269 g_Console_Add('chat <text>');
5270 Exit;
5271 end;
5273 chstr := b_Text_Format(chstr);
5274 if g_Game_IsClient then
5275 MC_SEND_Chat(chstr, NET_CHAT_PLAYER)
5276 else
5277 MH_SEND_Chat(gPlayer1Settings.Name + ': ' + chstr, NET_CHAT_PLAYER);
5278 end
5279 else
5280 g_Console_Add('chat <text>');
5281 end else
5282 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5283 end
5284 else if cmd = 'teamchat' then
5285 begin
5286 if g_Game_IsNet and (gGameSettings.GameMode in [GM_TDM, GM_CTF]) then
5287 begin
5288 if Length(P) > 1 then
5289 begin
5290 for a := 1 to High(P) do
5291 chstr := chstr + P[a] + ' ';
5293 if Length(chstr) > 200 then SetLength(chstr, 200);
5295 if Length(chstr) < 1 then
5296 begin
5297 g_Console_Add('teamchat <text>');
5298 Exit;
5299 end;
5301 chstr := b_Text_Format(chstr);
5302 if g_Game_IsClient then
5303 MC_SEND_Chat(chstr, NET_CHAT_TEAM)
5304 else
5305 MH_SEND_Chat(gPlayer1Settings.Name + ': ' + chstr, NET_CHAT_TEAM,
5306 gPlayer1Settings.Team);
5307 end
5308 else
5309 g_Console_Add('teamchat <text>');
5310 end else
5311 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5312 end
5313 else if cmd = 'game' then
5314 begin
5315 if gGameSettings.GameType <> GT_NONE then
5316 begin
5317 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5318 Exit;
5319 end;
5320 if Length(P) = 1 then
5321 begin
5322 g_Console_Add(cmd + ' <WAD> [MAP] [# players]');
5323 Exit;
5324 end;
5325 // Èãðà åù¸ íå çàïóùåíà, ñíà÷àëà íàì íàäî çàãðóçèòü êàêîé-òî WAD
5326 P[1] := addWadExtension(P[1]);
5327 if FileExists(MapsDir + P[1]) then
5328 begin
5329 // Åñëè êàðòà íå óêàçàíà, áåð¸ì ïåðâóþ êàðòó â ôàéëå
5330 if Length(P) < 3 then
5331 begin
5332 SetLength(P, 3);
5333 P[2] := g_Game_GetFirstMap(MapsDir + P[1]);
5334 end;
5336 s := P[1] + ':\' + UpperCase(P[2]);
5338 if g_Map_Exist(MapsDir + s) then
5339 begin
5340 // Çàïóñêàåì ñâîþ èãðó
5341 g_Game_Free();
5342 with gGameSettings do
5343 begin
5344 GameMode := g_Game_TextToMode(gcGameMode);
5345 if gSwitchGameMode <> GM_NONE then
5346 GameMode := gSwitchGameMode;
5347 if GameMode = GM_NONE then GameMode := GM_DM;
5348 if GameMode = GM_SINGLE then GameMode := GM_COOP;
5349 b := 1;
5350 if Length(P) >= 4 then
5351 b := StrToIntDef(P[3], 1);
5352 g_Game_StartCustom(s, GameMode, TimeLimit,
5353 GoalLimit, MaxLives, Options, b);
5354 end;
5355 end
5356 else
5357 if P[2] = '' then
5358 g_Console_Add(Format(_lc[I_MSG_NO_MAPS], [P[1]]))
5359 else
5360 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [UpperCase(P[2])]));
5361 end else
5362 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[1]]));
5363 end
5364 else if cmd = 'host' then
5365 begin
5366 if gGameSettings.GameType <> GT_NONE then
5367 begin
5368 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5369 Exit;
5370 end;
5371 if Length(P) < 4 then
5372 begin
5373 g_Console_Add(cmd + ' <listen IP> <port> <WAD> [MAP] [# players]');
5374 Exit;
5375 end;
5376 if not StrToIp(P[1], listen) then
5377 Exit;
5378 prt := StrToIntDef(P[2], 25666);
5380 P[3] := addWadExtension(P[3]);
5381 if FileExists(MapsDir + P[3]) then
5382 begin
5383 // Åñëè êàðòà íå óêàçàíà, áåð¸ì ïåðâóþ êàðòó â ôàéëå
5384 if Length(P) < 5 then
5385 begin
5386 SetLength(P, 5);
5387 P[4] := g_Game_GetFirstMap(MapsDir + P[1]);
5388 end;
5390 s := P[3] + ':\' + UpperCase(P[4]);
5392 if g_Map_Exist(MapsDir + s) then
5393 begin
5394 // Çàïóñêàåì ñâîþ èãðó
5395 g_Game_Free();
5396 with gGameSettings do
5397 begin
5398 GameMode := g_Game_TextToMode(gcGameMode);
5399 if gSwitchGameMode <> GM_NONE then
5400 GameMode := gSwitchGameMode;
5401 if GameMode = GM_NONE then GameMode := GM_DM;
5402 if GameMode = GM_SINGLE then GameMode := GM_COOP;
5403 b := 0;
5404 if Length(P) >= 6 then
5405 b := StrToIntDef(P[5], 0);
5406 g_Game_StartServer(s, GameMode, TimeLimit,
5407 GoalLimit, MaxLives, Options, b, listen, prt);
5408 end;
5409 end
5410 else
5411 if P[4] = '' then
5412 g_Console_Add(Format(_lc[I_MSG_NO_MAPS], [P[3]]))
5413 else
5414 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [UpperCase(P[4])]));
5415 end else
5416 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[3]]));
5417 end
5418 else if cmd = 'map' then
5419 begin
5420 if Length(P) = 1 then
5421 begin
5422 if g_Game_IsServer and (gGameSettings.GameType <> GT_SINGLE) then
5423 begin
5424 g_Console_Add(cmd + ' <MAP>');
5425 g_Console_Add(cmd + ' <WAD> [MAP]');
5426 end else
5427 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5428 end else
5429 if g_Game_IsServer and (gGameSettings.GameType <> GT_SINGLE) then
5430 begin
5431 // Èä¸ò ñâîÿ èãðà èëè ñåðâåð
5432 if Length(P) < 3 then
5433 begin
5434 // Ïåðâûé ïàðàìåòð - ëèáî êàðòà, ëèáî èìÿ WAD ôàéëà
5435 s := UpperCase(P[1]);
5436 if g_Map_Exist(MapsDir + gGameSettings.WAD + ':\' + s) then
5437 begin // Êàðòà íàøëàñü
5438 gExitByTrigger := False;
5439 if gGameOn then
5440 begin // Èä¸ò èãðà - çàâåðøàåì óðîâåíü
5441 gNextMap := s;
5442 gExit := EXIT_ENDLEVELCUSTOM;
5443 end
5444 else // Èíòåðìèññèÿ - ñðàçó çàãðóæàåì êàðòó
5445 g_Game_ChangeMap(s);
5446 end else
5447 begin
5448 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [s]));
5449 // Òàêîé êàðòû íåò, èùåì WAD ôàéë
5450 P[1] := addWadExtension(P[1]);
5451 if FileExists(MapsDir + P[1]) then
5452 begin
5453 // Ïàðàìåòðà êàðòû íåò, ïîýòîìó ñòàâèì ïåðâóþ èç ôàéëà
5454 SetLength(P, 3);
5455 P[2] := g_Game_GetFirstMap(MapsDir + P[1]);
5457 s := P[1] + ':\' + P[2];
5459 if g_Map_Exist(MapsDir + s) then
5460 begin
5461 gExitByTrigger := False;
5462 if gGameOn then
5463 begin // Èä¸ò èãðà - çàâåðøàåì óðîâåíü
5464 gNextMap := s;
5465 gExit := EXIT_ENDLEVELCUSTOM;
5466 end
5467 else // Èíòåðìèññèÿ - ñðàçó çàãðóæàåì êàðòó
5468 g_Game_ChangeMap(s);
5469 end else
5470 if P[2] = '' then
5471 g_Console_Add(Format(_lc[I_MSG_NO_MAPS], [P[1]]))
5472 else
5473 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [P[2]]));
5474 end else
5475 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[1]]));
5476 end;
5477 end else
5478 begin
5479 // Óêàçàíî äâà ïàðàìåòðà, çíà÷èò ïåðâûé - WAD ôàéë, à âòîðîé - êàðòà
5480 P[1] := addWadExtension(P[1]);
5481 if FileExists(MapsDir + P[1]) then
5482 begin
5483 // Íàøëè WAD ôàéë
5484 P[2] := UpperCase(P[2]);
5485 s := P[1] + ':\' + P[2];
5487 if g_Map_Exist(MapsDir + s) then
5488 begin // Íàøëè êàðòó
5489 gExitByTrigger := False;
5490 if gGameOn then
5491 begin // Èä¸ò èãðà - çàâåðøàåì óðîâåíü
5492 gNextMap := s;
5493 gExit := EXIT_ENDLEVELCUSTOM;
5494 end
5495 else // Èíòåðìèññèÿ - ñðàçó çàãðóæàåì êàðòó
5496 g_Game_ChangeMap(s);
5497 end else
5498 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [P[2]]));
5499 end else
5500 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[1]]));
5501 end;
5502 end else
5503 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5504 end
5505 else if cmd = 'nextmap' then
5506 begin
5507 if not(gGameOn or (gState = STATE_INTERCUSTOM)) then
5508 g_Console_Add(_lc[I_MSG_NOT_GAME])
5509 else begin
5510 nm := True;
5511 if Length(P) = 1 then
5512 begin
5513 if g_Game_IsServer and (gGameSettings.GameType <> GT_SINGLE) then
5514 begin
5515 g_Console_Add(cmd + ' <MAP>');
5516 g_Console_Add(cmd + ' <WAD> [MAP]');
5517 end else begin
5518 nm := False;
5519 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5520 end;
5521 end else
5522 begin
5523 nm := False;
5524 if g_Game_IsServer and (gGameSettings.GameType <> GT_SINGLE) then
5525 begin
5526 if Length(P) < 3 then
5527 begin
5528 // Ïåðâûé ïàðàìåòð - ëèáî êàðòà, ëèáî èìÿ WAD ôàéëà
5529 s := UpperCase(P[1]);
5530 if g_Map_Exist(MapsDir + gGameSettings.WAD + ':\' + s) then
5531 begin // Êàðòà íàøëàñü
5532 gExitByTrigger := False;
5533 gNextMap := s;
5534 nm := True;
5535 end else
5536 begin
5537 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [s]));
5538 // Òàêîé êàðòû íåò, èùåì WAD ôàéë
5539 P[1] := addWadExtension(P[1]);
5540 if FileExists(MapsDir + P[1]) then
5541 begin
5542 // Ïàðàìåòðà êàðòû íåò, ïîýòîìó ñòàâèì ïåðâóþ èç ôàéëà
5543 SetLength(P, 3);
5544 P[2] := g_Game_GetFirstMap(MapsDir + P[1]);
5546 s := P[1] + ':\' + P[2];
5548 if g_Map_Exist(MapsDir + s) then
5549 begin // Óñòàíàâëèâàåì êàðòó
5550 gExitByTrigger := False;
5551 gNextMap := s;
5552 nm := True;
5553 end else
5554 if P[2] = '' then
5555 g_Console_Add(Format(_lc[I_MSG_NO_MAPS], [P[1]]))
5556 else
5557 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [P[2]]));
5558 end else
5559 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[1]]));
5560 end;
5561 end else
5562 begin
5563 // Óêàçàíî äâà ïàðàìåòðà, çíà÷èò ïåðâûé - WAD ôàéë, à âòîðîé - êàðòà
5564 P[1] := addWadExtension(P[1]);
5565 if FileExists(MapsDir + P[1]) then
5566 begin
5567 // Íàøëè WAD ôàéë
5568 P[2] := UpperCase(P[2]);
5569 s := P[1] + ':\' + P[2];
5571 if g_Map_Exist(MapsDir + s) then
5572 begin // Íàøëè êàðòó
5573 gExitByTrigger := False;
5574 gNextMap := s;
5575 nm := True;
5576 end else
5577 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [P[2]]));
5578 end else
5579 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[1]]));
5580 end;
5581 end else
5582 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5583 end;
5584 if nm then
5585 if gNextMap = '' then
5586 g_Console_Add(_lc[I_MSG_NEXTMAP_UNSET])
5587 else
5588 g_Console_Add(Format(_lc[I_MSG_NEXTMAP_SET], [gNextMap]));
5589 end;
5590 end
5591 else if (cmd = 'endmap') or (cmd = 'goodbye') then
5592 begin
5593 if not gGameOn then
5594 g_Console_Add(_lc[I_MSG_NOT_GAME])
5595 else
5596 if g_Game_IsServer and (gGameSettings.GameType <> GT_SINGLE) then
5597 begin
5598 gExitByTrigger := False;
5599 // Ñëåäóþùàÿ êàðòà íå çàäàíà, ïðîáóåì íàéòè òðèããåð Âûõîä
5600 if (gNextMap = '') and (gTriggers <> nil) then
5601 for a := 0 to High(gTriggers) do
5602 if gTriggers[a].TriggerType = TRIGGER_EXIT then
5603 begin
5604 gExitByTrigger := True;
5605 gNextMap := gTriggers[a].Data.MapName;
5606 Break;
5607 end;
5608 // Èùåì ñëåäóþùóþ êàðòó â WAD ôàéëå
5609 if gNextMap = '' then
5610 gNextMap := g_Game_GetNextMap();
5611 // Ïðîâåðÿåì, íå çàäàí ëè WAD ôàéë ðåñóðñíîé ñòðîêîé
5612 if Pos(':\', gNextMap) = 0 then
5613 s := gGameSettings.WAD + ':\' + gNextMap
5614 else
5615 s := gNextMap;
5616 // Åñëè êàðòà íàéäåíà, âûõîäèì ñ óðîâíÿ
5617 if g_Map_Exist(MapsDir + s) then
5618 gExit := EXIT_ENDLEVELCUSTOM
5619 else
5620 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [gNextMap]));
5621 end else
5622 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5623 end
5624 else if (cmd = 'event') then
5625 begin
5626 if (Length(P) <= 1) then
5627 begin
5628 for a := 0 to High(gEvents) do
5629 if gEvents[a].Command = '' then
5630 g_Console_Add(gEvents[a].Name + ' <none>')
5631 else
5632 g_Console_Add(gEvents[a].Name + ' "' + gEvents[a].Command + '"');
5633 Exit;
5634 end;
5635 if (Length(P) = 2) then
5636 begin
5637 for a := 0 to High(gEvents) do
5638 if gEvents[a].Name = P[1] then
5639 if gEvents[a].Command = '' then
5640 g_Console_Add(gEvents[a].Name + ' <none>')
5641 else
5642 g_Console_Add(gEvents[a].Name + ' "' + gEvents[a].Command + '"');
5643 Exit;
5644 end;
5645 for a := 0 to High(gEvents) do
5646 if gEvents[a].Name = P[1] then
5647 begin
5648 gEvents[a].Command := '';
5649 for b := 2 to High(P) do
5650 if Pos(' ', P[b]) = 0 then
5651 gEvents[a].Command := gEvents[a].Command + ' ' + P[b]
5652 else
5653 gEvents[a].Command := gEvents[a].Command + ' "' + P[b] + '"';
5654 gEvents[a].Command := Trim(gEvents[a].Command);
5655 Exit;
5656 end;
5657 end
5658 // Êîìàíäû Ñâîåé èãðû:
5659 else if gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT] then
5660 begin
5661 if cmd = 'bot_addred' then
5662 begin
5663 if Length(P) > 1 then
5664 g_Bot_Add(TEAM_RED, StrToIntDef(P[1], 2))
5665 else
5666 g_Bot_Add(TEAM_RED, 2);
5667 end
5668 else if cmd = 'bot_addblue' then
5669 begin
5670 if Length(P) > 1 then
5671 g_Bot_Add(TEAM_BLUE, StrToIntDef(P[1], 2))
5672 else
5673 g_Bot_Add(TEAM_BLUE, 2);
5674 end
5675 else if cmd = 'suicide' then
5676 begin
5677 if gGameOn then
5678 begin
5679 if g_Game_IsClient then
5680 MC_SEND_CheatRequest(NET_CHEAT_SUICIDE)
5681 else
5682 begin
5683 if gPlayer1 <> nil then
5684 gPlayer1.Damage(SUICIDE_DAMAGE, gPlayer1.UID, 0, 0, HIT_SELF);
5685 if gPlayer2 <> nil then
5686 gPlayer2.Damage(SUICIDE_DAMAGE, gPlayer2.UID, 0, 0, HIT_SELF);
5687 end;
5688 end;
5689 end
5690 else if cmd = 'spectate' then
5691 begin
5692 if not gGameOn then
5693 Exit;
5694 g_Game_Spectate();
5695 end
5696 else if cmd = 'say' then
5697 begin
5698 if g_Game_IsServer and g_Game_IsNet then
5699 begin
5700 if Length(P) > 1 then
5701 begin
5702 chstr := '';
5703 for a := 1 to High(P) do
5704 chstr := chstr + P[a] + ' ';
5706 if Length(chstr) > 200 then SetLength(chstr, 200);
5708 if Length(chstr) < 1 then
5709 begin
5710 g_Console_Add('say <text>');
5711 Exit;
5712 end;
5714 chstr := b_Text_Format(chstr);
5715 MH_SEND_Chat(chstr, NET_CHAT_PLAYER);
5716 end
5717 else g_Console_Add('say <text>');
5718 end else
5719 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5720 end
5721 else if cmd = 'tell' then
5722 begin
5723 if g_Game_IsServer and g_Game_IsNet then
5724 begin
5725 if (Length(P) > 2) and (P[1] <> '') then
5726 begin
5727 chstr := '';
5728 for a := 2 to High(P) do
5729 chstr := chstr + P[a] + ' ';
5731 if Length(chstr) > 200 then SetLength(chstr, 200);
5733 if Length(chstr) < 1 then
5734 begin
5735 g_Console_Add('tell <playername> <text>');
5736 Exit;
5737 end;
5739 pl := g_Net_Client_ByName(P[1]);
5740 if pl <> nil then
5741 MH_SEND_Chat(b_Text_Format(chstr), NET_CHAT_PLAYER, pl^.ID)
5742 else
5743 g_Console_Add(Format(_lc[I_NET_ERR_NAME404], [P[1]]));
5744 end
5745 else g_Console_Add('tell <playername> <text>');
5746 end else
5747 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5748 end
5749 else if (cmd = 'overtime') and not g_Game_IsClient then
5750 begin
5751 if (Length(P) = 1) or (StrToIntDef(P[1], -1) <= 0) then
5752 Exit;
5753 // Äîïîëíèòåëüíîå âðåìÿ:
5754 gGameSettings.TimeLimit := (gTime - gGameStartTime) div 1000 + Word(StrToIntDef(P[1], 0));
5756 g_Console_Add(Format(_lc[I_MSG_TIME_LIMIT],
5757 [gGameSettings.TimeLimit div 3600,
5758 (gGameSettings.TimeLimit div 60) mod 60,
5759 gGameSettings.TimeLimit mod 60]));
5760 if g_Game_IsNet then MH_SEND_GameSettings;
5761 end
5762 else if (cmd = 'rcon_password') and g_Game_IsClient then
5763 begin
5764 if (Length(P) <= 1) then
5765 g_Console_Add('rcon_password <password>')
5766 else
5767 MC_SEND_RCONPassword(P[1]);
5768 end
5769 else if cmd = 'rcon' then
5770 begin
5771 if g_Game_IsClient then
5772 begin
5773 if Length(P) > 1 then
5774 begin
5775 chstr := '';
5776 for a := 1 to High(P) do
5777 chstr := chstr + P[a] + ' ';
5779 if Length(chstr) > 200 then SetLength(chstr, 200);
5781 if Length(chstr) < 1 then
5782 begin
5783 g_Console_Add('rcon <command>');
5784 Exit;
5785 end;
5787 MC_SEND_RCONCommand(chstr);
5788 end
5789 else g_Console_Add('rcon <command>');
5790 end;
5791 end
5792 else if cmd = 'ready' then
5793 begin
5794 if g_Game_IsServer and (gLMSRespawn = LMS_RESPAWN_WARMUP) then
5795 gLMSRespawnTime := gTime + 100;
5796 end
5797 else if (cmd = 'callvote') and g_Game_IsNet then
5798 begin
5799 if Length(P) > 1 then
5800 begin
5801 chstr := '';
5802 for a := 1 to High(P) do begin
5803 if a > 1 then chstr := chstr + ' ';
5804 chstr := chstr + P[a];
5805 end;
5807 if Length(chstr) > 200 then SetLength(chstr, 200);
5809 if Length(chstr) < 1 then
5810 begin
5811 g_Console_Add('callvote <command>');
5812 Exit;
5813 end;
5815 if g_Game_IsClient then
5816 MC_SEND_Vote(True, chstr)
5817 else
5818 g_Game_StartVote(chstr, gPlayer1Settings.Name);
5819 g_Console_Process('vote', True);
5820 end
5821 else
5822 g_Console_Add('callvote <command>');
5823 end
5824 else if (cmd = 'vote') and g_Game_IsNet then
5825 begin
5826 if g_Game_IsClient then
5827 MC_SEND_Vote(False)
5828 else if gVoteInProgress then
5829 begin
5830 if (gPlayer1 <> nil) or (gPlayer2 <> nil) then
5831 a := Floor((NetClientCount+1)/2.0) + 1
5832 else
5833 a := Floor(NetClientCount/2.0) + 1;
5834 if gVoted then
5835 begin
5836 Dec(gVoteCount);
5837 gVoted := False;
5838 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_REVOKED], [gPlayer1Settings.Name, gVoteCount, a]), True);
5839 MH_SEND_VoteEvent(NET_VE_REVOKE, gPlayer1Settings.Name, 'a', gVoteCount, a);
5840 end
5841 else
5842 begin
5843 Inc(gVoteCount);
5844 gVoted := True;
5845 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_VOTE], [gPlayer1Settings.Name, gVoteCount, a]), True);
5846 MH_SEND_VoteEvent(NET_VE_VOTE, gPlayer1Settings.Name, 'a', gVoteCount, a);
5847 g_Game_CheckVote;
5848 end;
5849 end;
5850 end
5851 end;
5852 end;
5854 procedure g_TakeScreenShot();
5855 var
5856 a: Word;
5857 FileName: string;
5858 ssdir, t: string;
5859 st: TStream;
5860 ok: Boolean;
5861 begin
5862 if e_NoGraphics then Exit;
5863 ssdir := GameDir+'/screenshots';
5864 if not findFileCI(ssdir, true) then
5865 begin
5866 // try to create dir
5867 try
5868 CreateDir(ssdir);
5869 except
5870 end;
5871 if not findFileCI(ssdir, true) then exit; // alas
5872 end;
5873 try
5874 for a := 1 to High(Word) do
5875 begin
5876 FileName := Format(ssdir+'screenshot%.3d.png', [a]);
5877 t := FileName;
5878 if findFileCI(t, true) then continue;
5879 if not findFileCI(FileName) then
5880 begin
5881 ok := false;
5882 st := createDiskFile(FileName);
5883 try
5884 e_MakeScreenshot(st, gScreenWidth, gScreenHeight);
5885 ok := true;
5886 finally
5887 st.Free();
5888 end;
5889 if not ok then try DeleteFile(FileName); except end else g_Console_Add(Format(_lc[I_CONSOLE_SCREENSHOT], [ExtractFileName(FileName)]));
5890 break;
5891 end;
5892 end;
5893 except
5894 end;
5895 end;
5897 procedure g_Game_InGameMenu(Show: Boolean);
5898 begin
5899 if (g_ActiveWindow = nil) and Show then
5900 begin
5901 if gGameSettings.GameType = GT_SINGLE then
5902 g_GUI_ShowWindow('GameSingleMenu')
5903 else
5904 begin
5905 if g_Game_IsClient then
5906 g_GUI_ShowWindow('GameClientMenu')
5907 else
5908 if g_Game_IsNet then
5909 g_GUI_ShowWindow('GameServerMenu')
5910 else
5911 g_GUI_ShowWindow('GameCustomMenu');
5912 end;
5913 g_Sound_PlayEx('MENU_OPEN');
5915 // Ïàóçà ïðè ìåíþ òîëüêî â îäèíî÷íîé èãðå:
5916 if (not g_Game_IsNet) then
5917 g_Game_Pause(True);
5918 end
5919 else
5920 if (g_ActiveWindow <> nil) and (not Show) then
5921 begin
5922 // Ïàóçà ïðè ìåíþ òîëüêî â îäèíî÷íîé èãðå:
5923 if (not g_Game_IsNet) then
5924 g_Game_Pause(False);
5925 end;
5926 end;
5928 procedure g_Game_Pause(Enable: Boolean);
5929 begin
5930 if not gGameOn then
5931 Exit;
5933 if gPause = Enable then
5934 Exit;
5936 if not (gGameSettings.GameType in [GT_SINGLE, GT_CUSTOM]) then
5937 Exit;
5939 gPause := Enable;
5940 g_Game_PauseAllSounds(Enable);
5941 end;
5943 procedure g_Game_PauseAllSounds(Enable: Boolean);
5944 var
5945 i: Integer;
5946 begin
5947 // Òðèããåðû:
5948 if gTriggers <> nil then
5949 for i := 0 to High(gTriggers) do
5950 with gTriggers[i] do
5951 if (TriggerType = TRIGGER_SOUND) and
5952 (Sound <> nil) and
5953 Sound.IsPlaying() then
5954 begin
5955 Sound.Pause(Enable);
5956 end;
5958 // Çâóêè èãðîêîâ:
5959 if gPlayers <> nil then
5960 for i := 0 to High(gPlayers) do
5961 if gPlayers[i] <> nil then
5962 gPlayers[i].PauseSounds(Enable);
5964 // Ìóçûêà:
5965 if gMusic <> nil then
5966 gMusic.Pause(Enable);
5967 end;
5969 procedure g_Game_StopAllSounds(all: Boolean);
5970 var
5971 i: Integer;
5972 begin
5973 if gTriggers <> nil then
5974 for i := 0 to High(gTriggers) do
5975 with gTriggers[i] do
5976 if (TriggerType = TRIGGER_SOUND) and
5977 (Sound <> nil) then
5978 Sound.Stop();
5980 if gMusic <> nil then
5981 gMusic.Stop();
5983 if all then
5984 e_StopChannels();
5985 end;
5987 procedure g_Game_UpdateTriggerSounds();
5988 var
5989 i: Integer;
5990 begin
5991 if gTriggers <> nil then
5992 for i := 0 to High(gTriggers) do
5993 with gTriggers[i] do
5994 if (TriggerType = TRIGGER_SOUND) and
5995 (Sound <> nil) and
5996 (Data.Local) and
5997 Sound.IsPlaying() then
5998 begin
5999 if ((gPlayer1 <> nil) and g_CollidePoint(gPlayer1.GameX, gPlayer1.GameY, X, Y, Width, Height)) or
6000 ((gPlayer2 <> nil) and g_CollidePoint(gPlayer2.GameX, gPlayer2.GameY, X, Y, Width, Height)) then
6001 begin
6002 Sound.SetPan(0.5 - Data.Pan/255.0);
6003 Sound.SetVolume(Data.Volume/255.0);
6004 end
6005 else
6006 Sound.SetCoords(X+(Width div 2), Y+(Height div 2), Data.Volume/255.0);
6007 end;
6008 end;
6010 function g_Game_IsWatchedPlayer(UID: Word): Boolean;
6011 begin
6012 Result := False;
6013 if (gPlayer1 <> nil) and (gPlayer1.UID = UID) then
6014 begin
6015 Result := True;
6016 Exit;
6017 end;
6018 if (gPlayer2 <> nil) and (gPlayer2.UID = UID) then
6019 begin
6020 Result := True;
6021 Exit;
6022 end;
6023 if gSpectMode <> SPECT_PLAYERS then
6024 Exit;
6025 if gSpectPID1 = UID then
6026 begin
6027 Result := True;
6028 Exit;
6029 end;
6030 if gSpectViewTwo and (gSpectPID2 = UID) then
6031 begin
6032 Result := True;
6033 Exit;
6034 end;
6035 end;
6037 function g_Game_IsWatchedTeam(Team: Byte): Boolean;
6038 var
6039 Pl: TPlayer;
6040 begin
6041 Result := False;
6042 if (gPlayer1 <> nil) and (gPlayer1.Team = Team) then
6043 begin
6044 Result := True;
6045 Exit;
6046 end;
6047 if (gPlayer2 <> nil) and (gPlayer2.Team = Team) then
6048 begin
6049 Result := True;
6050 Exit;
6051 end;
6052 if gSpectMode <> SPECT_PLAYERS then
6053 Exit;
6054 Pl := g_Player_Get(gSpectPID1);
6055 if (Pl <> nil) and (Pl.Team = Team) then
6056 begin
6057 Result := True;
6058 Exit;
6059 end;
6060 if gSpectViewTwo then
6061 begin
6062 Pl := g_Player_Get(gSpectPID2);
6063 if (Pl <> nil) and (Pl.Team = Team) then
6064 begin
6065 Result := True;
6066 Exit;
6067 end;
6068 end;
6069 end;
6071 procedure g_Game_Message(Msg: string; Time: Word);
6072 begin
6073 MessageText := b_Text_Format(Msg);
6074 MessageTime := Time;
6075 end;
6077 procedure g_Game_Announce_GoodShot(SpawnerUID: Word);
6078 var
6079 a: Integer;
6080 begin
6081 case gAnnouncer of
6082 ANNOUNCE_NONE:
6083 Exit;
6084 ANNOUNCE_ME,
6085 ANNOUNCE_MEPLUS:
6086 if not g_Game_IsWatchedPlayer(SpawnerUID) then
6087 Exit;
6088 end;
6089 for a := 0 to 3 do
6090 if goodsnd[a].IsPlaying() then
6091 Exit;
6093 goodsnd[Random(4)].Play();
6094 end;
6096 procedure g_Game_Announce_KillCombo(Param: Integer);
6097 var
6098 UID: Word;
6099 c, n: Byte;
6100 Pl: TPlayer;
6101 Name: String;
6102 begin
6103 UID := Param and $FFFF;
6104 c := Param shr 16;
6105 if c < 2 then
6106 Exit;
6108 Pl := g_Player_Get(UID);
6109 if Pl = nil then
6110 Name := '?'
6111 else
6112 Name := Pl.Name;
6114 case c of
6115 2: begin
6116 n := 0;
6117 g_Console_Add(Format(_lc[I_PLAYER_KILL_2X], [Name]), True);
6118 end;
6119 3: begin
6120 n := 1;
6121 g_Console_Add(Format(_lc[I_PLAYER_KILL_3X], [Name]), True);
6122 end;
6123 4: begin
6124 n := 2;
6125 g_Console_Add(Format(_lc[I_PLAYER_KILL_4X], [Name]), True);
6126 end;
6127 else begin
6128 n := 3;
6129 g_Console_Add(Format(_lc[I_PLAYER_KILL_MX], [Name]), True);
6130 end;
6131 end;
6133 case gAnnouncer of
6134 ANNOUNCE_NONE:
6135 Exit;
6136 ANNOUNCE_ME:
6137 if not g_Game_IsWatchedPlayer(UID) then
6138 Exit;
6139 ANNOUNCE_MEPLUS:
6140 if (not g_Game_IsWatchedPlayer(UID)) and (c < 4) then
6141 Exit;
6142 end;
6144 if killsnd[n].IsPlaying() then
6145 killsnd[n].Stop();
6146 killsnd[n].Play();
6147 end;
6149 procedure g_Game_StartVote(Command, Initiator: string);
6150 var
6151 Need: Integer;
6152 begin
6153 if not gVotesEnabled then Exit;
6154 if gGameSettings.GameType <> GT_SERVER then Exit;
6155 if gVoteInProgress or gVotePassed then
6156 begin
6157 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_INPROGRESS], [gVoteCommand]), True);
6158 MH_SEND_VoteEvent(NET_VE_INPROGRESS, gVoteCommand);
6159 Exit;
6160 end;
6161 gVoteInProgress := True;
6162 gVotePassed := False;
6163 gVoteTimer := gTime + gVoteTimeout * 1000;
6164 gVoteCount := 0;
6165 gVoted := False;
6166 gVoteCommand := Command;
6168 if (gPlayer1 <> nil) or (gPlayer2 <> nil) then
6169 Need := Floor((NetClientCount+1)/2.0)+1
6170 else
6171 Need := Floor(NetClientCount/2.0)+1;
6172 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_STARTED], [Initiator, Command, Need]), True);
6173 MH_SEND_VoteEvent(NET_VE_STARTED, Initiator, Command, Need);
6174 end;
6176 procedure g_Game_CheckVote;
6177 var
6178 I, Need: Integer;
6179 begin
6180 if gGameSettings.GameType <> GT_SERVER then Exit;
6181 if not gVoteInProgress then Exit;
6183 if (gTime >= gVoteTimer) then
6184 begin
6185 if (gPlayer1 <> nil) or (gPlayer2 <> nil) then
6186 Need := Floor((NetClientCount+1)/2.0) + 1
6187 else
6188 Need := Floor(NetClientCount/2.0) + 1;
6189 if gVoteCount >= Need then
6190 begin
6191 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_PASSED], [gVoteCommand]), True);
6192 MH_SEND_VoteEvent(NET_VE_PASSED, gVoteCommand);
6193 gVotePassed := True;
6194 gVoteCmdTimer := gTime + 5000;
6195 end
6196 else
6197 begin
6198 g_Console_Add(_lc[I_MESSAGE_VOTE_FAILED], True);
6199 MH_SEND_VoteEvent(NET_VE_FAILED);
6200 end;
6201 if NetClients <> nil then
6202 for I := Low(NetClients) to High(NetClients) do
6203 if NetClients[i].Used then
6204 NetClients[i].Voted := False;
6205 gVoteInProgress := False;
6206 gVoted := False;
6207 gVoteCount := 0;
6208 end
6209 else
6210 begin
6211 if (gPlayer1 <> nil) or (gPlayer2 <> nil) then
6212 Need := Floor((NetClientCount+1)/2.0) + 1
6213 else
6214 Need := Floor(NetClientCount/2.0) + 1;
6215 if gVoteCount >= Need then
6216 begin
6217 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_PASSED], [gVoteCommand]), True);
6218 MH_SEND_VoteEvent(NET_VE_PASSED, gVoteCommand);
6219 gVoteInProgress := False;
6220 gVotePassed := True;
6221 gVoteCmdTimer := gTime + 5000;
6222 gVoted := False;
6223 gVoteCount := 0;
6224 if NetClients <> nil then
6225 for I := Low(NetClients) to High(NetClients) do
6226 if NetClients[i].Used then
6227 NetClients[i].Voted := False;
6228 end;
6229 end;
6230 end;
6232 procedure g_Game_LoadMapList(FileName: string);
6233 var
6234 ListFile: TextFile;
6235 s: string;
6236 begin
6237 MapList := nil;
6238 MapIndex := -1;
6240 if not FileExists(FileName) then Exit;
6242 AssignFile(ListFile, FileName);
6243 Reset(ListFile);
6244 while not EOF(ListFile) do
6245 begin
6246 ReadLn(ListFile, s);
6248 s := Trim(s);
6249 if s = '' then Continue;
6251 SetLength(MapList, Length(MapList)+1);
6252 MapList[High(MapList)] := s;
6253 end;
6254 CloseFile(ListFile);
6255 end;
6257 procedure g_Game_SetDebugMode();
6258 begin
6259 gDebugMode := True;
6260 // ×èòû (äàæå â ñâîåé èãðå):
6261 gCheats := True;
6262 end;
6264 procedure g_Game_SetLoadingText(Text: String; Max: Integer; reWrite: Boolean);
6265 var
6266 i: Word;
6267 begin
6268 if Length(LoadingStat.Msgs) = 0 then
6269 Exit;
6271 with LoadingStat do
6272 begin
6273 if not reWrite then
6274 begin // Ïåðåõîäèì íà ñëåäóþùóþ ñòðîêó èëè ñêðîëëèðóåì:
6275 if NextMsg = Length(Msgs) then
6276 begin // scroll
6277 for i := 0 to High(Msgs)-1 do
6278 Msgs[i] := Msgs[i+1];
6279 end
6280 else
6281 Inc(NextMsg);
6282 end else
6283 if NextMsg = 0 then
6284 Inc(NextMsg);
6286 Msgs[NextMsg-1] := Text;
6287 CurValue := 0;
6288 MaxValue := Max;
6289 ShowCount := 0;
6290 end;
6292 g_ActiveWindow := nil;
6294 ProcessLoading;
6295 end;
6297 procedure g_Game_StepLoading();
6298 begin
6299 with LoadingStat do
6300 begin
6301 Inc(CurValue);
6302 Inc(ShowCount);
6303 if (ShowCount > LOADING_SHOW_STEP) then
6304 begin
6305 ShowCount := 0;
6306 ProcessLoading;
6307 end;
6308 end;
6309 end;
6311 procedure g_Game_ClearLoading();
6312 var
6313 len: Word;
6314 begin
6315 with LoadingStat do
6316 begin
6317 CurValue := 0;
6318 MaxValue := 0;
6319 ShowCount := 0;
6320 len := ((gScreenHeight div 3)*2 - 50) div LOADING_INTERLINE;
6321 if len < 1 then len := 1;
6322 SetLength(Msgs, len);
6323 for len := Low(Msgs) to High(Msgs) do
6324 Msgs[len] := '';
6325 NextMsg := 0;
6326 end;
6327 end;
6329 procedure Parse_Params(var pars: TParamStrValues);
6330 var
6331 i: Integer;
6332 s: String;
6333 begin
6334 SetLength(pars, 0);
6335 i := 1;
6336 while i <= ParamCount do
6337 begin
6338 s := ParamStr(i);
6339 if (s[1] = '-') and (Length(s) > 1) then
6340 begin
6341 if (s[2] = '-') and (Length(s) > 2) then
6342 begin // Îäèíî÷íûé ïàðàìåòð
6343 SetLength(pars, Length(pars) + 1);
6344 with pars[High(pars)] do
6345 begin
6346 Name := LowerCase(s);
6347 Value := '+';
6348 end;
6349 end
6350 else
6351 if (i < ParamCount) then
6352 begin // Ïàðàìåòð ñî çíà÷åíèåì
6353 Inc(i);
6354 SetLength(pars, Length(pars) + 1);
6355 with pars[High(pars)] do
6356 begin
6357 Name := LowerCase(s);
6358 Value := LowerCase(ParamStr(i));
6359 end;
6360 end;
6361 end;
6363 Inc(i);
6364 end;
6365 end;
6367 function Find_Param_Value(var pars: TParamStrValues; aName: String): String;
6368 var
6369 i: Integer;
6370 begin
6371 Result := '';
6372 for i := 0 to High(pars) do
6373 if pars[i].Name = aName then
6374 begin
6375 Result := pars[i].Value;
6376 Break;
6377 end;
6378 end;
6380 procedure g_Game_Process_Params();
6381 var
6382 pars: TParamStrValues;
6383 map: String;
6384 GMode, n: Byte;
6385 LimT, LimS: Integer;
6386 Opt: LongWord;
6387 Lives: Integer;
6388 s: String;
6389 Port: Integer;
6390 ip: String;
6391 F: TextFile;
6392 begin
6393 Parse_Params(pars);
6395 // Debug mode:
6396 s := Find_Param_Value(pars, '--debug');
6397 if (s <> '') then
6398 g_Game_SetDebugMode();
6400 // Connect when game loads
6401 ip := Find_Param_Value(pars, '-connect');
6403 if ip <> '' then
6404 begin
6405 s := Find_Param_Value(pars, '-port');
6406 if (s = '') or not TryStrToInt(s, Port) then
6407 Port := 25666;
6409 s := Find_Param_Value(pars, '-pw');
6411 g_Game_StartClient(ip, Port, s);
6412 Exit;
6413 end;
6415 // Start map when game loads:
6416 map := LowerCase(Find_Param_Value(pars, '-map'));
6417 if isWadPath(map) then
6418 begin
6419 // Game mode:
6420 s := Find_Param_Value(pars, '-gm');
6421 GMode := g_Game_TextToMode(s);
6422 if GMode = GM_NONE then GMode := GM_DM;
6423 if GMode = GM_SINGLE then GMode := GM_COOP;
6425 // Time limit:
6426 s := Find_Param_Value(pars, '-limt');
6427 if (s = '') or (not TryStrToInt(s, LimT)) then
6428 LimT := 0;
6429 if LimT < 0 then
6430 LimT := 0;
6432 // Goal limit:
6433 s := Find_Param_Value(pars, '-lims');
6434 if (s = '') or (not TryStrToInt(s, LimS)) then
6435 LimS := 0;
6436 if LimS < 0 then
6437 LimS := 0;
6439 // Lives limit:
6440 s := Find_Param_Value(pars, '-lives');
6441 if (s = '') or (not TryStrToInt(s, Lives)) then
6442 Lives := 0;
6443 if Lives < 0 then
6444 Lives := 0;
6446 // Options:
6447 s := Find_Param_Value(pars, '-opt');
6448 if (s = '') then
6449 Opt := GAME_OPTION_ALLOWEXIT or GAME_OPTION_BOTVSPLAYER or GAME_OPTION_BOTVSMONSTER
6450 else
6451 Opt := StrToIntDef(s, 0);
6452 if Opt = 0 then
6453 Opt := GAME_OPTION_ALLOWEXIT or GAME_OPTION_BOTVSPLAYER or GAME_OPTION_BOTVSMONSTER;
6455 // Close after map:
6456 s := Find_Param_Value(pars, '--close');
6457 if (s <> '') then
6458 gMapOnce := True;
6460 // Delete test map after play:
6461 s := Find_Param_Value(pars, '--testdelete');
6462 if (s <> '') then
6463 begin
6464 gMapToDelete := MapsDir + map;
6465 e_WriteLog('"--testdelete" is deprecated, use --tempdelete.', MSG_FATALERROR);
6466 Halt(1);
6467 end;
6469 // Delete temporary WAD after play:
6470 s := Find_Param_Value(pars, '--tempdelete');
6471 if (s <> '') then
6472 begin
6473 gMapToDelete := MapsDir + map;
6474 gTempDelete := True;
6475 end;
6477 // Number of players:
6478 s := Find_Param_Value(pars, '-pl');
6479 if (s = '') then
6480 n := 1
6481 else
6482 n := StrToIntDef(s, 1);
6484 // Start:
6485 s := Find_Param_Value(pars, '-port');
6486 if (s = '') or not TryStrToInt(s, Port) then
6487 g_Game_StartCustom(map, GMode, LimT, LimS, Lives, Opt, n)
6488 else
6489 g_Game_StartServer(map, GMode, LimT, LimS, Lives, Opt, n, 0, Port);
6490 end;
6492 // Execute script when game loads:
6493 s := Find_Param_Value(pars, '-exec');
6494 if s <> '' then
6495 begin
6496 if Pos(':\', s) = 0 then
6497 s := GameDir + '/' + s;
6499 {$I-}
6500 AssignFile(F, s);
6501 Reset(F);
6502 if IOResult <> 0 then
6503 begin
6504 e_WriteLog(Format(_lc[I_SIMPLE_ERROR], ['Failed to read file: ' + s]), MSG_WARNING);
6505 g_Console_Add(Format(_lc[I_CONSOLE_ERROR_READ], [s]));
6506 CloseFile(F);
6507 Exit;
6508 end;
6509 e_WriteLog('Executing script: ' + s, MSG_NOTIFY);
6510 g_Console_Add(Format(_lc[I_CONSOLE_EXEC], [s]));
6512 while not EOF(F) do
6513 begin
6514 ReadLn(F, s);
6515 if IOResult <> 0 then
6516 begin
6517 e_WriteLog(Format(_lc[I_SIMPLE_ERROR], ['Failed to read file: ' + s]), MSG_WARNING);
6518 g_Console_Add(Format(_lc[I_CONSOLE_ERROR_READ], [s]));
6519 CloseFile(F);
6520 Exit;
6521 end;
6522 if Pos('#', s) <> 1 then // script comment
6523 g_Console_Process(s, True);
6524 end;
6526 CloseFile(F);
6527 {$I+}
6528 end;
6530 SetLength(pars, 0);
6531 end;
6533 end.