DEADSOFTWARE

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