DEADSOFTWARE

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