DEADSOFTWARE

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