DEADSOFTWARE

even more shit in "give"
[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 if gPlayer1 <> nil then gPlayer1.RealizeCurrentWeapon();
1538 if gPlayer2 <> nil then gPlayer2.RealizeCurrentWeapon();
1539 end; // if server
1541 // Íàáëþäàòåëü
1542 if (gPlayer1 = nil) and (gPlayer2 = nil) and
1543 (not gConsoleShow) and (not gChatShow) and (g_ActiveWindow = nil) then
1544 begin
1545 if not gSpectKeyPress then
1546 begin
1547 if isKeyPressed(gGameControls.P1Control.KeyJump, gGameControls.P1Control.KeyJump2) then
1548 begin
1549 // switch spect mode
1550 case gSpectMode of
1551 SPECT_NONE: ; // not spectator
1552 SPECT_STATS,
1553 SPECT_MAPVIEW: Inc(gSpectMode);
1554 SPECT_PLAYERS: gSpectMode := SPECT_STATS; // reset to 1
1555 end;
1556 gSpectKeyPress := True;
1557 end;
1558 if gSpectMode = SPECT_MAPVIEW then
1559 begin
1560 if isKeyPressed(gGameControls.P1Control.KeyLeft, gGameControls.P1Control.KeyLeft2) then
1561 gSpectX := Max(gSpectX - gSpectStep, 0);
1562 if isKeyPressed(gGameControls.P1Control.KeyRight, gGameControls.P1Control.KeyRight2) then
1563 gSpectX := Min(gSpectX + gSpectStep, gMapInfo.Width - gScreenWidth);
1564 if isKeyPressed(gGameControls.P1Control.KeyUp, gGameControls.P1Control.KeyUp2) then
1565 gSpectY := Max(gSpectY - gSpectStep, 0);
1566 if isKeyPressed(gGameControls.P1Control.KeyDown, gGameControls.P1Control.KeyDown2) then
1567 gSpectY := Min(gSpectY + gSpectStep, gMapInfo.Height - gScreenHeight);
1568 if isKeyPressed(gGameControls.P1Control.KeyPrevWeapon, gGameControls.P1Control.KeyPrevWeapon2) then
1569 begin
1570 // decrease step
1571 if gSpectStep > 4 then gSpectStep := gSpectStep shr 1;
1572 gSpectKeyPress := True;
1573 end;
1574 if isKeyPressed(gGameControls.P1Control.KeyNextWeapon, gGameControls.P1Control.KeyNextWeapon2) then
1575 begin
1576 // increase step
1577 if gSpectStep < 64 then gSpectStep := gSpectStep shl 1;
1578 gSpectKeyPress := True;
1579 end;
1580 end;
1581 if gSpectMode = SPECT_PLAYERS then
1582 begin
1583 if isKeyPressed(gGameControls.P1Control.KeyUp, gGameControls.P1Control.KeyUp2) then
1584 begin
1585 // add second view
1586 gSpectViewTwo := True;
1587 gSpectKeyPress := True;
1588 end;
1589 if isKeyPressed(gGameControls.P1Control.KeyDown, gGameControls.P1Control.KeyDown2) then
1590 begin
1591 // remove second view
1592 gSpectViewTwo := False;
1593 gSpectKeyPress := True;
1594 end;
1595 if isKeyPressed(gGameControls.P1Control.KeyLeft, gGameControls.P1Control.KeyLeft2) then
1596 begin
1597 // prev player (view 1)
1598 gSpectPID1 := GetActivePlayerID_Prev(gSpectPID1);
1599 gSpectKeyPress := True;
1600 end;
1601 if isKeyPressed(gGameControls.P1Control.KeyRight, gGameControls.P1Control.KeyRight2) then
1602 begin
1603 // next player (view 1)
1604 gSpectPID1 := GetActivePlayerID_Next(gSpectPID1);
1605 gSpectKeyPress := True;
1606 end;
1607 if isKeyPressed(gGameControls.P1Control.KeyPrevWeapon, gGameControls.P1Control.KeyPrevWeapon2) then
1608 begin
1609 // prev player (view 2)
1610 gSpectPID2 := GetActivePlayerID_Prev(gSpectPID2);
1611 gSpectKeyPress := True;
1612 end;
1613 if isKeyPressed(gGameControls.P1Control.KeyNextWeapon, gGameControls.P1Control.KeyNextWeapon2) then
1614 begin
1615 // next player (view 2)
1616 gSpectPID2 := GetActivePlayerID_Next(gSpectPID2);
1617 gSpectKeyPress := True;
1618 end;
1619 end;
1620 end
1621 else
1622 if (not isKeyPressed(gGameControls.P1Control.KeyJump, gGameControls.P1Control.KeyJump2)) and
1623 (not isKeyPressed(gGameControls.P1Control.KeyLeft, gGameControls.P1Control.KeyLeft2)) and
1624 (not isKeyPressed(gGameControls.P1Control.KeyRight, gGameControls.P1Control.KeyRight2)) and
1625 (not isKeyPressed(gGameControls.P1Control.KeyUp, gGameControls.P1Control.KeyUp2)) and
1626 (not isKeyPressed(gGameControls.P1Control.KeyDown, gGameControls.P1Control.KeyDown2)) and
1627 (not isKeyPressed(gGameControls.P1Control.KeyPrevWeapon, gGameControls.P1Control.KeyPrevWeapon2)) and
1628 (not isKeyPressed(gGameControls.P1Control.KeyNextWeapon, gGameControls.P1Control.KeyNextWeapon2)) then
1629 gSpectKeyPress := False;
1630 end;
1632 // Îáíîâëÿåì âñå îñòàëüíîå:
1633 g_Map_Update();
1634 g_Items_Update();
1635 g_Triggers_Update();
1636 g_Weapon_Update();
1637 g_Monsters_Update();
1638 g_GFX_Update();
1639 g_Player_UpdateAll();
1640 g_Player_UpdatePhysicalObjects();
1641 if gGameSettings.GameType = GT_SERVER then
1642 if Length(gMonstersSpawned) > 0 then
1643 begin
1644 for I := 0 to High(gMonstersSpawned) do
1645 MH_SEND_MonsterSpawn(gMonstersSpawned[I]);
1646 SetLength(gMonstersSpawned, 0);
1647 end;
1649 if (gSoundTriggerTime > 8) then
1650 begin
1651 g_Game_UpdateTriggerSounds();
1652 gSoundTriggerTime := 0;
1653 end
1654 else
1655 Inc(gSoundTriggerTime);
1657 if (NetMode = NET_SERVER) then
1658 begin
1659 Inc(NetTimeToUpdate);
1660 Inc(NetTimeToReliable);
1661 if NetTimeToReliable >= NetRelupdRate then
1662 begin
1663 for I := 0 to High(gPlayers) do
1664 if gPlayers[I] <> nil then
1665 MH_SEND_PlayerPos(True, gPlayers[I].UID);
1667 if gMonsters <> nil then
1668 for I := 0 to High(gMonsters) do
1669 if gMonsters[I] <> nil then
1670 begin
1671 if (gMonsters[I].MonsterType = MONSTER_BARREL) then
1672 begin
1673 if (gMonsters[I].GameVelX <> 0) or (gMonsters[I].GameVelY <> 0) then
1674 MH_SEND_MonsterPos(gMonsters[I].UID);
1675 end
1676 else
1677 if (gMonsters[I].MonsterState <> MONSTATE_SLEEP) then
1678 if (gMonsters[I].MonsterState <> MONSTATE_DEAD) or
1679 (gMonsters[I].GameVelX <> 0) or
1680 (gMonsters[I].GameVelY <> 0) then
1681 MH_SEND_MonsterPos(gMonsters[I].UID);
1682 end;
1684 NetTimeToReliable := 0;
1685 NetTimeToUpdate := NetUpdateRate;
1686 end
1687 else if NetTimeToUpdate >= NetUpdateRate then
1688 begin
1689 if gPlayers <> nil then
1690 for I := 0 to High(gPlayers) do
1691 if gPlayers[I] <> nil then
1692 MH_SEND_PlayerPos(False, gPlayers[I].UID);
1694 if gMonsters <> nil then
1695 for I := 0 to High(gMonsters) do
1696 if gMonsters[I] <> nil then
1697 begin
1698 if (gMonsters[I].MonsterType = MONSTER_BARREL) then
1699 begin
1700 if (gMonsters[I].GameVelX <> 0) or (gMonsters[I].GameVelY <> 0) then
1701 MH_SEND_MonsterPos(gMonsters[I].UID);
1702 end
1703 else
1704 if (gMonsters[I].MonsterState <> MONSTATE_SLEEP) then
1705 if (gMonsters[I].MonsterState <> MONSTATE_DEAD) or
1706 (gMonsters[I].GameVelX <> 0) or
1707 (gMonsters[I].GameVelY <> 0) then
1708 MH_SEND_MonsterPos(gMonsters[I].UID);
1709 end;
1711 NetTimeToUpdate := 0;
1712 end;
1714 if NetUseMaster then
1715 if gTime >= NetTimeToMaster then
1716 begin
1717 if (NetMHost = nil) or (NetMPeer = nil) then
1718 if not g_Net_Slist_Connect then
1719 g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_SLIST_ERROR]);
1721 g_Net_Slist_Update;
1722 NetTimeToMaster := gTime + NetMasterRate;
1723 end;
1724 end
1725 else
1726 if NetMode = NET_CLIENT then
1727 MC_SEND_PlayerPos();
1728 end; // if gameOn ...
1730 // Àêòèâíî îêíî èíòåðôåéñà - ïåðåäàåì êëàâèøè åìó:
1731 if g_ActiveWindow <> nil then
1732 begin
1733 w := e_GetFirstKeyPressed();
1735 if (w <> IK_INVALID) then
1736 begin
1737 Msg.Msg := MESSAGE_DIKEY;
1738 Msg.wParam := w;
1739 g_ActiveWindow.OnMessage(Msg);
1740 end;
1742 // Åñëè îíî îò ýòîãî íå çàêðûëîñü, òî îáíîâëÿåì:
1743 if g_ActiveWindow <> nil then
1744 g_ActiveWindow.Update();
1746 // Íóæíî ñìåíèòü ðàçðåøåíèå:
1747 if gResolutionChange then
1748 begin
1749 e_WriteLog('Changing resolution', MSG_NOTIFY);
1750 g_Game_ChangeResolution(gRC_Width, gRC_Height, gRC_FullScreen, gRC_Maximized);
1751 gResolutionChange := False;
1752 end;
1754 // Íóæíî ñìåíèòü ÿçûê:
1755 if gLanguageChange then
1756 begin
1757 //e_WriteLog('Read language file', MSG_NOTIFY);
1758 //g_Language_Load(DataDir + gLanguage + '.txt');
1759 g_Language_Set(gLanguage);
1760 g_Menu_Reset();
1761 gLanguageChange := False;
1762 end;
1763 end;
1765 // Äåëàåì ñêðèíøîò (íå ÷àùå 200 ìèëëèñåêóíä):
1766 if e_KeyPressed(gGameControls.GameControls.TakeScreenshot) then
1767 if (GetTimer()-LastScreenShot) > 200000 div 1000 then
1768 begin
1769 g_TakeScreenShot();
1770 LastScreenShot := GetTimer();
1771 end;
1773 // Ãîðÿ÷àÿ êëàâèøà äëÿ âûçîâà ìåíþ âûõîäà èç èãðû (F10):
1774 if e_KeyPressed(IK_F10) and
1775 gGameOn and
1776 (not gConsoleShow) and
1777 (g_ActiveWindow = nil) then
1778 begin
1779 KeyPress(IK_F10);
1780 end;
1782 Time := GetTimer() {div 1000};
1784 // Îáðàáîòêà îòëîæåííûõ ñîáûòèé:
1785 if gDelayedEvents <> nil then
1786 for a := 0 to High(gDelayedEvents) do
1787 if gDelayedEvents[a].Pending and
1789 ((gDelayedEvents[a].DEType = DE_GLOBEVENT) and (gDelayedEvents[a].Time <= Time)) or
1790 ((gDelayedEvents[a].DEType > DE_GLOBEVENT) and (gDelayedEvents[a].Time <= gTime))
1791 ) then
1792 begin
1793 case gDelayedEvents[a].DEType of
1794 DE_GLOBEVENT:
1795 g_Game_ExecuteEvent(gDelayedEvents[a].DEStr);
1796 DE_BFGHIT:
1797 if gGameOn then
1798 g_Game_Announce_GoodShot(gDelayedEvents[a].DENum);
1799 DE_KILLCOMBO:
1800 if gGameOn then
1801 begin
1802 g_Game_Announce_KillCombo(gDelayedEvents[a].DENum);
1803 if g_Game_IsNet and g_Game_IsServer then
1804 MH_SEND_GameEvent(NET_EV_KILLCOMBO, gDelayedEvents[a].DENum);
1805 end;
1806 end;
1807 gDelayedEvents[a].Pending := False;
1808 end;
1810 // Êàæäóþ ñåêóíäó îáíîâëÿåì ñ÷åò÷èê îáíîâëåíèé:
1811 UPSCounter := UPSCounter + 1;
1812 if Time - UPSTime >= 1000 then
1813 begin
1814 UPS := UPSCounter;
1815 UPSCounter := 0;
1816 UPSTime := Time;
1817 end;
1818 end;
1820 procedure g_Game_LoadData();
1821 begin
1822 if DataLoaded then Exit;
1824 e_WriteLog('Loading game data...', MSG_NOTIFY);
1826 g_Texture_CreateWADEx('NOTEXTURE', GameWAD+':TEXTURES\NOTEXTURE');
1827 g_Texture_CreateWADEx('TEXTURE_PLAYER_HUD', GameWAD+':TEXTURES\HUD');
1828 g_Texture_CreateWADEx('TEXTURE_PLAYER_HUDAIR', GameWAD+':TEXTURES\AIRBAR');
1829 g_Texture_CreateWADEx('TEXTURE_PLAYER_HUDJET', GameWAD+':TEXTURES\JETBAR');
1830 g_Texture_CreateWADEx('TEXTURE_PLAYER_HUDBG', GameWAD+':TEXTURES\HUDBG');
1831 g_Texture_CreateWADEx('TEXTURE_PLAYER_ARMORHUD', GameWAD+':TEXTURES\ARMORHUD');
1832 g_Texture_CreateWADEx('TEXTURE_PLAYER_REDFLAG', GameWAD+':TEXTURES\FLAGHUD_RB');
1833 g_Texture_CreateWADEx('TEXTURE_PLAYER_REDFLAG_S', GameWAD+':TEXTURES\FLAGHUD_RS');
1834 g_Texture_CreateWADEx('TEXTURE_PLAYER_REDFLAG_D', GameWAD+':TEXTURES\FLAGHUD_RD');
1835 g_Texture_CreateWADEx('TEXTURE_PLAYER_BLUEFLAG', GameWAD+':TEXTURES\FLAGHUD_BB');
1836 g_Texture_CreateWADEx('TEXTURE_PLAYER_BLUEFLAG_S', GameWAD+':TEXTURES\FLAGHUD_BS');
1837 g_Texture_CreateWADEx('TEXTURE_PLAYER_BLUEFLAG_D', GameWAD+':TEXTURES\FLAGHUD_BD');
1838 g_Texture_CreateWADEx('TEXTURE_PLAYER_TALKBUBBLE', GameWAD+':TEXTURES\TALKBUBBLE');
1839 g_Texture_CreateWADEx('TEXTURE_PLAYER_INVULPENTA', GameWAD+':TEXTURES\PENTA');
1840 g_Frames_CreateWAD(nil, 'FRAMES_TELEPORT', GameWAD+':TEXTURES\TELEPORT', 64, 64, 10, False);
1841 g_Sound_CreateWADEx('SOUND_GAME_TELEPORT', GameWAD+':SOUNDS\TELEPORT');
1842 g_Sound_CreateWADEx('SOUND_GAME_NOTELEPORT', GameWAD+':SOUNDS\NOTELEPORT');
1843 g_Sound_CreateWADEx('SOUND_GAME_DOOROPEN', GameWAD+':SOUNDS\DOOROPEN');
1844 g_Sound_CreateWADEx('SOUND_GAME_DOORCLOSE', GameWAD+':SOUNDS\DOORCLOSE');
1845 g_Sound_CreateWADEx('SOUND_GAME_BULK1', GameWAD+':SOUNDS\BULK1');
1846 g_Sound_CreateWADEx('SOUND_GAME_BULK2', GameWAD+':SOUNDS\BULK2');
1847 g_Sound_CreateWADEx('SOUND_GAME_BUBBLE1', GameWAD+':SOUNDS\BUBBLE1');
1848 g_Sound_CreateWADEx('SOUND_GAME_BUBBLE2', GameWAD+':SOUNDS\BUBBLE2');
1849 g_Sound_CreateWADEx('SOUND_GAME_SWITCH1', GameWAD+':SOUNDS\SWITCH1');
1850 g_Sound_CreateWADEx('SOUND_GAME_SWITCH0', GameWAD+':SOUNDS\SWITCH0');
1851 g_Sound_CreateWADEx('SOUND_GAME_RADIO', GameWAD+':SOUNDS\RADIO');
1852 g_Sound_CreateWADEx('SOUND_ANNOUNCER_GOOD1', GameWAD+':SOUNDS\GOOD1');
1853 g_Sound_CreateWADEx('SOUND_ANNOUNCER_GOOD2', GameWAD+':SOUNDS\GOOD2');
1854 g_Sound_CreateWADEx('SOUND_ANNOUNCER_GOOD3', GameWAD+':SOUNDS\GOOD3');
1855 g_Sound_CreateWADEx('SOUND_ANNOUNCER_GOOD4', GameWAD+':SOUNDS\GOOD4');
1856 g_Sound_CreateWADEx('SOUND_ANNOUNCER_KILL2X', GameWAD+':SOUNDS\KILL2X');
1857 g_Sound_CreateWADEx('SOUND_ANNOUNCER_KILL3X', GameWAD+':SOUNDS\KILL3X');
1858 g_Sound_CreateWADEx('SOUND_ANNOUNCER_KILL4X', GameWAD+':SOUNDS\KILL4X');
1859 g_Sound_CreateWADEx('SOUND_ANNOUNCER_KILLMX', GameWAD+':SOUNDS\KILLMX');
1861 goodsnd[0] := TPlayableSound.Create();
1862 goodsnd[1] := TPlayableSound.Create();
1863 goodsnd[2] := TPlayableSound.Create();
1864 goodsnd[3] := TPlayableSound.Create();
1866 goodsnd[0].SetByName('SOUND_ANNOUNCER_GOOD1');
1867 goodsnd[1].SetByName('SOUND_ANNOUNCER_GOOD2');
1868 goodsnd[2].SetByName('SOUND_ANNOUNCER_GOOD3');
1869 goodsnd[3].SetByName('SOUND_ANNOUNCER_GOOD4');
1871 killsnd[0] := TPlayableSound.Create();
1872 killsnd[1] := TPlayableSound.Create();
1873 killsnd[2] := TPlayableSound.Create();
1874 killsnd[3] := TPlayableSound.Create();
1876 killsnd[0].SetByName('SOUND_ANNOUNCER_KILL2X');
1877 killsnd[1].SetByName('SOUND_ANNOUNCER_KILL3X');
1878 killsnd[2].SetByName('SOUND_ANNOUNCER_KILL4X');
1879 killsnd[3].SetByName('SOUND_ANNOUNCER_KILLMX');
1881 g_Game_SetLoadingText(_lc[I_LOAD_ITEMS_DATA], 0, False);
1882 g_Items_LoadData();
1884 g_Game_SetLoadingText(_lc[I_LOAD_WEAPONS_DATA], 0, False);
1885 g_Weapon_LoadData();
1887 g_Monsters_LoadData();
1889 DataLoaded := True;
1890 end;
1892 procedure g_Game_FreeData();
1893 begin
1894 if not DataLoaded then Exit;
1896 g_Items_FreeData();
1897 g_Weapon_FreeData();
1898 g_Monsters_FreeData();
1900 e_WriteLog('Releasing game data...', MSG_NOTIFY);
1902 g_Texture_Delete('NOTEXTURE');
1903 g_Texture_Delete('TEXTURE_PLAYER_HUD');
1904 g_Texture_Delete('TEXTURE_PLAYER_HUDBG');
1905 g_Texture_Delete('TEXTURE_PLAYER_ARMORHUD');
1906 g_Texture_Delete('TEXTURE_PLAYER_REDFLAG');
1907 g_Texture_Delete('TEXTURE_PLAYER_REDFLAG_S');
1908 g_Texture_Delete('TEXTURE_PLAYER_REDFLAG_D');
1909 g_Texture_Delete('TEXTURE_PLAYER_BLUEFLAG');
1910 g_Texture_Delete('TEXTURE_PLAYER_BLUEFLAG_S');
1911 g_Texture_Delete('TEXTURE_PLAYER_BLUEFLAG_D');
1912 g_Texture_Delete('TEXTURE_PLAYER_TALKBUBBLE');
1913 g_Texture_Delete('TEXTURE_PLAYER_INVULPENTA');
1914 g_Frames_DeleteByName('FRAMES_TELEPORT');
1915 g_Sound_Delete('SOUND_GAME_TELEPORT');
1916 g_Sound_Delete('SOUND_GAME_NOTELEPORT');
1917 g_Sound_Delete('SOUND_GAME_DOOROPEN');
1918 g_Sound_Delete('SOUND_GAME_DOORCLOSE');
1919 g_Sound_Delete('SOUND_GAME_BULK1');
1920 g_Sound_Delete('SOUND_GAME_BULK2');
1921 g_Sound_Delete('SOUND_GAME_BUBBLE1');
1922 g_Sound_Delete('SOUND_GAME_BUBBLE2');
1923 g_Sound_Delete('SOUND_GAME_SWITCH1');
1924 g_Sound_Delete('SOUND_GAME_SWITCH0');
1926 goodsnd[0].Free();
1927 goodsnd[1].Free();
1928 goodsnd[2].Free();
1929 goodsnd[3].Free();
1931 g_Sound_Delete('SOUND_ANNOUNCER_GOOD1');
1932 g_Sound_Delete('SOUND_ANNOUNCER_GOOD2');
1933 g_Sound_Delete('SOUND_ANNOUNCER_GOOD3');
1934 g_Sound_Delete('SOUND_ANNOUNCER_GOOD4');
1936 killsnd[0].Free();
1937 killsnd[1].Free();
1938 killsnd[2].Free();
1939 killsnd[3].Free();
1941 g_Sound_Delete('SOUND_ANNOUNCER_KILL2X');
1942 g_Sound_Delete('SOUND_ANNOUNCER_KILL3X');
1943 g_Sound_Delete('SOUND_ANNOUNCER_KILL4X');
1944 g_Sound_Delete('SOUND_ANNOUNCER_KILLMX');
1946 DataLoaded := False;
1947 end;
1949 procedure DrawCustomStat();
1950 var
1951 pc, x, y, w, _y,
1952 w1, w2, w3,
1953 t, p, m: Integer;
1954 ww1, hh1: Word;
1955 ww2, hh2, r, g, b, rr, gg, bb: Byte;
1956 s1, s2, topstr: String;
1957 begin
1958 e_TextureFontGetSize(gStdFont, ww2, hh2);
1960 e_PollInput();
1961 if e_KeyPressed(IK_TAB) then
1962 begin
1963 if not gStatsPressed then
1964 begin
1965 gStatsOff := not gStatsOff;
1966 gStatsPressed := True;
1967 end;
1968 end
1969 else
1970 gStatsPressed := False;
1972 if gStatsOff then
1973 begin
1974 s1 := _lc[I_MENU_INTER_NOTICE_TAB];
1975 w := (Length(s1) * ww2) div 2;
1976 x := gScreenWidth div 2 - w;
1977 y := 8;
1978 e_TextureFontPrint(x, y, s1, gStdFont);
1979 Exit;
1980 end;
1982 if (gGameSettings.GameMode = GM_COOP) then
1983 begin
1984 if gMissionFailed then
1985 topstr := _lc[I_MENU_INTER_MISSION_FAIL]
1986 else
1987 topstr := _lc[I_MENU_INTER_LEVEL_COMPLETE];
1988 end
1989 else
1990 topstr := _lc[I_MENU_INTER_ROUND_OVER];
1992 e_CharFont_GetSize(gMenuFont, topstr, ww1, hh1);
1993 e_CharFont_Print(gMenuFont, (gScreenWidth div 2)-(ww1 div 2), 16, topstr);
1995 if g_Game_IsNet then
1996 begin
1997 topstr := Format(_lc[I_MENU_INTER_NOTICE_TIME], [gServInterTime]);
1998 if not gChatShow then
1999 e_TextureFontPrintEx((gScreenWidth div 2)-(Length(topstr)*ww2 div 2),
2000 gScreenHeight-(hh2+4)*2, topstr, gStdFont, 255, 255, 255, 1);
2001 end;
2003 if g_Game_IsClient then
2004 topstr := _lc[I_MENU_INTER_NOTICE_MAP]
2005 else
2006 topstr := _lc[I_MENU_INTER_NOTICE_SPACE];
2007 if not gChatShow then
2008 e_TextureFontPrintEx((gScreenWidth div 2)-(Length(topstr)*ww2 div 2),
2009 gScreenHeight-(hh2+4), topstr, gStdFont, 255, 255, 255, 1);
2011 x := 32;
2012 y := 16+hh1+16;
2014 w := gScreenWidth-x*2;
2016 w2 := (w-16) div 6;
2017 w3 := w2;
2018 w1 := w-16-w2-w3;
2020 e_DrawFillQuad(x, y, gScreenWidth-x-1, gScreenHeight-y-1, 64, 64, 64, 32);
2021 e_DrawQuad(x, y, gScreenWidth-x-1, gScreenHeight-y-1, 255, 127, 0);
2023 m := Max(Length(_lc[I_MENU_MAP])+1, Length(_lc[I_GAME_GAME_TIME])+1)*ww2;
2025 case CustomStat.GameMode of
2026 GM_DM:
2027 begin
2028 if gGameSettings.MaxLives = 0 then
2029 s1 := _lc[I_GAME_DM]
2030 else
2031 s1 := _lc[I_GAME_LMS];
2032 end;
2033 GM_TDM:
2034 begin
2035 if gGameSettings.MaxLives = 0 then
2036 s1 := _lc[I_GAME_TDM]
2037 else
2038 s1 := _lc[I_GAME_TLMS];
2039 end;
2040 GM_CTF: s1 := _lc[I_GAME_CTF];
2041 GM_COOP:
2042 begin
2043 if gGameSettings.MaxLives = 0 then
2044 s1 := _lc[I_GAME_COOP]
2045 else
2046 s1 := _lc[I_GAME_SURV];
2047 end;
2048 else s1 := '';
2049 end;
2051 _y := y+16;
2052 e_TextureFontPrintEx(x+(w div 2)-(Length(s1)*ww2 div 2), _y, s1, gStdFont, 255, 255, 255, 1);
2053 _y := _y+8;
2055 _y := _y+16;
2056 e_TextureFontPrintEx(x+8, _y, _lc[I_MENU_MAP], gStdFont, 255, 127, 0, 1);
2057 e_TextureFontPrint(x+8+m, _y, Format('%s - %s', [CustomStat.Map, CustomStat.MapName]), gStdFont);
2059 _y := _y+16;
2060 e_TextureFontPrintEx(x+8, _y, _lc[I_GAME_GAME_TIME], gStdFont, 255, 127, 0, 1);
2061 e_TextureFontPrint(x+8+m, _y, Format('%d:%.2d:%.2d', [CustomStat.GameTime div 1000 div 3600,
2062 (CustomStat.GameTime div 1000 div 60) mod 60,
2063 CustomStat.GameTime div 1000 mod 60]), gStdFont);
2065 pc := Length(CustomStat.PlayerStat);
2066 if pc = 0 then Exit;
2068 if CustomStat.GameMode = GM_COOP then
2069 begin
2070 m := Max(Length(_lc[I_GAME_MONSTERS])+1, Length(_lc[I_GAME_SECRETS])+1)*ww2;
2071 _y := _y+32;
2072 s2 := _lc[I_GAME_MONSTERS];
2073 e_TextureFontPrintEx(x+8, _y, s2, gStdFont, 255, 127, 0, 1);
2074 e_TextureFontPrintEx(x+8+m, _y, IntToStr(gCoopMonstersKilled) + '/' + IntToStr(gTotalMonsters), gStdFont, 255, 255, 255, 1);
2075 _y := _y+16;
2076 s2 := _lc[I_GAME_SECRETS];
2077 e_TextureFontPrintEx(x+8, _y, s2, gStdFont, 255, 127, 0, 1);
2078 e_TextureFontPrintEx(x+8+m, _y, IntToStr(gCoopSecretsFound) + '/' + IntToStr(gSecretsCount), gStdFont, 255, 255, 255, 1);
2079 if gLastMap then
2080 begin
2081 m := Max(Length(_lc[I_GAME_MONSTERS_TOTAL])+1, Length(_lc[I_GAME_SECRETS_TOTAL])+1)*ww2;
2082 _y := _y-16;
2083 s2 := _lc[I_GAME_MONSTERS_TOTAL];
2084 e_TextureFontPrintEx(x+250, _y, s2, gStdFont, 255, 127, 0, 1);
2085 e_TextureFontPrintEx(x+250+m, _y, IntToStr(gCoopTotalMonstersKilled) + '/' + IntToStr(gCoopTotalMonsters), gStdFont, 255, 255, 255, 1);
2086 _y := _y+16;
2087 s2 := _lc[I_GAME_SECRETS_TOTAL];
2088 e_TextureFontPrintEx(x+250, _y, s2, gStdFont, 255, 127, 0, 1);
2089 e_TextureFontPrintEx(x+250+m, _y, IntToStr(gCoopTotalSecretsFound) + '/' + IntToStr(gCoopTotalSecrets), gStdFont, 255, 255, 255, 1);
2090 end;
2091 end;
2093 if CustomStat.GameMode in [GM_TDM, GM_CTF] then
2094 begin
2095 _y := _y+16+16;
2097 with CustomStat do
2098 if TeamStat[TEAM_RED].Goals > TeamStat[TEAM_BLUE].Goals then s1 := _lc[I_GAME_WIN_RED]
2099 else if TeamStat[TEAM_BLUE].Goals > TeamStat[TEAM_RED].Goals then s1 := _lc[I_GAME_WIN_BLUE]
2100 else s1 := _lc[I_GAME_WIN_DRAW];
2102 e_TextureFontPrintEx(x+8+(w div 2)-(Length(s1)*ww2 div 2), _y, s1, gStdFont, 255, 255, 255, 1);
2103 _y := _y+40;
2105 for t := TEAM_RED to TEAM_BLUE do
2106 begin
2107 if t = TEAM_RED then
2108 begin
2109 e_TextureFontPrintEx(x+8, _y, _lc[I_GAME_TEAM_RED],
2110 gStdFont, 255, 0, 0, 1);
2111 e_TextureFontPrintEx(x+w1+8, _y, IntToStr(CustomStat.TeamStat[TEAM_RED].Goals),
2112 gStdFont, 255, 0, 0, 1);
2113 r := 255;
2114 g := 0;
2115 b := 0;
2116 end
2117 else
2118 begin
2119 e_TextureFontPrintEx(x+8, _y, _lc[I_GAME_TEAM_BLUE],
2120 gStdFont, 0, 0, 255, 1);
2121 e_TextureFontPrintEx(x+w1+8, _y, IntToStr(CustomStat.TeamStat[TEAM_BLUE].Goals),
2122 gStdFont, 0, 0, 255, 1);
2123 r := 0;
2124 g := 0;
2125 b := 255;
2126 end;
2128 e_DrawLine(1, x+8, _y+20, x-8+w, _y+20, r, g, b);
2129 _y := _y+24;
2131 for p := 0 to High(CustomStat.PlayerStat) do
2132 if CustomStat.PlayerStat[p].Team = t then
2133 with CustomStat.PlayerStat[p] do
2134 begin
2135 if Spectator then
2136 begin
2137 rr := r div 2;
2138 gg := g div 2;
2139 bb := b div 2;
2140 end
2141 else
2142 begin
2143 rr := r;
2144 gg := g;
2145 bb := b;
2146 end;
2147 e_TextureFontPrintEx(x+8, _y, Name, gStdFont, rr, gg, bb, 1);
2148 e_TextureFontPrintEx(x+w1+8, _y, IntToStr(Frags), gStdFont, rr, gg, bb, 1);
2149 e_TextureFontPrintEx(x+w1+w2+8, _y, IntToStr(Deaths), gStdFont, rr, gg, bb, 1);
2150 _y := _y+24;
2151 end;
2153 _y := _y+16+16;
2154 end;
2155 end
2156 else if CustomStat.GameMode in [GM_DM, GM_COOP] then
2157 begin
2158 _y := _y+40;
2159 e_TextureFontPrintEx(x+8, _y, _lc[I_GAME_PLAYER_NAME], gStdFont, 255, 127, 0, 1);
2160 e_TextureFontPrintEx(x+8+w1, _y, _lc[I_GAME_FRAGS], gStdFont, 255, 127, 0, 1);
2161 e_TextureFontPrintEx(x+8+w1+w2, _y, _lc[I_GAME_DEATHS], gStdFont, 255, 127, 0, 1);
2163 _y := _y+24;
2164 for p := 0 to High(CustomStat.PlayerStat) do
2165 with CustomStat.PlayerStat[p] do
2166 begin
2167 e_DrawFillQuad(x+8, _y+4, x+24-1, _y+16+4-1, Color.R, Color.G, Color.B, 0);
2169 if Spectator then
2170 r := 127
2171 else
2172 r := 255;
2174 e_TextureFontPrintEx(x+8+16+8, _y+4, Name, gStdFont, r, r, r, 1, True);
2175 e_TextureFontPrintEx(x+w1+8+16+8, _y+4, IntToStr(Frags), gStdFont, r, r, r, 1, True);
2176 e_TextureFontPrintEx(x+w1+w2+8+16+8, _y+4, IntToStr(Deaths), gStdFont, r, r, r, 1, True);
2177 _y := _y+24;
2178 end;
2179 end;
2180 end;
2182 procedure DrawSingleStat();
2183 var
2184 tm, key_x, val_x, y: Integer;
2185 w1, w2, h: Word;
2186 s1, s2: String;
2188 procedure player_stat(n: Integer);
2189 var
2190 kpm: Real;
2192 begin
2193 // "Kills: # / #":
2194 s1 := Format(' %d ', [SingleStat.PlayerStat[n].Kills]);
2195 s2 := Format(' %d', [gTotalMonsters]);
2197 e_CharFont_Print(gMenuFont, key_x, y, _lc[I_MENU_INTER_KILLS]);
2198 e_CharFont_PrintEx(gMenuFont, val_x, y, s1, _RGB(255, 0, 0));
2199 e_CharFont_GetSize(gMenuFont, s1, w1, h);
2200 e_CharFont_Print(gMenuFont, val_x+w1, y, '/');
2201 s1 := s1 + '/';
2202 e_CharFont_GetSize(gMenuFont, s1, w1, h);
2203 e_CharFont_PrintEx(gMenuFont, val_x+w1, y, s2, _RGB(255, 0, 0));
2205 // "Kills-per-minute: ##.#":
2206 s1 := _lc[I_MENU_INTER_KPM];
2207 if tm > 0 then
2208 kpm := (SingleStat.PlayerStat[n].Kills / tm) * 60
2209 else
2210 kpm := SingleStat.PlayerStat[n].Kills;
2211 s2 := Format(' %.1f', [kpm]);
2213 e_CharFont_Print(gMenuFont, key_x, y+32, s1);
2214 e_CharFont_PrintEx(gMenuFont, val_x, y+32, s2, _RGB(255, 0, 0));
2216 // "Secrets found: # / #":
2217 s1 := Format(' %d ', [SingleStat.PlayerStat[n].Secrets]);
2218 s2 := Format(' %d', [SingleStat.TotalSecrets]);
2220 e_CharFont_Print(gMenuFont, key_x, y+64, _lc[I_MENU_INTER_SECRETS]);
2221 e_CharFont_PrintEx(gMenuFont, val_x, y+64, s1, _RGB(255, 0, 0));
2222 e_CharFont_GetSize(gMenuFont, s1, w1, h);
2223 e_CharFont_Print(gMenuFont, val_x+w1, y+64, '/');
2224 s1 := s1 + '/';
2225 e_CharFont_GetSize(gMenuFont, s1, w1, h);
2226 e_CharFont_PrintEx(gMenuFont, val_x+w1, y+64, s2, _RGB(255, 0, 0));
2227 end;
2229 begin
2230 // "Level Complete":
2231 e_CharFont_GetSize(gMenuFont, _lc[I_MENU_INTER_LEVEL_COMPLETE], w1, h);
2232 e_CharFont_Print(gMenuFont, (gScreenWidth-w1) div 2, 32, _lc[I_MENU_INTER_LEVEL_COMPLETE]);
2234 // Îïðåäåëÿåì êîîðäèíàòû âûðàâíèâàíèÿ ïî ñàìîé äëèííîé ñòðîêå:
2235 s1 := _lc[I_MENU_INTER_KPM];
2236 e_CharFont_GetSize(gMenuFont, s1, w1, h);
2237 Inc(w1, 16);
2238 s1 := ' 9999.9';
2239 e_CharFont_GetSize(gMenuFont, s1, w2, h);
2241 key_x := (gScreenWidth-w1-w2) div 2;
2242 val_x := key_x + w1;
2244 // "Time: #:##:##":
2245 tm := SingleStat.GameTime div 1000;
2246 s1 := _lc[I_MENU_INTER_TIME];
2247 s2 := Format(' %d:%.2d:%.2d', [tm div (60*60), (tm mod (60*60)) div 60, tm mod 60]);
2249 e_CharFont_Print(gMenuFont, key_x, 80, s1);
2250 e_CharFont_PrintEx(gMenuFont, val_x, 80, s2, _RGB(255, 0, 0));
2252 if SingleStat.TwoPlayers then
2253 begin
2254 // "Player 1":
2255 s1 := _lc[I_MENU_PLAYER_1];
2256 e_CharFont_GetSize(gMenuFont, s1, w1, h);
2257 e_CharFont_Print(gMenuFont, (gScreenWidth-w1) div 2, 128, s1);
2259 // Ñòàòèñòèêà ïåðâîãî èãðîêà:
2260 y := 176;
2261 player_stat(0);
2263 // "Player 2":
2264 s1 := _lc[I_MENU_PLAYER_2];
2265 e_CharFont_GetSize(gMenuFont, s1, w1, h);
2266 e_CharFont_Print(gMenuFont, (gScreenWidth-w1) div 2, 288, s1);
2268 // Ñòàòèñòèêà âòîðîãî èãðîêà:
2269 y := 336;
2270 player_stat(1);
2271 end
2272 else
2273 begin
2274 // Ñòàòèñòèêà ïåðâîãî èãðîêà:
2275 y := 128;
2276 player_stat(0);
2277 end;
2278 end;
2280 procedure DrawLoadingStat();
2281 var
2282 ww, hh: Word;
2283 xx, yy, i: Integer;
2284 s: String;
2285 begin
2286 if Length(LoadingStat.Msgs) = 0 then
2287 Exit;
2289 e_CharFont_GetSize(gMenuFont, _lc[I_MENU_LOADING], ww, hh);
2290 yy := (gScreenHeight div 3);
2291 e_CharFont_Print(gMenuFont, (gScreenWidth div 2)-(ww div 2), yy-2*hh, _lc[I_MENU_LOADING]);
2292 xx := (gScreenWidth div 3);
2294 with LoadingStat do
2295 for i := 0 to NextMsg-1 do
2296 begin
2297 if (i = (NextMsg-1)) and (MaxValue > 0) then
2298 s := Format('%s: %d/%d', [Msgs[i], CurValue, MaxValue])
2299 else
2300 s := Msgs[i];
2302 e_CharFont_PrintEx(gMenuSmallFont, xx, yy, s, _RGB(255, 0, 0));
2303 yy := yy + LOADING_INTERLINE;
2304 end;
2305 end;
2307 procedure DrawMinimap(p: TPlayer; RenderRect: e_graphics.TRect);
2308 var
2309 a, aX, aY, aX2, aY2, Scale, ScaleSz: Integer;
2310 begin
2311 if (gMapInfo.Width > RenderRect.Right - RenderRect.Left) or
2312 (gMapInfo.Height > RenderRect.Bottom - RenderRect.Top) then
2313 begin
2314 Scale := 1;
2315 // Ñêîëüêî ïèêñåëîâ êàðòû â 1 ïèêñåëå ìèíè-êàðòû:
2316 ScaleSz := 16 div Scale;
2317 // Ðàçìåðû ìèíè-êàðòû:
2318 aX := max(gMapInfo.Width div ScaleSz, 1);
2319 aY := max(gMapInfo.Height div ScaleSz, 1);
2320 // Ðàìêà êàðòû:
2321 e_DrawFillQuad(0, 0, aX-1, aY-1, 0, 0, 0, 0);
2323 if gWalls <> nil then
2324 begin
2325 // Ðèñóåì ñòåíû:
2326 for a := 0 to High(gWalls) do
2327 with gWalls[a] do
2328 if PanelType <> 0 then
2329 begin
2330 // Ëåâûé âåðõíèé óãîë:
2331 aX := X div ScaleSz;
2332 aY := Y div ScaleSz;
2333 // Ðàçìåðû:
2334 aX2 := max(Width div ScaleSz, 1);
2335 aY2 := max(Height div ScaleSz, 1);
2336 // Ïðàâûé íèæíèé óãîë:
2337 aX2 := aX + aX2 - 1;
2338 aY2 := aY + aY2 - 1;
2340 case PanelType of
2341 PANEL_WALL: e_DrawFillQuad(aX, aY, aX2, aY2, 208, 208, 208, 0);
2342 PANEL_OPENDOOR, PANEL_CLOSEDOOR:
2343 if Enabled then e_DrawFillQuad(aX, aY, aX2, aY2, 160, 160, 160, 0);
2344 end;
2345 end;
2346 end;
2347 if gSteps <> nil then
2348 begin
2349 // Ðèñóåì ñòóïåíè:
2350 for a := 0 to High(gSteps) do
2351 with gSteps[a] do
2352 if PanelType <> 0 then
2353 begin
2354 // Ëåâûé âåðõíèé óãîë:
2355 aX := X div ScaleSz;
2356 aY := Y div ScaleSz;
2357 // Ðàçìåðû:
2358 aX2 := max(Width div ScaleSz, 1);
2359 aY2 := max(Height div ScaleSz, 1);
2360 // Ïðàâûé íèæíèé óãîë:
2361 aX2 := aX + aX2 - 1;
2362 aY2 := aY + aY2 - 1;
2364 e_DrawFillQuad(aX, aY, aX2, aY2, 128, 128, 128, 0);
2365 end;
2366 end;
2367 if gLifts <> nil then
2368 begin
2369 // Ðèñóåì ëèôòû:
2370 for a := 0 to High(gLifts) do
2371 with gLifts[a] do
2372 if PanelType <> 0 then
2373 begin
2374 // Ëåâûé âåðõíèé óãîë:
2375 aX := X div ScaleSz;
2376 aY := Y div ScaleSz;
2377 // Ðàçìåðû:
2378 aX2 := max(Width div ScaleSz, 1);
2379 aY2 := max(Height div ScaleSz, 1);
2380 // Ïðàâûé íèæíèé óãîë:
2381 aX2 := aX + aX2 - 1;
2382 aY2 := aY + aY2 - 1;
2384 case LiftType of
2385 0: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 72, 36, 0);
2386 1: e_DrawFillQuad(aX, aY, aX2, aY2, 116, 124, 96, 0);
2387 2: e_DrawFillQuad(aX, aY, aX2, aY2, 200, 80, 4, 0);
2388 3: e_DrawFillQuad(aX, aY, aX2, aY2, 252, 140, 56, 0);
2389 end;
2390 end;
2391 end;
2392 if gWater <> nil then
2393 begin
2394 // Ðèñóåì âîäó:
2395 for a := 0 to High(gWater) do
2396 with gWater[a] do
2397 if PanelType <> 0 then
2398 begin
2399 // Ëåâûé âåðõíèé óãîë:
2400 aX := X div ScaleSz;
2401 aY := Y div ScaleSz;
2402 // Ðàçìåðû:
2403 aX2 := max(Width div ScaleSz, 1);
2404 aY2 := max(Height div ScaleSz, 1);
2405 // Ïðàâûé íèæíèé óãîë:
2406 aX2 := aX + aX2 - 1;
2407 aY2 := aY + aY2 - 1;
2409 e_DrawFillQuad(aX, aY, aX2, aY2, 0, 0, 192, 0);
2410 end;
2411 end;
2412 if gAcid1 <> nil then
2413 begin
2414 // Ðèñóåì êèñëîòó 1:
2415 for a := 0 to High(gAcid1) do
2416 with gAcid1[a] do
2417 if PanelType <> 0 then
2418 begin
2419 // Ëåâûé âåðõíèé óãîë:
2420 aX := X div ScaleSz;
2421 aY := Y div ScaleSz;
2422 // Ðàçìåðû:
2423 aX2 := max(Width div ScaleSz, 1);
2424 aY2 := max(Height div ScaleSz, 1);
2425 // Ïðàâûé íèæíèé óãîë:
2426 aX2 := aX + aX2 - 1;
2427 aY2 := aY + aY2 - 1;
2429 e_DrawFillQuad(aX, aY, aX2, aY2, 0, 176, 0, 0);
2430 end;
2431 end;
2432 if gAcid2 <> nil then
2433 begin
2434 // Ðèñóåì êèñëîòó 2:
2435 for a := 0 to High(gAcid2) do
2436 with gAcid2[a] do
2437 if PanelType <> 0 then
2438 begin
2439 // Ëåâûé âåðõíèé óãîë:
2440 aX := X div ScaleSz;
2441 aY := Y div ScaleSz;
2442 // Ðàçìåðû:
2443 aX2 := max(Width div ScaleSz, 1);
2444 aY2 := max(Height div ScaleSz, 1);
2445 // Ïðàâûé íèæíèé óãîë:
2446 aX2 := aX + aX2 - 1;
2447 aY2 := aY + aY2 - 1;
2449 e_DrawFillQuad(aX, aY, aX2, aY2, 176, 0, 0, 0);
2450 end;
2451 end;
2452 if gPlayers <> nil then
2453 begin
2454 // Ðèñóåì èãðîêîâ:
2455 for a := 0 to High(gPlayers) do
2456 if gPlayers[a] <> nil then with gPlayers[a] do
2457 if Live then begin
2458 // Ëåâûé âåðõíèé óãîë:
2459 aX := Obj.X div ScaleSz + 1;
2460 aY := Obj.Y div ScaleSz + 1;
2461 // Ðàçìåðû:
2462 aX2 := max(Obj.Rect.Width div ScaleSz, 1);
2463 aY2 := max(Obj.Rect.Height div ScaleSz, 1);
2464 // Ïðàâûé íèæíèé óãîë:
2465 aX2 := aX + aX2 - 1;
2466 aY2 := aY + aY2 - 1;
2468 if gPlayers[a] = p then
2469 e_DrawFillQuad(aX, aY, aX2, aY2, 0, 255, 0, 0)
2470 else
2471 case Team of
2472 TEAM_RED: e_DrawFillQuad(aX, aY, aX2, aY2, 255, 0, 0, 0);
2473 TEAM_BLUE: e_DrawFillQuad(aX, aY, aX2, aY2, 0, 0, 255, 0);
2474 else e_DrawFillQuad(aX, aY, aX2, aY2, 255, 128, 0, 0);
2475 end;
2476 end;
2477 end;
2478 if gMonsters <> nil then
2479 begin
2480 // Ðèñóåì ìîíñòðîâ:
2481 for a := 0 to High(gMonsters) do
2482 if gMonsters[a] <> nil then with gMonsters[a] do
2483 if Live then begin
2484 // Ëåâûé âåðõíèé óãîë:
2485 aX := Obj.X div ScaleSz + 1;
2486 aY := Obj.Y div ScaleSz + 1;
2487 // Ðàçìåðû:
2488 aX2 := max(Obj.Rect.Width div ScaleSz, 1);
2489 aY2 := max(Obj.Rect.Height div ScaleSz, 1);
2490 // Ïðàâûé íèæíèé óãîë:
2491 aX2 := aX + aX2 - 1;
2492 aY2 := aY + aY2 - 1;
2494 e_DrawFillQuad(aX, aY, aX2, aY2, 255, 255, 0, 0);
2495 end;
2496 end;
2497 end;
2498 end;
2500 procedure DrawMapView(x, y, w, h: Integer);
2501 var
2502 bx, by: Integer;
2503 begin
2504 glPushMatrix();
2506 bx := Round(x/(gMapInfo.Width - w)*(gBackSize.X - w));
2507 by := Round(y/(gMapInfo.Height - h)*(gBackSize.Y - h));
2508 g_Map_DrawBack(-bx, -by);
2510 sX := x;
2511 sY := y;
2512 sWidth := w;
2513 sHeight := h;
2515 glTranslatef(-x, -y, 0);
2517 g_Map_DrawPanels(PANEL_BACK);
2518 g_Map_DrawPanels(PANEL_STEP);
2519 g_Items_Draw();
2520 g_Weapon_Draw();
2521 g_Player_DrawShells();
2522 g_Player_DrawAll();
2523 g_Player_DrawCorpses();
2524 g_Map_DrawPanels(PANEL_WALL);
2525 g_Monsters_Draw();
2526 g_Map_DrawPanels(PANEL_CLOSEDOOR);
2527 g_GFX_Draw();
2528 g_Map_DrawFlags();
2529 g_Map_DrawPanels(PANEL_ACID1);
2530 g_Map_DrawPanels(PANEL_ACID2);
2531 g_Map_DrawPanels(PANEL_WATER);
2532 g_Map_DrawPanels(PANEL_FORE);
2533 if g_debug_HealthBar then
2534 begin
2535 g_Monsters_DrawHealth();
2536 g_Player_DrawHealth();
2537 end;
2539 glPopMatrix();
2540 end;
2542 procedure DrawPlayer(p: TPlayer);
2543 var
2544 px, py, a, b, c, d: Integer;
2545 //R: TRect;
2546 begin
2547 if (p = nil) or (p.FDummy) then
2548 begin
2549 glPushMatrix();
2550 g_Map_DrawBack(0, 0);
2551 glPopMatrix();
2552 Exit;
2553 end;
2555 gPlayerDrawn := p;
2557 glPushMatrix();
2559 px := p.GameX + PLAYER_RECT_CX;
2560 py := p.GameY + PLAYER_RECT_CY;
2562 if px > (gPlayerScreenSize.X div 2) then
2563 a := -px + (gPlayerScreenSize.X div 2)
2564 else
2565 a := 0;
2566 if py > (gPlayerScreenSize.Y div 2) then
2567 b := -py + (gPlayerScreenSize.Y div 2)
2568 else
2569 b := 0;
2570 if px > (gMapInfo.Width - (gPlayerScreenSize.X div 2)) then
2571 a := -gMapInfo.Width + gPlayerScreenSize.X;
2572 if py > (gMapInfo.Height - (gPlayerScreenSize.Y div 2)) then
2573 b := -gMapInfo.Height + gPlayerScreenSize.Y;
2574 if gMapInfo.Width <= gPlayerScreenSize.X then
2575 a := 0;
2576 if gMapInfo.Height <= gPlayerScreenSize.Y then
2577 b := 0;
2579 if p.IncCam <> 0 then
2580 begin
2581 if py > (gMapInfo.Height - (gPlayerScreenSize.Y div 2)) then
2582 begin
2583 if p.IncCam > 120-(py-(gMapInfo.Height-(gPlayerScreenSize.Y div 2))) then
2584 p.IncCam := 120-(py-(gMapInfo.Height-(gPlayerScreenSize.Y div 2)));
2585 end;
2587 if py < (gPlayerScreenSize.Y div 2) then
2588 begin
2589 if p.IncCam < -120+((gPlayerScreenSize.Y div 2)-py) then
2590 p.IncCam := -120+((gPlayerScreenSize.Y div 2)-py);
2591 end;
2593 if p.IncCam < 0 then
2594 while (py+(gPlayerScreenSize.Y div 2)-p.IncCam > gMapInfo.Height) and
2595 (p.IncCam < 0) do
2596 p.IncCam := p.IncCam + 1;
2598 if p.IncCam > 0 then
2599 while (py-(gPlayerScreenSize.Y div 2)-p.IncCam < 0) and
2600 (p.IncCam > 0) do
2601 p.IncCam := p.IncCam - 1;
2602 end;
2604 if (px< gPlayerScreenSize.X div 2) or
2605 (gMapInfo.Width-gPlayerScreenSize.X <= 256) then
2606 c := 0
2607 else
2608 if (px > gMapInfo.Width-(gPlayerScreenSize.X div 2)) then
2609 c := gBackSize.X - gPlayerScreenSize.X
2610 else
2611 c := Round((px-(gPlayerScreenSize.X div 2))/(gMapInfo.Width-gPlayerScreenSize.X)*(gBackSize.X-gPlayerScreenSize.X));
2613 if (py-p.IncCam <= gPlayerScreenSize.Y div 2) or
2614 (gMapInfo.Height-gPlayerScreenSize.Y <= 256) then
2615 d := 0
2616 else
2617 if (py-p.IncCam >= gMapInfo.Height-(gPlayerScreenSize.Y div 2)) then
2618 d := gBackSize.Y - gPlayerScreenSize.Y
2619 else
2620 d := Round((py-p.IncCam-(gPlayerScreenSize.Y div 2))/(gMapInfo.Height-gPlayerScreenSize.Y)*(gBackSize.Y-gPlayerScreenSize.Y));
2622 g_Map_DrawBack(-c, -d);
2624 sX := -a;
2625 sY := -(b+p.IncCam);
2626 sWidth := gPlayerScreenSize.X;
2627 sHeight := gPlayerScreenSize.Y;
2629 glTranslatef(a, b+p.IncCam, 0);
2631 g_Map_DrawPanels(PANEL_BACK);
2632 g_Map_DrawPanels(PANEL_STEP);
2633 g_Items_Draw();
2634 g_Weapon_Draw();
2635 g_Player_DrawShells();
2636 g_Player_DrawAll();
2637 g_Player_DrawCorpses();
2638 g_Map_DrawPanels(PANEL_WALL);
2639 g_Monsters_Draw();
2640 g_Map_DrawPanels(PANEL_CLOSEDOOR);
2641 g_GFX_Draw();
2642 g_Map_DrawFlags();
2643 g_Map_DrawPanels(PANEL_ACID1);
2644 g_Map_DrawPanels(PANEL_ACID2);
2645 g_Map_DrawPanels(PANEL_WATER);
2646 g_Map_DrawPanels(PANEL_FORE);
2647 if g_debug_HealthBar then
2648 begin
2649 g_Monsters_DrawHealth();
2650 g_Player_DrawHealth();
2651 end;
2653 if p.FSpectator then
2654 e_TextureFontPrintEx(p.GameX + PLAYER_RECT_CX - 4,
2655 p.GameY + PLAYER_RECT_CY - 4,
2656 'X', gStdFont, 255, 255, 255, 1, True);
2658 for a := 0 to High(gCollideMap) do
2659 for b := 0 to High(gCollideMap[a]) do
2660 begin
2661 d := 0;
2662 if ByteBool(gCollideMap[a, b] and MARK_WALL) then
2663 d := d + 1;
2664 if ByteBool(gCollideMap[a, b] and MARK_DOOR) then
2665 d := d + 2;
2667 case d of
2668 1: e_DrawPoint(1, b, a, 200, 200, 200);
2669 2: e_DrawPoint(1, b, a, 64, 64, 255);
2670 3: e_DrawPoint(1, b, a, 255, 0, 255);
2671 end;
2672 end;
2675 glPopMatrix();
2677 p.DrawPain();
2678 p.DrawPickup();
2679 p.DrawRulez();
2680 if gShowMap then DrawMinimap(p, _TRect(0, 0, 128, 128));
2681 if g_Debug_Player then
2682 g_Player_DrawDebug(p);
2683 p.DrawGUI();
2684 end;
2686 procedure g_Game_Draw();
2687 var
2688 ID: DWORD;
2689 w, h: Word;
2690 ww, hh: Byte;
2691 Time: Int64;
2692 back: string;
2693 plView1, plView2: TPlayer;
2694 Split: Boolean;
2695 begin
2696 if gExit = EXIT_QUIT then Exit;
2698 Time := GetTimer() {div 1000};
2699 FPSCounter := FPSCounter+1;
2700 if Time - FPSTime >= 1000 then
2701 begin
2702 FPS := FPSCounter;
2703 FPSCounter := 0;
2704 FPSTime := Time;
2705 end;
2707 if gGameOn or (gState = STATE_FOLD) then
2708 begin
2709 if (gPlayer1 <> nil) and (gPlayer2 <> nil) then
2710 begin
2711 gSpectMode := SPECT_NONE;
2712 if not gRevertPlayers then
2713 begin
2714 plView1 := gPlayer1;
2715 plView2 := gPlayer2;
2716 end
2717 else
2718 begin
2719 plView1 := gPlayer2;
2720 plView2 := gPlayer1;
2721 end;
2722 end
2723 else
2724 if (gPlayer1 <> nil) or (gPlayer2 <> nil) then
2725 begin
2726 gSpectMode := SPECT_NONE;
2727 if gPlayer2 = nil then
2728 plView1 := gPlayer1
2729 else
2730 plView1 := gPlayer2;
2731 plView2 := nil;
2732 end
2733 else
2734 begin
2735 plView1 := nil;
2736 plView2 := nil;
2737 end;
2739 if (plView1 = nil) and (plView2 = nil) and (gSpectMode = SPECT_NONE) then
2740 gSpectMode := SPECT_STATS;
2742 if gSpectMode = SPECT_PLAYERS then
2743 if gPlayers <> nil then
2744 begin
2745 plView1 := GetActivePlayer_ByID(gSpectPID1);
2746 if plView1 = nil then
2747 begin
2748 gSpectPID1 := GetActivePlayerID_Next();
2749 plView1 := GetActivePlayer_ByID(gSpectPID1);
2750 end;
2751 if gSpectViewTwo then
2752 begin
2753 plView2 := GetActivePlayer_ByID(gSpectPID2);
2754 if plView2 = nil then
2755 begin
2756 gSpectPID2 := GetActivePlayerID_Next();
2757 plView2 := GetActivePlayer_ByID(gSpectPID2);
2758 end;
2759 end;
2760 end;
2762 if gSpectMode = SPECT_MAPVIEW then
2763 begin
2764 // Ðåæèì ïðîñìîòðà êàðòû
2765 Split := False;
2766 e_SetViewPort(0, 0, gScreenWidth, gScreenHeight);
2767 DrawMapView(gSpectX, gSpectY, gScreenWidth, gScreenHeight);
2768 gHearPoint1.Active := True;
2769 gHearPoint1.Coords.X := gScreenWidth div 2 + gSpectX;
2770 gHearPoint1.Coords.Y := gScreenHeight div 2 + gSpectY;
2771 gHearPoint2.Active := False;
2772 end
2773 else
2774 begin
2775 Split := (plView1 <> nil) and (plView2 <> nil);
2777 // Òî÷êè ñëóõà èãðîêîâ
2778 if plView1 <> nil then
2779 begin
2780 gHearPoint1.Active := True;
2781 gHearPoint1.Coords.X := plView1.GameX;
2782 gHearPoint1.Coords.Y := plView1.GameY;
2783 end else
2784 gHearPoint1.Active := False;
2785 if plView2 <> nil then
2786 begin
2787 gHearPoint2.Active := True;
2788 gHearPoint2.Coords.X := plView2.GameX;
2789 gHearPoint2.Coords.Y := plView2.GameY;
2790 end else
2791 gHearPoint2.Active := False;
2793 // Ðàçìåð ýêðàíîâ èãðîêîâ:
2794 gPlayerScreenSize.X := gScreenWidth-196;
2795 if Split then
2796 begin
2797 gPlayerScreenSize.Y := gScreenHeight div 2;
2798 if gScreenHeight mod 2 = 0 then
2799 Dec(gPlayerScreenSize.Y);
2800 end
2801 else
2802 gPlayerScreenSize.Y := gScreenHeight;
2804 if Split then
2805 if gScreenHeight mod 2 = 0 then
2806 e_SetViewPort(0, gPlayerScreenSize.Y+2, gPlayerScreenSize.X+196, gPlayerScreenSize.Y)
2807 else
2808 e_SetViewPort(0, gPlayerScreenSize.Y+1, gPlayerScreenSize.X+196, gPlayerScreenSize.Y);
2810 DrawPlayer(plView1);
2811 gPlayer1ScreenCoord.X := sX;
2812 gPlayer1ScreenCoord.Y := sY;
2814 if Split then
2815 begin
2816 e_SetViewPort(0, 0, gPlayerScreenSize.X+196, gPlayerScreenSize.Y);
2818 DrawPlayer(plView2);
2819 gPlayer2ScreenCoord.X := sX;
2820 gPlayer2ScreenCoord.Y := sY;
2821 end;
2823 e_SetViewPort(0, 0, gScreenWidth, gScreenHeight);
2825 if Split then
2826 e_DrawLine(2, 0, gScreenHeight div 2, gScreenWidth, gScreenHeight div 2, 0, 0, 0);
2827 end;
2829 if MessageText <> '' then
2830 begin
2831 w := 0;
2832 h := 0;
2833 e_CharFont_GetSizeFmt(gMenuFont, MessageText, w, h);
2834 if Split then
2835 e_CharFont_PrintFmt(gMenuFont, (gScreenWidth div 2)-(w div 2),
2836 (gScreenHeight div 2)-(h div 2), MessageText)
2837 else
2838 e_CharFont_PrintFmt(gMenuFont, (gScreenWidth div 2)-(w div 2),
2839 Round(gScreenHeight / 2.75)-(h div 2), MessageText);
2840 end;
2842 if IsDrawStat or (gSpectMode = 1) then DrawStat();
2844 if gSpectHUD and (not gChatShow) and (gSpectMode <> SPECT_NONE) then
2845 begin
2846 // Draw spectator GUI
2847 ww := 0;
2848 hh := 0;
2849 e_TextureFontGetSize(gStdFont, ww, hh);
2850 case gSpectMode of
2851 SPECT_STATS:
2852 e_TextureFontPrintEx(0, gScreenHeight - (hh+2)*2, 'MODE: Stats', gStdFont, 255, 255, 255, 1);
2853 SPECT_MAPVIEW:
2854 e_TextureFontPrintEx(0, gScreenHeight - (hh+2)*2, 'MODE: Observe Map', gStdFont, 255, 255, 255, 1);
2855 SPECT_PLAYERS:
2856 e_TextureFontPrintEx(0, gScreenHeight - (hh+2)*2, 'MODE: Watch Players', gStdFont, 255, 255, 255, 1);
2857 end;
2858 e_TextureFontPrintEx(2*ww, gScreenHeight - (hh+2), '< jump >', gStdFont, 255, 255, 255, 1);
2859 if gSpectMode = SPECT_MAPVIEW then
2860 begin
2861 e_TextureFontPrintEx(22*ww, gScreenHeight - (hh+2)*2, '[-]', gStdFont, 255, 255, 255, 1);
2862 e_TextureFontPrintEx(26*ww, gScreenHeight - (hh+2)*2, 'Step ' + IntToStr(gSpectStep), gStdFont, 255, 255, 255, 1);
2863 e_TextureFontPrintEx(34*ww, gScreenHeight - (hh+2)*2, '[+]', gStdFont, 255, 255, 255, 1);
2864 e_TextureFontPrintEx(18*ww, gScreenHeight - (hh+2), '<prev weap>', gStdFont, 255, 255, 255, 1);
2865 e_TextureFontPrintEx(30*ww, gScreenHeight - (hh+2), '<next weap>', gStdFont, 255, 255, 255, 1);
2866 end;
2867 if gSpectMode = SPECT_PLAYERS then
2868 begin
2869 e_TextureFontPrintEx(22*ww, gScreenHeight - (hh+2)*2, 'Player 1', gStdFont, 255, 255, 255, 1);
2870 e_TextureFontPrintEx(20*ww, gScreenHeight - (hh+2), '<left/right>', gStdFont, 255, 255, 255, 1);
2871 if gSpectViewTwo then
2872 begin
2873 e_TextureFontPrintEx(37*ww, gScreenHeight - (hh+2)*2, 'Player 2', gStdFont, 255, 255, 255, 1);
2874 e_TextureFontPrintEx(34*ww, gScreenHeight - (hh+2), '<prev w/next w>', gStdFont, 255, 255, 255, 1);
2875 e_TextureFontPrintEx(52*ww, gScreenHeight - (hh+2)*2, '2x View', gStdFont, 255, 255, 255, 1);
2876 e_TextureFontPrintEx(51*ww, gScreenHeight - (hh+2), '<up/down>', gStdFont, 255, 255, 255, 1);
2877 end
2878 else
2879 begin
2880 e_TextureFontPrintEx(35*ww, gScreenHeight - (hh+2)*2, '2x View', gStdFont, 255, 255, 255, 1);
2881 e_TextureFontPrintEx(34*ww, gScreenHeight - (hh+2), '<up/down>', gStdFont, 255, 255, 255, 1);
2882 end;
2883 end;
2884 end;
2885 end;
2887 if gPause and gGameOn and (g_ActiveWindow = nil) then
2888 begin
2889 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2891 e_CharFont_GetSize(gMenuFont, _lc[I_MENU_PAUSE], w, h);
2892 e_CharFont_Print(gMenuFont, (gScreenWidth div 2)-(w div 2),
2893 (gScreenHeight div 2)-(h div 2), _lc[I_MENU_PAUSE]);
2894 end;
2896 if not gGameOn then
2897 begin
2898 if (gState = STATE_MENU) then
2899 begin
2900 if ((g_ActiveWindow = nil) or (g_ActiveWindow.BackTexture = '')) then
2901 begin
2902 if g_Texture_Get('MENU_BACKGROUND', ID) then
2903 e_DrawSize(ID, 0, 0, 0, False, False, gScreenWidth, gScreenHeight)
2904 else e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
2905 end;
2906 if g_ActiveWindow <> nil then
2907 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2908 end;
2910 if gState = STATE_FOLD then
2911 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 0, 0, 0, EndingGameCounter);
2913 if gState = STATE_INTERCUSTOM then
2914 begin
2915 if gLastMap and (gGameSettings.GameMode = GM_COOP) then
2916 begin
2917 back := 'TEXTURE_endpic';
2918 if not g_Texture_Get(back, ID) then
2919 back := _lc[I_TEXTURE_ENDPIC];
2920 end
2921 else
2922 back := 'INTER';
2924 if g_Texture_Get(back, ID) then
2925 e_DrawSize(ID, 0, 0, 0, False, False, gScreenWidth, gScreenHeight)
2926 else
2927 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
2929 DrawCustomStat();
2931 if g_ActiveWindow <> nil then
2932 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2933 end;
2935 if gState = STATE_INTERSINGLE then
2936 begin
2937 if EndingGameCounter > 0 then
2938 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 0, 0, 0, EndingGameCounter)
2939 else
2940 begin
2941 back := 'INTER';
2943 if g_Texture_Get(back, ID) then
2944 e_DrawSize(ID, 0, 0, 0, False, False, gScreenWidth, gScreenHeight)
2945 else
2946 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
2948 DrawSingleStat();
2950 if g_ActiveWindow <> nil then
2951 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2952 end;
2953 end;
2955 if gState = STATE_ENDPIC then
2956 begin
2957 ID := DWORD(-1);
2958 if not g_Texture_Get('TEXTURE_endpic', ID) then
2959 g_Texture_Get(_lc[I_TEXTURE_ENDPIC], ID);
2961 if ID <> DWORD(-1) then
2962 e_DrawSize(ID, 0, 0, 0, False, False, gScreenWidth, gScreenHeight)
2963 else
2964 e_Clear(GL_COLOR_BUFFER_BIT, 0, 0, 0);
2966 if g_ActiveWindow <> nil then
2967 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2968 end;
2970 if gState = STATE_SLIST then
2971 begin
2972 if g_Texture_Get('MENU_BACKGROUND', ID) then
2973 begin
2974 e_DrawSize(ID, 0, 0, 0, False, False, gScreenWidth, gScreenHeight);
2975 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2976 end;
2977 g_Serverlist_Draw(slCurrent);
2978 end;
2979 end;
2981 if g_ActiveWindow <> nil then
2982 begin
2983 if gGameOn then
2984 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
2985 g_ActiveWindow.Draw();
2986 end;
2988 g_Console_Draw();
2990 if g_debug_Sounds and gGameOn then
2991 begin
2992 for w := 0 to High(e_SoundsArray) do
2993 for h := 0 to e_SoundsArray[w].nRefs do
2994 e_DrawPoint(1, w+100, h+100, 255, 0, 0);
2995 end;
2997 if gShowFPS then
2998 begin
2999 e_TextureFontPrint(0, 0, Format('FPS: %d', [FPS]), gStdFont);
3000 e_TextureFontPrint(0, 16, Format('UPS: %d', [UPS]), gStdFont);
3001 end;
3003 if gGameOn and gShowTime and (gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT]) then
3004 e_TextureFontPrint(gScreenWidth-72, 0,
3005 Format('%d:%.2d:%.2d', [gTime div 1000 div 3600, (gTime div 1000 div 60) mod 60, gTime div 1000 mod 60]),
3006 gStdFont);
3007 end;
3009 procedure g_Game_Quit();
3010 begin
3011 g_Game_StopAllSounds(True);
3012 gMusic.Free();
3013 g_Game_SaveOptions();
3014 g_Game_FreeData();
3015 g_PlayerModel_FreeData();
3016 g_Texture_DeleteAll();
3017 g_Frames_DeleteAll();
3018 g_Menu_Free();
3020 if NetInitDone then g_Net_Free;
3022 // Íàäî óäàëèòü êàðòó ïîñëå òåñòà:
3023 if gMapToDelete <> '' then
3024 g_Game_DeleteTestMap();
3026 gExit := EXIT_QUIT;
3027 PushExitEvent();
3028 end;
3030 procedure g_FatalError(Text: String);
3031 begin
3032 g_Console_Add(Format(_lc[I_FATAL_ERROR], [Text]), True);
3033 e_WriteLog(Format(_lc[I_FATAL_ERROR], [Text]), MSG_WARNING);
3035 gExit := EXIT_SIMPLE;
3036 end;
3038 procedure g_SimpleError(Text: String);
3039 begin
3040 g_Console_Add(Format(_lc[I_SIMPLE_ERROR], [Text]), True);
3041 e_WriteLog(Format(_lc[I_SIMPLE_ERROR], [Text]), MSG_WARNING);
3042 end;
3044 procedure g_Game_SetupScreenSize();
3045 var
3046 d: Single;
3047 begin
3048 // Ðàçìåð ýêðàíîâ èãðîêîâ:
3049 gPlayerScreenSize.X := gScreenWidth-196;
3050 if (gPlayer1 <> nil) and (gPlayer2 <> nil) then
3051 gPlayerScreenSize.Y := gScreenHeight div 2
3052 else
3053 gPlayerScreenSize.Y := gScreenHeight;
3055 // Ðàçìåð çàäíåãî ïëàíà:
3056 if BackID <> DWORD(-1) then
3057 begin
3058 d := SKY_STRETCH;
3060 if (gScreenWidth*d > gMapInfo.Width) or
3061 (gScreenHeight*d > gMapInfo.Height) then
3062 d := 1.0;
3064 gBackSize.X := Round(gScreenWidth*d);
3065 gBackSize.Y := Round(gScreenHeight*d);
3066 end;
3067 end;
3069 procedure g_Game_ChangeResolution(newWidth, newHeight: Word; nowFull, nowMax: Boolean);
3070 begin
3071 g_Window_SetSize(newWidth, newHeight, nowFull);
3072 end;
3074 procedure g_Game_AddPlayer(Team: Byte = TEAM_NONE);
3075 begin
3076 if ((not gGameOn) and (gState <> STATE_INTERCUSTOM))
3077 or (not (gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT])) then
3078 Exit;
3079 if gPlayer1 = nil then
3080 begin
3081 if g_Game_IsClient then
3082 begin
3083 if NetPlrUID1 > -1 then
3084 begin
3085 MC_SEND_CheatRequest(NET_CHEAT_SPECTATE);
3086 gPlayer1 := g_Player_Get(NetPlrUID1);
3087 end;
3088 Exit;
3089 end;
3091 if not (Team in [TEAM_RED, TEAM_BLUE]) then
3092 Team := gPlayer1Settings.Team;
3094 // Ñîçäàíèå ïåðâîãî èãðîêà:
3095 gPlayer1 := g_Player_Get(g_Player_Create(gPlayer1Settings.Model,
3096 gPlayer1Settings.Color,
3097 Team, False));
3098 if gPlayer1 = nil then
3099 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [1]))
3100 else
3101 begin
3102 gPlayer1.Name := gPlayer1Settings.Name;
3103 g_Console_Add(Format(_lc[I_PLAYER_JOIN], [gPlayer1.Name]), True);
3104 if g_Game_IsServer and g_Game_IsNet then
3105 MH_SEND_PlayerCreate(gPlayer1.UID);
3106 gPlayer1.Respawn(False, True);
3108 if g_Game_IsNet and NetUseMaster then
3109 g_Net_Slist_Update;
3110 end;
3112 Exit;
3113 end;
3114 if gPlayer2 = nil then
3115 begin
3116 if g_Game_IsClient then
3117 begin
3118 if NetPlrUID2 > -1 then
3119 gPlayer2 := g_Player_Get(NetPlrUID2);
3120 Exit;
3121 end;
3123 if not (Team in [TEAM_RED, TEAM_BLUE]) then
3124 Team := gPlayer2Settings.Team;
3126 // Ñîçäàíèå âòîðîãî èãðîêà:
3127 gPlayer2 := g_Player_Get(g_Player_Create(gPlayer2Settings.Model,
3128 gPlayer2Settings.Color,
3129 Team, False));
3130 if gPlayer2 = nil then
3131 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [2]))
3132 else
3133 begin
3134 gPlayer2.Name := gPlayer2Settings.Name;
3135 g_Console_Add(Format(_lc[I_PLAYER_JOIN], [gPlayer2.Name]), True);
3136 if g_Game_IsServer and g_Game_IsNet then
3137 MH_SEND_PlayerCreate(gPlayer2.UID);
3138 gPlayer2.Respawn(False, True);
3140 if g_Game_IsNet and NetUseMaster then
3141 g_Net_Slist_Update;
3142 end;
3144 Exit;
3145 end;
3146 end;
3148 procedure g_Game_RemovePlayer();
3149 var
3150 Pl: TPlayer;
3151 begin
3152 if ((not gGameOn) and (gState <> STATE_INTERCUSTOM))
3153 or (not (gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT])) then
3154 Exit;
3155 Pl := gPlayer2;
3156 if Pl <> nil then
3157 begin
3158 if g_Game_IsServer then
3159 begin
3160 Pl.Lives := 0;
3161 Pl.Kill(K_SIMPLEKILL, 0, HIT_DISCON);
3162 g_Console_Add(Format(_lc[I_PLAYER_LEAVE], [Pl.Name]), True);
3163 g_Player_Remove(Pl.UID);
3165 if g_Game_IsNet and NetUseMaster then
3166 g_Net_Slist_Update;
3167 end else
3168 gPlayer2 := nil;
3169 Exit;
3170 end;
3171 Pl := gPlayer1;
3172 if Pl <> nil then
3173 begin
3174 if g_Game_IsServer then
3175 begin
3176 Pl.Lives := 0;
3177 Pl.Kill(K_SIMPLEKILL, 0, HIT_DISCON);
3178 g_Console_Add(Format(_lc[I_PLAYER_LEAVE], [Pl.Name]), True);
3179 g_Player_Remove(Pl.UID);
3181 if g_Game_IsNet and NetUseMaster then
3182 g_Net_Slist_Update;
3183 end else
3184 begin
3185 gPlayer1 := nil;
3186 MC_SEND_CheatRequest(NET_CHEAT_SPECTATE);
3187 end;
3188 Exit;
3189 end;
3190 end;
3192 procedure g_Game_Spectate();
3193 begin
3194 g_Game_RemovePlayer();
3195 if gPlayer1 <> nil then
3196 g_Game_RemovePlayer();
3197 end;
3199 procedure g_Game_SpectateCenterView();
3200 begin
3201 gSpectX := Max(gMapInfo.Width div 2 - gScreenWidth div 2, 0);
3202 gSpectY := Max(gMapInfo.Height div 2 - gScreenHeight div 2, 0);
3203 end;
3205 procedure g_Game_StartSingle(Map: String; TwoPlayers: Boolean; nPlayers: Byte);
3206 var
3207 i, nPl: Integer;
3208 begin
3209 g_Game_Free();
3211 e_WriteLog('Starting singleplayer game...', MSG_NOTIFY);
3213 g_Game_ClearLoading();
3215 // Íàñòðîéêè èãðû:
3216 FillByte(gGameSettings, SizeOf(TGameSettings), 0);
3217 gAimLine := False;
3218 gShowMap := False;
3219 gGameSettings.GameType := GT_SINGLE;
3220 gGameSettings.MaxLives := 0;
3221 gGameSettings.Options := gGameSettings.Options + GAME_OPTION_ALLOWEXIT;
3222 gGameSettings.Options := gGameSettings.Options + GAME_OPTION_MONSTERS;
3223 gGameSettings.Options := gGameSettings.Options + GAME_OPTION_BOTVSMONSTER;
3224 gSwitchGameMode := GM_SINGLE;
3226 g_Game_ExecuteEvent('ongamestart');
3228 // Óñòàíîâêà ðàçìåðîâ îêîí èãðîêîâ:
3229 g_Game_SetupScreenSize();
3231 // Ñîçäàíèå ïåðâîãî èãðîêà:
3232 gPlayer1 := g_Player_Get(g_Player_Create(gPlayer1Settings.Model,
3233 gPlayer1Settings.Color,
3234 gPlayer1Settings.Team, False));
3235 if gPlayer1 = nil then
3236 begin
3237 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [1]));
3238 Exit;
3239 end;
3241 gPlayer1.Name := gPlayer1Settings.Name;
3242 nPl := 1;
3244 // Ñîçäàíèå âòîðîãî èãðîêà, åñëè åñòü:
3245 if TwoPlayers then
3246 begin
3247 gPlayer2 := g_Player_Get(g_Player_Create(gPlayer2Settings.Model,
3248 gPlayer2Settings.Color,
3249 gPlayer2Settings.Team, False));
3250 if gPlayer2 = nil then
3251 begin
3252 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [2]));
3253 Exit;
3254 end;
3256 gPlayer2.Name := gPlayer2Settings.Name;
3257 Inc(nPl);
3258 end;
3260 // Çàãðóçêà è çàïóñê êàðòû:
3261 if not g_Game_StartMap(MAP, True) then
3262 begin
3263 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [gGameSettings.WAD + ':\' + MAP]));
3264 Exit;
3265 end;
3267 // Íàñòðîéêè èãðîêîâ è áîòîâ:
3268 g_Player_Init();
3270 // Ñîçäàåì áîòîâ:
3271 for i := nPl+1 to nPlayers do
3272 g_Player_Create(STD_PLAYER_MODEL, _RGB(0, 0, 0), 0, True);
3273 end;
3275 procedure g_Game_StartCustom(Map: String; GameMode: Byte;
3276 TimeLimit, GoalLimit: Word;
3277 MaxLives: Byte;
3278 Options: LongWord; nPlayers: Byte);
3279 var
3280 i, nPl: Integer;
3281 begin
3282 g_Game_Free();
3284 e_WriteLog('Starting custom game...', MSG_NOTIFY);
3286 g_Game_ClearLoading();
3288 // Íàñòðîéêè èãðû:
3289 gGameSettings.GameType := GT_CUSTOM;
3290 gGameSettings.GameMode := GameMode;
3291 gSwitchGameMode := GameMode;
3292 gGameSettings.TimeLimit := TimeLimit;
3293 gGameSettings.GoalLimit := GoalLimit;
3294 gGameSettings.MaxLives := IfThen(GameMode = GM_CTF, 0, MaxLives);
3295 gGameSettings.Options := Options;
3297 gCoopTotalMonstersKilled := 0;
3298 gCoopTotalSecretsFound := 0;
3299 gCoopTotalMonsters := 0;
3300 gCoopTotalSecrets := 0;
3301 gAimLine := False;
3302 gShowMap := False;
3304 g_Game_ExecuteEvent('ongamestart');
3306 // Óñòàíîâêà ðàçìåðîâ îêîí èãðîêîâ:
3307 g_Game_SetupScreenSize();
3309 // Ðåæèì íàáëþäàòåëÿ:
3310 if nPlayers = 0 then
3311 begin
3312 gPlayer1 := nil;
3313 gPlayer2 := nil;
3314 end;
3316 nPl := 0;
3317 if nPlayers >= 1 then
3318 begin
3319 // Ñîçäàíèå ïåðâîãî èãðîêà:
3320 gPlayer1 := g_Player_Get(g_Player_Create(gPlayer1Settings.Model,
3321 gPlayer1Settings.Color,
3322 gPlayer1Settings.Team, False));
3323 if gPlayer1 = nil then
3324 begin
3325 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [1]));
3326 Exit;
3327 end;
3329 gPlayer1.Name := gPlayer1Settings.Name;
3330 Inc(nPl);
3331 end;
3333 if nPlayers >= 2 then
3334 begin
3335 // Ñîçäàíèå âòîðîãî èãðîêà:
3336 gPlayer2 := g_Player_Get(g_Player_Create(gPlayer2Settings.Model,
3337 gPlayer2Settings.Color,
3338 gPlayer2Settings.Team, False));
3339 if gPlayer2 = nil then
3340 begin
3341 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [2]));
3342 Exit;
3343 end;
3345 gPlayer2.Name := gPlayer2Settings.Name;
3346 Inc(nPl);
3347 end;
3349 // Çàãðóçêà è çàïóñê êàðòû:
3350 if not g_Game_StartMap(Map, True) then
3351 begin
3352 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Map]));
3353 Exit;
3354 end;
3356 // Íåò òî÷åê ïîÿâëåíèÿ:
3357 if (g_Map_GetPointCount(RESPAWNPOINT_PLAYER1) +
3358 g_Map_GetPointCount(RESPAWNPOINT_PLAYER2) +
3359 g_Map_GetPointCount(RESPAWNPOINT_DM) +
3360 g_Map_GetPointCount(RESPAWNPOINT_RED)+
3361 g_Map_GetPointCount(RESPAWNPOINT_BLUE)) < 1 then
3362 begin
3363 g_FatalError(_lc[I_GAME_ERROR_GET_SPAWN]);
3364 Exit;
3365 end;
3367 // Íàñòðîéêè èãðîêîâ è áîòîâ:
3368 g_Player_Init();
3370 // Ñîçäàåì áîòîâ:
3371 for i := nPl+1 to nPlayers do
3372 g_Player_Create(STD_PLAYER_MODEL, _RGB(0, 0, 0), 0, True);
3373 end;
3375 procedure g_Game_StartServer(Map: String; GameMode: Byte;
3376 TimeLimit, GoalLimit: Word; MaxLives: Byte;
3377 Options: LongWord; nPlayers: Byte;
3378 IPAddr: LongWord; Port: Word);
3379 begin
3380 g_Game_Free();
3382 e_WriteLog('Starting net game (server)...', MSG_NOTIFY);
3384 g_Game_ClearLoading();
3386 // Íàñòðîéêè èãðû:
3387 gGameSettings.GameType := GT_SERVER;
3388 gGameSettings.GameMode := GameMode;
3389 gSwitchGameMode := GameMode;
3390 gGameSettings.TimeLimit := TimeLimit;
3391 gGameSettings.GoalLimit := GoalLimit;
3392 gGameSettings.MaxLives := IfThen(GameMode = GM_CTF, 0, MaxLives);
3393 gGameSettings.Options := Options;
3395 gCoopTotalMonstersKilled := 0;
3396 gCoopTotalSecretsFound := 0;
3397 gCoopTotalMonsters := 0;
3398 gCoopTotalSecrets := 0;
3399 gAimLine := False;
3400 gShowMap := False;
3402 g_Game_ExecuteEvent('ongamestart');
3404 // Óñòàíîâêà ðàçìåðîâ îêíà èãðîêà
3405 g_Game_SetupScreenSize();
3407 // Ðåæèì íàáëþäàòåëÿ:
3408 if nPlayers = 0 then
3409 begin
3410 gPlayer1 := nil;
3411 gPlayer2 := nil;
3412 end;
3414 if nPlayers >= 1 then
3415 begin
3416 // Ñîçäàíèå ïåðâîãî èãðîêà:
3417 gPlayer1 := g_Player_Get(g_Player_Create(gPlayer1Settings.Model,
3418 gPlayer1Settings.Color,
3419 gPlayer1Settings.Team, False));
3420 if gPlayer1 = nil then
3421 begin
3422 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [1]));
3423 Exit;
3424 end;
3426 gPlayer1.Name := gPlayer1Settings.Name;
3427 end;
3429 if nPlayers >= 2 then
3430 begin
3431 // Ñîçäàíèå âòîðîãî èãðîêà:
3432 gPlayer2 := g_Player_Get(g_Player_Create(gPlayer2Settings.Model,
3433 gPlayer2Settings.Color,
3434 gPlayer2Settings.Team, False));
3435 if gPlayer2 = nil then
3436 begin
3437 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [2]));
3438 Exit;
3439 end;
3441 gPlayer2.Name := gPlayer2Settings.Name;
3442 end;
3444 // Ñòàðòóåì ñåðâåð
3445 if not g_Net_Host(IPAddr, Port, NetMaxClients) then
3446 begin
3447 g_FatalError(_lc[I_NET_MSG] + _lc[I_NET_ERR_HOST]);
3448 Exit;
3449 end;
3451 g_Net_Slist_Set(NetSlistIP, NetSlistPort);
3453 // Çàãðóçêà è çàïóñê êàðòû:
3454 if not g_Game_StartMap(Map, True) then
3455 begin
3456 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [Map]));
3457 Exit;
3458 end;
3460 // Íåò òî÷åê ïîÿâëåíèÿ:
3461 if (g_Map_GetPointCount(RESPAWNPOINT_PLAYER1) +
3462 g_Map_GetPointCount(RESPAWNPOINT_PLAYER2) +
3463 g_Map_GetPointCount(RESPAWNPOINT_DM) +
3464 g_Map_GetPointCount(RESPAWNPOINT_RED)+
3465 g_Map_GetPointCount(RESPAWNPOINT_BLUE)) < 1 then
3466 begin
3467 g_FatalError(_lc[I_GAME_ERROR_GET_SPAWN]);
3468 Exit;
3469 end;
3471 // Íàñòðîéêè èãðîêîâ è áîòîâ:
3472 g_Player_Init();
3474 NetState := NET_STATE_GAME;
3475 end;
3477 procedure g_Game_StartClient(Addr: String; Port: Word; PW: String);
3478 var
3479 Map: String;
3480 WadName: string;
3481 Ptr: Pointer;
3482 T: Cardinal;
3483 MID: Byte;
3484 State: Byte;
3485 OuterLoop: Boolean;
3486 newResPath: string;
3487 begin
3488 g_Game_Free();
3490 State := 0;
3491 e_WriteLog('Starting net game (client)...', MSG_NOTIFY);
3492 e_WriteLog('NET: Trying to connect to ' + Addr + ':' + IntToStr(Port) + '...', MSG_NOTIFY);
3494 g_Game_ClearLoading();
3496 // Íàñòðîéêè èãðû:
3497 gGameSettings.GameType := GT_CLIENT;
3499 gCoopTotalMonstersKilled := 0;
3500 gCoopTotalSecretsFound := 0;
3501 gCoopTotalMonsters := 0;
3502 gCoopTotalSecrets := 0;
3503 gAimLine := False;
3504 gShowMap := False;
3506 g_Game_ExecuteEvent('ongamestart');
3508 // Óñòàíîâêà ðàçìåðîâ îêîí èãðîêîâ:
3509 g_Game_SetupScreenSize();
3511 NetState := NET_STATE_AUTH;
3513 g_Game_SetLoadingText(_lc[I_LOAD_CONNECT], 0, False);
3514 // Ñòàðòóåì êëèåíò
3515 if not g_Net_Connect(Addr, Port) then
3516 begin
3517 g_FatalError(_lc[I_NET_MSG] + _lc[I_NET_ERR_CONN]);
3518 NetState := NET_STATE_NONE;
3519 Exit;
3520 end;
3522 g_Game_SetLoadingText(_lc[I_LOAD_SEND_INFO], 0, False);
3523 MC_SEND_Info(PW);
3524 g_Game_SetLoadingText(_lc[I_LOAD_WAIT_INFO], 0, False);
3526 OuterLoop := True;
3527 while OuterLoop do
3528 begin
3529 while (enet_host_service(NetHost, @NetEvent, 0) > 0) do
3530 begin
3531 if (NetEvent.kind = ENET_EVENT_TYPE_RECEIVE) then
3532 begin
3533 Ptr := NetEvent.packet^.data;
3534 e_Raw_Seek(0);
3536 MID := e_Raw_Read_Byte(Ptr);
3538 if (MID = NET_MSG_INFO) and (State = 0) then
3539 begin
3540 NetMyID := e_Raw_Read_Byte(Ptr);
3541 NetPlrUID1 := e_Raw_Read_Word(Ptr);
3543 WadName := e_Raw_Read_String(Ptr);
3544 Map := e_Raw_Read_String(Ptr);
3546 gWADHash := e_Raw_Read_MD5(Ptr);
3548 gGameSettings.GameMode := e_Raw_Read_Byte(Ptr);
3549 gSwitchGameMode := gGameSettings.GameMode;
3550 gGameSettings.GoalLimit := e_Raw_Read_Word(Ptr);
3551 gGameSettings.TimeLimit := e_Raw_Read_Word(Ptr);
3552 gGameSettings.MaxLives := e_Raw_Read_Byte(Ptr);
3553 gGameSettings.Options := e_Raw_Read_LongWord(Ptr);
3554 T := e_Raw_Read_LongWord(Ptr);
3556 newResPath := g_Res_SearchSameWAD(MapsDir, WadName, gWADHash);
3557 if newResPath = '' then
3558 begin
3559 g_Game_SetLoadingText(_lc[I_LOAD_DL_RES], 0, False);
3560 newResPath := g_Res_DownloadWAD(WadName);
3561 if newResPath = '' then
3562 begin
3563 g_FatalError(_lc[I_NET_ERR_HASH]);
3564 enet_packet_destroy(NetEvent.packet);
3565 NetState := NET_STATE_NONE;
3566 Exit;
3567 end;
3568 end;
3569 newResPath := ExtractRelativePath(MapsDir, newResPath);
3571 gPlayer1 := g_Player_Get(g_Player_Create(gPlayer1Settings.Model,
3572 gPlayer1Settings.Color,
3573 gPlayer1Settings.Team, False));
3575 if gPlayer1 = nil then
3576 begin
3577 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [1]));
3579 enet_packet_destroy(NetEvent.packet);
3580 NetState := NET_STATE_NONE;
3581 Exit;
3582 end;
3584 gPlayer1.Name := gPlayer1Settings.Name;
3585 gPlayer1.UID := NetPlrUID1;
3586 gPlayer1.Reset(True);
3588 if not g_Game_StartMap(newResPath + ':\' + Map, True) then
3589 begin
3590 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [WadName + ':\' + Map]));
3592 enet_packet_destroy(NetEvent.packet);
3593 NetState := NET_STATE_NONE;
3594 Exit;
3595 end;
3597 gTime := T;
3599 State := 1;
3600 OuterLoop := False;
3601 enet_packet_destroy(NetEvent.packet);
3602 break;
3603 end
3604 else
3605 enet_packet_destroy(NetEvent.packet);
3606 end
3607 else
3608 if (NetEvent.kind = ENET_EVENT_TYPE_DISCONNECT) then
3609 begin
3610 State := 0;
3611 if (NetEvent.data <= NET_DISC_MAX) then
3612 g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_ERR_CONN] + ' ' +
3613 _lc[TStrings_Locale(Cardinal(I_NET_DISC_NONE) + NetEvent.data)], True);
3614 OuterLoop := False;
3615 Break;
3616 end;
3617 end;
3619 ProcessLoading();
3621 e_PollInput();
3623 if e_KeyPressed(IK_ESCAPE) or e_KeyPressed(IK_SPACE) then
3624 begin
3625 State := 0;
3626 break;
3627 end;
3628 end;
3630 if State <> 1 then
3631 begin
3632 g_FatalError(_lc[I_NET_MSG] + _lc[I_NET_ERR_CONN]);
3633 NetState := NET_STATE_NONE;
3634 Exit;
3635 end;
3637 gLMSRespawn := LMS_RESPAWN_NONE;
3638 gLMSRespawnTime := 0;
3640 g_Player_Init();
3641 NetState := NET_STATE_GAME;
3642 MC_SEND_FullStateRequest;
3643 e_WriteLog('NET: Connection successful.', MSG_NOTIFY);
3644 end;
3646 procedure g_Game_SaveOptions();
3647 begin
3648 g_Options_Write_Video(GameDir+'/'+CONFIG_FILENAME);
3649 end;
3651 procedure g_Game_ChangeMap(MapPath: String);
3652 var
3653 Force: Boolean;
3654 begin
3655 g_Game_ClearLoading();
3657 Force := gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF];
3658 // Åñëè óðîâåíü çàâåðøèëñÿ ïî òðèããåðó Âûõîä, íå î÷èùàòü èíâåíòàðü
3659 if gExitByTrigger then
3660 begin
3661 Force := False;
3662 gExitByTrigger := False;
3663 end;
3664 if not g_Game_StartMap(MapPath, Force) then
3665 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [MapPath]));
3666 end;
3668 procedure g_Game_Restart();
3669 var
3670 Map: string;
3671 begin
3672 if g_Game_IsClient then
3673 Exit;
3674 map := g_ExtractFileName(gMapInfo.Map);
3676 MessageTime := 0;
3677 gGameOn := False;
3678 g_Game_ClearLoading();
3679 g_Game_StartMap(Map, True);
3680 end;
3682 function g_Game_StartMap(Map: String; Force: Boolean = False): Boolean;
3683 var
3684 NewWAD, ResName: String;
3685 I: Integer;
3686 begin
3687 g_Map_Free();
3688 g_Player_RemoveAllCorpses();
3690 if (not g_Game_IsClient) and
3691 (gSwitchGameMode <> gGameSettings.GameMode) and
3692 (gGameSettings.GameMode <> GM_SINGLE) then
3693 begin
3694 if gSwitchGameMode = GM_CTF then
3695 gGameSettings.MaxLives := 0;
3696 gGameSettings.GameMode := gSwitchGameMode;
3697 Force := True;
3698 end else
3699 gSwitchGameMode := gGameSettings.GameMode;
3701 g_Player_ResetTeams();
3703 if Pos(':\', Map) > 0 then
3704 begin
3705 NewWAD := g_ExtractWadName(Map);
3706 ResName := g_ExtractFileName(Map);
3707 if g_Game_IsServer then
3708 begin
3709 gWADHash := MD5File(MapsDir + NewWAD);
3710 g_Game_LoadWAD(NewWAD);
3711 end else
3712 // hash recieved in MC_RECV_GameEvent -> NET_EV_MAPSTART
3713 g_Game_ClientWAD(NewWAD, gWADHash);
3714 end else
3715 ResName := Map;
3717 Result := g_Map_Load(MapsDir + gGameSettings.WAD + ':\' + ResName);
3718 if Result then
3719 begin
3720 g_Player_ResetAll(Force or gLastMap, gGameSettings.GameType = GT_SINGLE);
3722 gState := STATE_NONE;
3723 g_ActiveWindow := nil;
3724 gGameOn := True;
3726 DisableCheats();
3727 ResetTimer();
3729 if gGameSettings.GameMode = GM_CTF then
3730 begin
3731 g_Map_ResetFlag(FLAG_RED);
3732 g_Map_ResetFlag(FLAG_BLUE);
3733 // CTF, à ôëàãîâ íåò:
3734 if not g_Map_HaveFlagPoints() then
3735 g_SimpleError(_lc[I_GAME_ERROR_CTF]);
3736 end;
3737 end
3738 else
3739 begin
3740 gState := STATE_MENU;
3741 gGameOn := False;
3742 end;
3744 gExit := 0;
3745 gPause := False;
3746 gTime := 0;
3747 NetTimeToUpdate := 1;
3748 NetTimeToReliable := 0;
3749 NetTimeToMaster := NetMasterRate;
3750 gLMSRespawn := LMS_RESPAWN_NONE;
3751 gLMSRespawnTime := 0;
3752 gMissionFailed := False;
3753 gNextMap := '';
3755 gCoopMonstersKilled := 0;
3756 gCoopSecretsFound := 0;
3758 gVoteInProgress := False;
3759 gVotePassed := False;
3760 gVoteCount := 0;
3761 gVoted := False;
3763 gStatsOff := False;
3765 if not gGameOn then Exit;
3767 g_Game_SpectateCenterView();
3769 if (gGameSettings.MaxLives > 0) and (gGameSettings.WarmupTime > 0) then
3770 begin
3771 gLMSRespawn := LMS_RESPAWN_WARMUP;
3772 gLMSRespawnTime := gTime + gGameSettings.WarmupTime*1000;
3773 gLMSSoftSpawn := True;
3774 if NetMode = NET_SERVER then
3775 MH_SEND_GameEvent(NET_EV_LMS_WARMUP, (gLMSRespawnTime - gTime) div 1000)
3776 else
3777 g_Console_Add(Format(_lc[I_MSG_WARMUP_START], [(gLMSRespawnTime - gTime) div 1000]), True);
3778 end;
3780 if NetMode = NET_SERVER then
3781 begin
3782 MH_SEND_GameEvent(NET_EV_MAPSTART, gGameSettings.GameMode, Map);
3784 // Ìàñòåðñåðâåð
3785 if NetUseMaster then
3786 begin
3787 if (NetMHost = nil) or (NetMPeer = nil) then
3788 if not g_Net_Slist_Connect then
3789 g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_SLIST_ERROR]);
3791 g_Net_Slist_Update;
3792 end;
3794 if NetClients <> nil then
3795 for I := 0 to High(NetClients) do
3796 if NetClients[I].Used then
3797 begin
3798 NetClients[I].Voted := False;
3799 if NetClients[I].RequestedFullUpdate then
3800 begin
3801 MH_SEND_Everything((NetClients[I].State = NET_STATE_AUTH), I);
3802 NetClients[I].RequestedFullUpdate := False;
3803 end;
3804 end;
3806 g_Net_UnbanNonPermHosts();
3807 end;
3809 if gLastMap then
3810 begin
3811 gCoopTotalMonstersKilled := 0;
3812 gCoopTotalSecretsFound := 0;
3813 gCoopTotalMonsters := 0;
3814 gCoopTotalSecrets := 0;
3815 gLastMap := False;
3816 end;
3818 g_Game_ExecuteEvent('onmapstart');
3819 end;
3821 procedure SetFirstLevel();
3822 begin
3823 gNextMap := '';
3825 MapList := g_Map_GetMapsList(MapsDir + gGameSettings.WAD);
3826 if MapList = nil then
3827 Exit;
3829 SortSArray(MapList);
3830 gNextMap := MapList[Low(MapList)];
3832 MapList := nil;
3833 end;
3835 procedure g_Game_ExitLevel(Map: Char16);
3836 begin
3837 gNextMap := Map;
3839 gCoopTotalMonstersKilled := gCoopTotalMonstersKilled + gCoopMonstersKilled;
3840 gCoopTotalSecretsFound := gCoopTotalSecretsFound + gCoopSecretsFound;
3841 gCoopTotalMonsters := gCoopTotalMonsters + gTotalMonsters;
3842 gCoopTotalSecrets := gCoopTotalSecrets + gSecretsCount;
3844 // Âûøëè â âûõîä â Îäèíî÷íîé èãðå:
3845 if gGameSettings.GameType = GT_SINGLE then
3846 gExit := EXIT_ENDLEVELSINGLE
3847 else // Âûøëè â âûõîä â Ñâîåé èãðå
3848 begin
3849 gExit := EXIT_ENDLEVELCUSTOM;
3850 if gGameSettings.GameMode = GM_COOP then
3851 g_Player_RememberAll;
3853 if not g_Map_Exist(MapsDir + gGameSettings.WAD + ':\' + gNextMap) then
3854 begin
3855 gLastMap := True;
3856 if gGameSettings.GameMode = GM_COOP then
3857 gStatsOff := True;
3859 gStatsPressed := True;
3860 gNextMap := 'MAP01';
3862 if not g_Map_Exist(MapsDir + gGameSettings.WAD + ':\' + gNextMap) then
3863 g_Game_NextLevel;
3865 if g_Game_IsNet then
3866 begin
3867 MH_SEND_GameStats();
3868 MH_SEND_CoopStats();
3869 end;
3870 end;
3871 end;
3872 end;
3874 procedure g_Game_RestartLevel();
3875 var
3876 Map: string;
3877 begin
3878 if gGameSettings.GameMode = GM_SINGLE then
3879 begin
3880 g_Game_Restart();
3881 Exit;
3882 end;
3883 gExit := EXIT_ENDLEVELCUSTOM;
3884 Map := g_ExtractFileName(gMapInfo.Map);
3885 gNextMap := Map;
3886 end;
3888 procedure g_Game_ClientWAD(NewWAD: String; WHash: TMD5Digest);
3889 var
3890 gWAD: String;
3891 begin
3892 if LowerCase(NewWAD) = LowerCase(gGameSettings.WAD) then
3893 Exit;
3894 if not g_Game_IsClient then
3895 Exit;
3896 gWAD := g_Res_SearchSameWAD(MapsDir, ExtractFileName(NewWAD), WHash);
3897 if gWAD = '' then
3898 begin
3899 g_Game_SetLoadingText(_lc[I_LOAD_DL_RES], 0, False);
3900 gWAD := g_Res_DownloadWAD(ExtractFileName(NewWAD));
3901 if gWAD = '' then
3902 begin
3903 g_Game_Free();
3904 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_WAD], [ExtractFileName(NewWAD)]));
3905 Exit;
3906 end;
3907 end;
3908 NewWAD := ExtractRelativePath(MapsDir, gWAD);
3909 g_Game_LoadWAD(NewWAD);
3910 end;
3912 procedure g_Game_RestartRound(NoMapRestart: Boolean = False);
3913 var
3914 i, n, nb, nr: Integer;
3915 begin
3916 if not g_Game_IsServer then Exit;
3917 if gLMSRespawn = LMS_RESPAWN_NONE then Exit;
3918 gLMSRespawn := LMS_RESPAWN_NONE;
3919 gLMSRespawnTime := 0;
3920 MessageTime := 0;
3922 if (gGameSettings.GameMode = GM_COOP) and not NoMapRestart then
3923 begin
3924 gMissionFailed := True;
3925 g_Game_RestartLevel;
3926 Exit;
3927 end;
3929 n := 0; nb := 0; nr := 0;
3930 for i := Low(gPlayers) to High(gPlayers) do
3931 if (gPlayers[i] <> nil) and
3932 ((not gPlayers[i].FSpectator) or gPlayers[i].FWantsInGame or
3933 (gPlayers[i] is TBot)) then
3934 begin
3935 Inc(n);
3936 if gPlayers[i].Team = TEAM_RED then Inc(nr)
3937 else if gPlayers[i].Team = TEAM_BLUE then Inc(nb)
3938 end;
3940 if (n < 2) or ((gGameSettings.GameMode = GM_TDM) and ((nr = 0) or (nb = 0))) then
3941 begin
3942 // wait a second until the fuckers finally decide to join
3943 gLMSRespawn := LMS_RESPAWN_WARMUP;
3944 gLMSRespawnTime := gTime + 1000;
3945 gLMSSoftSpawn := NoMapRestart;
3946 Exit;
3947 end;
3949 g_Player_RemoveAllCorpses;
3950 g_Game_Message(_lc[I_MESSAGE_LMS_START], 144);
3951 if g_Game_IsNet then
3952 MH_SEND_GameEvent(NET_EV_LMS_START);
3954 for i := Low(gPlayers) to High(gPlayers) do
3955 begin
3956 if gPlayers[i] = nil then continue;
3957 if gPlayers[i] is TBot then gPlayers[i].FWantsInGame := True;
3958 // don't touch normal spectators
3959 if gPlayers[i].FSpectator and not gPlayers[i].FWantsInGame then
3960 begin
3961 gPlayers[i].FNoRespawn := True;
3962 gPlayers[i].Lives := 0;
3963 if g_Game_IsNet then
3964 MH_SEND_PlayerStats(gPlayers[I].UID);
3965 continue;
3966 end;
3967 gPlayers[i].FNoRespawn := False;
3968 gPlayers[i].Lives := gGameSettings.MaxLives;
3969 gPlayers[i].Respawn(False, True);
3970 if gGameSettings.GameMode = GM_COOP then
3971 begin
3972 gPlayers[i].Frags := 0;
3973 gPlayers[i].RecallState;
3974 end;
3975 if (gPlayer1 = nil) and (gLMSPID1 > 0) then
3976 gPlayer1 := g_Player_Get(gLMSPID1);
3977 if (gPlayer2 = nil) and (gLMSPID2 > 0) then
3978 gPlayer2 := g_Player_Get(gLMSPID2);
3979 end;
3981 for i := Low(gItems) to High(gItems) do
3982 begin
3983 if gItems[i].Respawnable then
3984 begin
3985 gItems[i].QuietRespawn := True;
3986 gItems[i].RespawnTime := 0;
3987 end
3988 else
3989 begin
3990 g_Items_Remove(i);
3991 if g_Game_IsNet then MH_SEND_ItemDestroy(True, i);
3992 end;
3993 end;
3995 for i := Low(gMonsters) to High(gMonsters) do
3996 begin
3997 if (gMonsters[i] <> nil) and not gMonsters[i].FNoRespawn then
3998 gMonsters[i].Respawn;
3999 end;
4001 gLMSSoftSpawn := False;
4002 end;
4004 function g_Game_GetFirstMap(WAD: String): String;
4005 begin
4006 Result := '';
4008 MapList := g_Map_GetMapsList(WAD);
4009 if MapList = nil then
4010 Exit;
4012 SortSArray(MapList);
4013 Result := MapList[Low(MapList)];
4015 if not g_Map_Exist(WAD + ':\' + Result) then
4016 Result := '';
4018 MapList := nil;
4019 end;
4021 function g_Game_GetNextMap(): String;
4022 var
4023 I: Integer;
4024 Map: string;
4025 begin
4026 Result := '';
4028 MapList := g_Map_GetMapsList(MapsDir + gGameSettings.WAD);
4029 if MapList = nil then
4030 Exit;
4032 Map := g_ExtractFileName(gMapInfo.Map);
4034 SortSArray(MapList);
4035 MapIndex := -255;
4036 for I := Low(MapList) to High(MapList) do
4037 if Map = MapList[I] then
4038 begin
4039 MapIndex := I;
4040 Break;
4041 end;
4043 if MapIndex <> -255 then
4044 begin
4045 if MapIndex = High(MapList) then
4046 Result := MapList[Low(MapList)]
4047 else
4048 Result := MapList[MapIndex + 1];
4050 if not g_Map_Exist(MapsDir + gGameSettings.WAD + ':\' + Result) then Result := Map;
4051 end;
4053 MapList := nil;
4054 end;
4056 procedure g_Game_NextLevel();
4057 begin
4058 if gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF, GM_COOP] then
4059 gExit := EXIT_ENDLEVELCUSTOM
4060 else
4061 begin
4062 gExit := EXIT_ENDLEVELSINGLE;
4063 Exit;
4064 end;
4066 if gNextMap <> '' then Exit;
4067 gNextMap := g_Game_GetNextMap();
4068 end;
4070 function g_Game_IsTestMap(): Boolean;
4071 begin
4072 result := StrEquCI1251(TEST_MAP_NAME, g_ExtractFileName(gMapInfo.Map));
4073 end;
4075 procedure g_Game_DeleteTestMap();
4076 var
4077 a: Integer;
4078 MapName: Char16;
4079 WadName: string;
4081 WAD: TWADFile;
4082 MapList: SArray;
4083 time: Integer;
4085 begin
4086 a := Pos('.wad:\', gMapToDelete);
4087 if a = 0 then
4088 Exit;
4090 // Âûäåëÿåì èìÿ wad-ôàéëà è èìÿ êàðòû:
4091 WadName := Copy(gMapToDelete, 1, a + 3);
4092 Delete(gMapToDelete, 1, a + 5);
4093 gMapToDelete := UpperCase(gMapToDelete);
4094 MapName := '';
4095 CopyMemory(@MapName[0], @gMapToDelete[1], Min(16, Length(gMapToDelete)));
4098 // Èìÿ êàðòû íå ñòàíäàðòíîå òåñòîâîå:
4099 if MapName <> TEST_MAP_NAME then
4100 Exit;
4102 if not gTempDelete then
4103 begin
4104 time := g_GetFileTime(WadName);
4105 WAD := TWADFile.Create();
4107 // ×èòàåì Wad-ôàéë:
4108 if not WAD.ReadFile(WadName) then
4109 begin // Íåò òàêîãî WAD-ôàéëà
4110 WAD.Free();
4111 Exit;
4112 end;
4114 // Ñîñòàâëÿåì ñïèñîê êàðò è èùåì íóæíóþ:
4115 WAD.CreateImage();
4116 MapList := WAD.GetResourcesList('');
4118 if MapList <> nil then
4119 for a := 0 to High(MapList) do
4120 if MapList[a] = MapName then
4121 begin
4122 // Óäàëÿåì è ñîõðàíÿåì:
4123 WAD.RemoveResource('', MapName);
4124 WAD.SaveTo(WadName);
4125 Break;
4126 end;
4128 WAD.Free();
4129 g_SetFileTime(WadName, time);
4130 end else
4132 if gTempDelete then DeleteFile(WadName);
4133 end;
4135 procedure GameCVars(P: SArray);
4136 var
4137 a, b: Integer;
4138 stat: TPlayerStatArray;
4139 cmd, s: string;
4140 config: TConfig;
4141 begin
4142 stat := nil;
4143 cmd := LowerCase(P[0]);
4144 if cmd = 'r_showfps' then
4145 begin
4146 if (Length(P) > 1) and
4147 ((P[1] = '1') or (P[1] = '0')) then
4148 gShowFPS := (P[1][1] = '1');
4150 if gShowFPS then
4151 g_Console_Add(_lc[I_MSG_SHOW_FPS_ON])
4152 else
4153 g_Console_Add(_lc[I_MSG_SHOW_FPS_OFF]);
4154 end
4155 else if (cmd = 'g_friendlyfire') and not g_Game_IsClient then
4156 begin
4157 with gGameSettings do
4158 begin
4159 if (Length(P) > 1) and
4160 ((P[1] = '1') or (P[1] = '0')) then
4161 begin
4162 if (P[1][1] = '1') then
4163 Options := Options or GAME_OPTION_TEAMDAMAGE
4164 else
4165 Options := Options and (not GAME_OPTION_TEAMDAMAGE);
4166 end;
4168 if (LongBool(Options and GAME_OPTION_TEAMDAMAGE)) then
4169 g_Console_Add(_lc[I_MSG_FRIENDLY_FIRE_ON])
4170 else
4171 g_Console_Add(_lc[I_MSG_FRIENDLY_FIRE_OFF]);
4173 if g_Game_IsNet then MH_SEND_GameSettings;
4174 end;
4175 end
4176 else if (cmd = 'g_weaponstay') and not g_Game_IsClient then
4177 begin
4178 with gGameSettings do
4179 begin
4180 if (Length(P) > 1) and
4181 ((P[1] = '1') or (P[1] = '0')) then
4182 begin
4183 if (P[1][1] = '1') then
4184 Options := Options or GAME_OPTION_WEAPONSTAY
4185 else
4186 Options := Options and (not GAME_OPTION_WEAPONSTAY);
4187 end;
4189 if (LongBool(Options and GAME_OPTION_WEAPONSTAY)) then
4190 g_Console_Add(_lc[I_MSG_WEAPONSTAY_ON])
4191 else
4192 g_Console_Add(_lc[I_MSG_WEAPONSTAY_OFF]);
4194 if g_Game_IsNet then MH_SEND_GameSettings;
4195 end;
4196 end
4197 else if cmd = 'g_gamemode' then
4198 begin
4199 a := g_Game_TextToMode(P[1]);
4200 if a = GM_SINGLE then a := GM_COOP;
4201 if (Length(P) > 1) and (a <> GM_NONE) and (not g_Game_IsClient) then
4202 begin
4203 gSwitchGameMode := a;
4204 if (gGameOn and (gGameSettings.GameMode = GM_SINGLE)) or
4205 (gState = STATE_INTERSINGLE) then
4206 gSwitchGameMode := GM_SINGLE;
4207 if not gGameOn then
4208 gGameSettings.GameMode := gSwitchGameMode;
4209 end;
4210 if gSwitchGameMode = gGameSettings.GameMode then
4211 g_Console_Add(Format(_lc[I_MSG_GAMEMODE_CURRENT],
4212 [g_Game_ModeToText(gGameSettings.GameMode)]))
4213 else
4214 g_Console_Add(Format(_lc[I_MSG_GAMEMODE_CHANGE],
4215 [g_Game_ModeToText(gGameSettings.GameMode),
4216 g_Game_ModeToText(gSwitchGameMode)]));
4217 end
4218 else if (cmd = 'g_allow_exit') and not g_Game_IsClient then
4219 begin
4220 with gGameSettings do
4221 begin
4222 if (Length(P) > 1) and
4223 ((P[1] = '1') or (P[1] = '0')) then
4224 begin
4225 if (P[1][1] = '1') then
4226 Options := Options or GAME_OPTION_ALLOWEXIT
4227 else
4228 Options := Options and (not GAME_OPTION_ALLOWEXIT);
4229 end;
4231 if (LongBool(Options and GAME_OPTION_ALLOWEXIT)) then
4232 g_Console_Add(_lc[I_MSG_ALLOWEXIT_ON])
4233 else
4234 g_Console_Add(_lc[I_MSG_ALLOWEXIT_OFF]);
4235 g_Console_Add(_lc[I_MSG_ONMAPCHANGE]);
4237 if g_Game_IsNet then MH_SEND_GameSettings;
4238 end;
4239 end
4240 else if (cmd = 'g_allow_monsters') and not g_Game_IsClient then
4241 begin
4242 with gGameSettings do
4243 begin
4244 if (Length(P) > 1) and
4245 ((P[1] = '1') or (P[1] = '0')) then
4246 begin
4247 if (P[1][1] = '1') then
4248 Options := Options or GAME_OPTION_MONSTERS
4249 else
4250 Options := Options and (not GAME_OPTION_MONSTERS);
4251 end;
4253 if (LongBool(Options and GAME_OPTION_MONSTERS)) then
4254 g_Console_Add(_lc[I_MSG_ALLOWMON_ON])
4255 else
4256 g_Console_Add(_lc[I_MSG_ALLOWMON_OFF]);
4257 g_Console_Add(_lc[I_MSG_ONMAPCHANGE]);
4259 if g_Game_IsNet then MH_SEND_GameSettings;
4260 end;
4261 end
4262 else if (cmd = 'g_bot_vsplayers') and not g_Game_IsClient then
4263 begin
4264 with gGameSettings do
4265 begin
4266 if (Length(P) > 1) and
4267 ((P[1] = '1') or (P[1] = '0')) then
4268 begin
4269 if (P[1][1] = '1') then
4270 Options := Options or GAME_OPTION_BOTVSPLAYER
4271 else
4272 Options := Options and (not GAME_OPTION_BOTVSPLAYER);
4273 end;
4275 if (LongBool(Options and GAME_OPTION_BOTVSPLAYER)) then
4276 g_Console_Add(_lc[I_MSG_BOTSVSPLAYERS_ON])
4277 else
4278 g_Console_Add(_lc[I_MSG_BOTSVSPLAYERS_OFF]);
4280 if g_Game_IsNet then MH_SEND_GameSettings;
4281 end;
4282 end
4283 else if (cmd = 'g_bot_vsmonsters') and not g_Game_IsClient then
4284 begin
4285 with gGameSettings do
4286 begin
4287 if (Length(P) > 1) and
4288 ((P[1] = '1') or (P[1] = '0')) then
4289 begin
4290 if (P[1][1] = '1') then
4291 Options := Options or GAME_OPTION_BOTVSMONSTER
4292 else
4293 Options := Options and (not GAME_OPTION_BOTVSMONSTER);
4294 end;
4296 if (LongBool(Options and GAME_OPTION_BOTVSMONSTER)) then
4297 g_Console_Add(_lc[I_MSG_BOTSVSMONSTERS_ON])
4298 else
4299 g_Console_Add(_lc[I_MSG_BOTSVSMONSTERS_OFF]);
4301 if g_Game_IsNet then MH_SEND_GameSettings;
4302 end;
4303 end
4304 else if (cmd = 'g_warmuptime') and not g_Game_IsClient then
4305 begin
4306 if Length(P) > 1 then
4307 begin
4308 if StrToIntDef(P[1], gGameSettings.WarmupTime) = 0 then
4309 gGameSettings.WarmupTime := 30
4310 else
4311 gGameSettings.WarmupTime := StrToIntDef(P[1], gGameSettings.WarmupTime);
4312 end;
4314 g_Console_Add(Format(_lc[I_MSG_WARMUP],
4315 [gGameSettings.WarmupTime]));
4316 g_Console_Add(_lc[I_MSG_ONMAPCHANGE]);
4317 end
4318 else if cmd = 'net_interp' then
4319 begin
4320 if (Length(P) > 1) then
4321 NetInterpLevel := StrToIntDef(P[1], NetInterpLevel);
4323 g_Console_Add('net_interp = ' + IntToStr(NetInterpLevel));
4324 config := TConfig.CreateFile(GameDir+'/'+CONFIG_FILENAME);
4325 config.WriteInt('Client', 'InterpolationSteps', NetInterpLevel);
4326 config.SaveFile(GameDir+'/'+CONFIG_FILENAME);
4327 config.Free();
4328 end
4329 else if cmd = 'net_forceplayerupdate' then
4330 begin
4331 if (Length(P) > 1) and
4332 ((P[1] = '1') or (P[1] = '0')) then
4333 NetForcePlayerUpdate := (P[1][1] = '1');
4335 if NetForcePlayerUpdate then
4336 g_Console_Add('net_forceplayerupdate = 1')
4337 else
4338 g_Console_Add('net_forceplayerupdate = 0');
4339 config := TConfig.CreateFile(GameDir+'/'+CONFIG_FILENAME);
4340 config.WriteBool('Client', 'ForcePlayerUpdate', NetForcePlayerUpdate);
4341 config.SaveFile(GameDir+'/'+CONFIG_FILENAME);
4342 config.Free();
4343 end
4344 else if cmd = 'net_predictself' then
4345 begin
4346 if (Length(P) > 1) and
4347 ((P[1] = '1') or (P[1] = '0')) then
4348 NetPredictSelf := (P[1][1] = '1');
4350 if NetPredictSelf then
4351 g_Console_Add('net_predictself = 1')
4352 else
4353 g_Console_Add('net_predictself = 0');
4354 config := TConfig.CreateFile(GameDir+'/'+CONFIG_FILENAME);
4355 config.WriteBool('Client', 'PredictSelf', NetPredictSelf);
4356 config.SaveFile(GameDir+'/'+CONFIG_FILENAME);
4357 config.Free();
4358 end
4359 else if cmd = 'sv_name' then
4360 begin
4361 if (Length(P) > 1) and (Length(P[1]) > 0) then
4362 begin
4363 NetServerName := P[1];
4364 if Length(NetServerName) > 64 then
4365 SetLength(NetServerName, 64);
4366 if g_Game_IsServer and g_Game_IsNet and NetUseMaster then
4367 g_Net_Slist_Update;
4368 end;
4370 g_Console_Add(cmd + ' = "' + NetServerName + '"');
4371 end
4372 else if cmd = 'sv_passwd' then
4373 begin
4374 if (Length(P) > 1) and (Length(P[1]) > 0) then
4375 begin
4376 NetPassword := P[1];
4377 if Length(NetPassword) > 24 then
4378 SetLength(NetPassword, 24);
4379 if g_Game_IsServer and g_Game_IsNet and NetUseMaster then
4380 g_Net_Slist_Update;
4381 end;
4383 g_Console_Add(cmd + ' = "' + AnsiLowerCase(NetPassword) + '"');
4384 end
4385 else if cmd = 'sv_maxplrs' then
4386 begin
4387 if (Length(P) > 1) then
4388 begin
4389 NetMaxClients := Min(Max(StrToIntDef(P[1], NetMaxClients), 1), NET_MAXCLIENTS);
4390 if g_Game_IsServer and g_Game_IsNet then
4391 begin
4392 b := 0;
4393 for a := 0 to High(NetClients) do
4394 if NetClients[a].Used then
4395 begin
4396 Inc(b);
4397 if b > NetMaxClients then
4398 begin
4399 s := g_Player_Get(NetClients[a].Player).Name;
4400 enet_peer_disconnect(NetClients[a].Peer, NET_DISC_FULL);
4401 g_Console_Add(Format(_lc[I_PLAYER_KICK], [s]));
4402 MH_SEND_GameEvent(NET_EV_PLAYER_KICK, 0, s);
4403 end;
4404 end;
4405 if NetUseMaster then
4406 g_Net_Slist_Update;
4407 end;
4408 end;
4410 g_Console_Add(cmd + ' = ' + IntToStr(NetMaxClients));
4411 end
4412 else if cmd = 'sv_public' then
4413 begin
4414 if (Length(P) > 1) then
4415 begin
4416 NetUseMaster := StrToIntDef(P[1], Byte(NetUseMaster)) > 0;
4417 if g_Game_IsServer and g_Game_IsNet then
4418 if NetUseMaster then
4419 begin
4420 if NetMPeer = nil then
4421 if not g_Net_Slist_Connect() then
4422 g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_SLIST_ERROR]);
4423 g_Net_Slist_Update();
4424 end
4425 else
4426 if NetMPeer <> nil then
4427 g_Net_Slist_Disconnect();
4428 end;
4430 g_Console_Add(cmd + ' = ' + IntToStr(Byte(NetUseMaster)));
4431 end
4432 else if cmd = 'sv_intertime' then
4433 begin
4434 if (Length(P) > 1) then
4435 gDefInterTime := Min(Max(StrToIntDef(P[1], gDefInterTime), -1), 120);
4437 g_Console_Add(cmd + ' = ' + IntToStr(gDefInterTime));
4438 end
4439 else if cmd = 'p1_name' then
4440 begin
4441 if (Length(P) > 1) and gGameOn then
4442 begin
4443 if g_Game_IsClient then
4444 begin
4445 gPlayer1Settings.Name := b_Text_Unformat(P[1]);
4446 MC_SEND_PlayerSettings;
4447 end
4448 else
4449 if gPlayer1 <> nil then
4450 begin
4451 gPlayer1.Name := b_Text_Unformat(P[1]);
4452 if g_Game_IsNet then MH_SEND_PlayerSettings(gPlayer1.UID);
4453 end
4454 else
4455 gPlayer1Settings.Name := b_Text_Unformat(P[1]);
4456 end;
4457 end
4458 else if cmd = 'p2_name' then
4459 begin
4460 if (Length(P) > 1) and gGameOn then
4461 begin
4462 if g_Game_IsClient then
4463 begin
4464 gPlayer2Settings.Name := b_Text_Unformat(P[1]);
4465 MC_SEND_PlayerSettings;
4466 end
4467 else
4468 if gPlayer2 <> nil then
4469 begin
4470 gPlayer2.Name := b_Text_Unformat(P[1]);
4471 if g_Game_IsNet then MH_SEND_PlayerSettings(gPlayer2.UID);
4472 end
4473 else
4474 gPlayer2Settings.Name := b_Text_Unformat(P[1]);
4475 end;
4476 end
4477 else if cmd = 'p1_color' then
4478 begin
4479 if Length(P) > 3 then
4480 if g_Game_IsClient then
4481 begin
4482 gPlayer1Settings.Color := _RGB(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4483 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4484 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4485 MC_SEND_PlayerSettings;
4486 end
4487 else
4488 if gPlayer1 <> nil then
4489 begin
4490 gPlayer1.Model.SetColor(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4491 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4492 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4493 if g_Game_IsNet then MH_SEND_PlayerSettings(gPlayer1.UID);
4494 end
4495 else
4496 gPlayer1Settings.Color := _RGB(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4497 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4498 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4499 end
4500 else if (cmd = 'p2_color') and not g_Game_IsNet then
4501 begin
4502 if Length(P) > 3 then
4503 if g_Game_IsClient then
4504 begin
4505 gPlayer2Settings.Color := _RGB(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4506 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4507 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4508 MC_SEND_PlayerSettings;
4509 end
4510 else
4511 if gPlayer2 <> nil then
4512 begin
4513 gPlayer2.Model.SetColor(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4514 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4515 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4516 if g_Game_IsNet then MH_SEND_PlayerSettings(gPlayer2.UID);
4517 end
4518 else
4519 gPlayer2Settings.Color := _RGB(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4520 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4521 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4522 end
4523 else if gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT] then
4524 begin
4525 if cmd = 'r_showtime' then
4526 begin
4527 if (Length(P) > 1) and
4528 ((P[1] = '1') or (P[1] = '0')) then
4529 gShowTime := (P[1][1] = '1');
4531 if gShowTime then
4532 g_Console_Add(_lc[I_MSG_TIME_ON])
4533 else
4534 g_Console_Add(_lc[I_MSG_TIME_OFF]);
4535 end
4536 else if cmd = 'r_showscore' then
4537 begin
4538 if (Length(P) > 1) and
4539 ((P[1] = '1') or (P[1] = '0')) then
4540 gShowGoals := (P[1][1] = '1');
4542 if gShowGoals then
4543 g_Console_Add(_lc[I_MSG_SCORE_ON])
4544 else
4545 g_Console_Add(_lc[I_MSG_SCORE_OFF]);
4546 end
4547 else if cmd = 'r_showstat' then
4548 begin
4549 if (Length(P) > 1) and
4550 ((P[1] = '1') or (P[1] = '0')) then
4551 gShowStat := (P[1][1] = '1');
4553 if gShowStat then
4554 g_Console_Add(_lc[I_MSG_STATS_ON])
4555 else
4556 g_Console_Add(_lc[I_MSG_STATS_OFF]);
4557 end
4558 else if cmd = 'r_showkillmsg' then
4559 begin
4560 if (Length(P) > 1) and
4561 ((P[1] = '1') or (P[1] = '0')) then
4562 gShowKillMsg := (P[1][1] = '1');
4564 if gShowKillMsg then
4565 g_Console_Add(_lc[I_MSG_KILL_MSGS_ON])
4566 else
4567 g_Console_Add(_lc[I_MSG_KILL_MSGS_OFF]);
4568 end
4569 else if cmd = 'r_showlives' then
4570 begin
4571 if (Length(P) > 1) and
4572 ((P[1] = '1') or (P[1] = '0')) then
4573 gShowLives := (P[1][1] = '1');
4575 if gShowLives then
4576 g_Console_Add(_lc[I_MSG_LIVES_ON])
4577 else
4578 g_Console_Add(_lc[I_MSG_LIVES_OFF]);
4579 end
4580 else if cmd = 'r_showspect' then
4581 begin
4582 if (Length(P) > 1) and
4583 ((P[1] = '1') or (P[1] = '0')) then
4584 gSpectHUD := (P[1][1] = '1');
4586 if gSpectHUD then
4587 g_Console_Add(_lc[I_MSG_SPECT_HUD_ON])
4588 else
4589 g_Console_Add(_lc[I_MSG_SPECT_HUD_OFF]);
4590 end
4591 else if cmd = 'r_showping' then
4592 begin
4593 if (Length(P) > 1) and
4594 ((P[1] = '1') or (P[1] = '0')) then
4595 gShowPing := (P[1][1] = '1');
4597 if gShowPing then
4598 g_Console_Add(_lc[I_MSG_PING_ON])
4599 else
4600 g_Console_Add(_lc[I_MSG_PING_OFF]);
4601 end
4602 else if (cmd = 'g_scorelimit') and not g_Game_IsClient then
4603 begin
4604 if Length(P) > 1 then
4605 begin
4606 if StrToIntDef(P[1], gGameSettings.GoalLimit) = 0 then
4607 gGameSettings.GoalLimit := 0
4608 else
4609 begin
4610 b := 0;
4612 if gGameSettings.GameMode = GM_DM then
4613 begin // DM
4614 stat := g_Player_GetStats();
4615 if stat <> nil then
4616 for a := 0 to High(stat) do
4617 if stat[a].Frags > b then
4618 b := stat[a].Frags;
4619 end
4620 else // TDM/CTF
4621 b := Max(gTeamStat[TEAM_RED].Goals, gTeamStat[TEAM_BLUE].Goals);
4623 gGameSettings.GoalLimit := Max(StrToIntDef(P[1], gGameSettings.GoalLimit), b);
4624 end;
4626 if g_Game_IsNet then MH_SEND_GameSettings;
4627 end;
4629 g_Console_Add(Format(_lc[I_MSG_SCORE_LIMIT], [gGameSettings.GoalLimit]));
4630 end
4631 else if (cmd = 'g_timelimit') and not g_Game_IsClient then
4632 begin
4633 if (Length(P) > 1) and (StrToIntDef(P[1], -1) >= 0) then
4634 gGameSettings.TimeLimit := StrToIntDef(P[1], -1);
4636 g_Console_Add(Format(_lc[I_MSG_TIME_LIMIT],
4637 [gGameSettings.TimeLimit div 3600,
4638 (gGameSettings.TimeLimit div 60) mod 60,
4639 gGameSettings.TimeLimit mod 60]));
4640 if g_Game_IsNet then MH_SEND_GameSettings;
4641 end
4642 else if (cmd = 'g_maxlives') and not g_Game_IsClient then
4643 begin
4644 if Length(P) > 1 then
4645 begin
4646 if StrToIntDef(P[1], gGameSettings.MaxLives) = 0 then
4647 gGameSettings.MaxLives := 0
4648 else
4649 begin
4650 b := 0;
4651 stat := g_Player_GetStats();
4652 if stat <> nil then
4653 for a := 0 to High(stat) do
4654 if stat[a].Lives > b then
4655 b := stat[a].Lives;
4656 gGameSettings.MaxLives :=
4657 Max(StrToIntDef(P[1], gGameSettings.MaxLives), b);
4658 end;
4659 end;
4661 g_Console_Add(Format(_lc[I_MSG_LIVES],
4662 [gGameSettings.MaxLives]));
4663 if g_Game_IsNet then MH_SEND_GameSettings;
4664 end;
4665 end;
4666 end;
4668 procedure DebugCommands(P: SArray);
4669 var
4670 a, b: Integer;
4671 cmd: string;
4672 //pt: TPoint;
4673 begin
4674 // Êîìàíäû îòëàäî÷íîãî ðåæèìà:
4675 if gDebugMode then
4676 begin
4677 cmd := LowerCase(P[0]);
4678 if cmd = 'd_window' then
4679 begin
4680 g_Console_Add(Format('gWinPosX = %d, gWinPosY %d', [gWinPosX, gWinPosY]));
4681 g_Console_Add(Format('gWinRealPosX = %d, gWinRealPosY %d', [gWinRealPosX, gWinRealPosY]));
4682 g_Console_Add(Format('gScreenWidth = %d, gScreenHeight = %d', [gScreenWidth, gScreenHeight]));
4683 g_Console_Add(Format('gWinSizeX = %d, gWinSizeY = %d', [gWinSizeX, gWinSizeY]));
4684 g_Console_Add(Format('Frame X = %d, Y = %d, Caption Y = %d', [gWinFrameX, gWinFrameY, gWinCaption]));
4685 end
4686 else if cmd = 'd_sounds' then
4687 begin
4688 if (Length(P) > 1) and
4689 ((P[1] = '1') or (P[1] = '0')) then
4690 g_Debug_Sounds := (P[1][1] = '1');
4692 g_Console_Add(Format('d_sounds is %d', [Byte(g_Debug_Sounds)]));
4693 end
4694 else if cmd = 'd_frames' then
4695 begin
4696 if (Length(P) > 1) and
4697 ((P[1] = '1') or (P[1] = '0')) then
4698 g_Debug_Frames := (P[1][1] = '1');
4700 g_Console_Add(Format('d_frames is %d', [Byte(g_Debug_Frames)]));
4701 end
4702 else if cmd = 'd_winmsg' then
4703 begin
4704 if (Length(P) > 1) and
4705 ((P[1] = '1') or (P[1] = '0')) then
4706 g_Debug_WinMsgs := (P[1][1] = '1');
4708 g_Console_Add(Format('d_winmsg is %d', [Byte(g_Debug_WinMsgs)]));
4709 end
4710 else if (cmd = 'd_monoff') and not g_Game_IsNet then
4711 begin
4712 if (Length(P) > 1) and
4713 ((P[1] = '1') or (P[1] = '0')) then
4714 g_Debug_MonsterOff := (P[1][1] = '1');
4716 g_Console_Add(Format('d_monoff is %d', [Byte(g_debug_MonsterOff)]));
4717 end
4718 else if (cmd = 'd_botoff') and not g_Game_IsNet then
4719 begin
4720 if Length(P) > 1 then
4721 case P[1][1] of
4722 '0': g_debug_BotAIOff := 0;
4723 '1': g_debug_BotAIOff := 1;
4724 '2': g_debug_BotAIOff := 2;
4725 '3': g_debug_BotAIOff := 3;
4726 end;
4728 g_Console_Add(Format('d_botoff is %d', [g_debug_BotAIOff]));
4729 end
4730 else if cmd = 'd_monster' then
4731 begin
4732 if gGameOn and (gPlayer1 <> nil) and (gPlayer1.Live) and (not g_Game_IsNet) then
4733 if Length(P) < 2 then
4734 begin
4735 g_Console_Add(cmd + ' [ID | Name] [behaviour]');
4736 g_Console_Add('ID | Name');
4737 for b := MONSTER_DEMON to MONSTER_MAN do
4738 g_Console_Add(Format('%2d | %s', [b, g_Monsters_GetNameByID(b)]));
4739 end else
4740 begin
4741 a := StrToIntDef(P[1], 0);
4742 if (a < MONSTER_DEMON) or (a > MONSTER_MAN) then
4743 a := g_Monsters_GetIDByName(P[1]);
4745 if (a < MONSTER_DEMON) or (a > MONSTER_MAN) then
4746 g_Console_Add(Format(_lc[I_MSG_NO_MONSTER], [P[1]]))
4747 else
4748 begin
4749 with gPlayer1.Obj do
4750 b := g_Monsters_Create(a,
4751 X + Rect.X + (Rect.Width div 2),
4752 Y + Rect.Y + Rect.Height,
4753 gPlayer1.Direction, True);
4754 if (Length(P) > 2) and (b >= 0) then
4755 gMonsters[b].MonsterBehaviour := Min(Max(StrToIntDef(P[2], BH_NORMAL), BH_NORMAL), BH_GOOD);
4756 end;
4757 end;
4758 end
4759 else if (cmd = 'd_health') then
4760 begin
4761 if (Length(P) > 1) and
4762 ((P[1] = '1') or (P[1] = '0')) then
4763 g_debug_HealthBar := (P[1][1] = '1');
4765 g_Console_Add(Format('d_health is %d', [Byte(g_debug_HealthBar)]));
4766 end
4767 else if (cmd = 'd_player') then
4768 begin
4769 if (Length(P) > 1) and
4770 ((P[1] = '1') or (P[1] = '0')) then
4771 g_debug_Player := (P[1][1] = '1');
4773 g_Console_Add(Format(cmd + ' is %d', [Byte(g_Debug_Player)]));
4774 end
4775 else if (cmd = 'd_joy') then
4776 begin
4777 for a := 1 to 8 do
4778 g_Console_Add(e_JoystickStateToString(a));
4779 end;
4780 end
4781 else
4782 g_Console_Add(_lc[I_MSG_NOT_DEBUG]);
4783 end;
4786 procedure GameCheats(P: SArray);
4787 var
4788 cmd: string;
4789 f, a: Integer;
4790 plr: TPlayer;
4791 begin
4792 if (not gGameOn) or (not gCheats) or ((gGameSettings.GameType <> GT_SINGLE) and
4793 (gGameSettings.GameMode <> GM_COOP) and (not gDebugMode)) or g_Game_IsNet then
4794 begin
4795 g_Console_Add('not available');
4796 exit;
4797 end;
4798 plr := gPlayer1;
4799 if plr = nil then
4800 begin
4801 g_Console_Add('where is the player?!');
4802 exit;
4803 end;
4804 cmd := LowerCase(P[0]);
4805 // god
4806 if cmd = 'god' then
4807 begin
4808 plr.GodMode := not plr.GodMode;
4809 if plr.GodMode then g_Console_Add('player is godlike now') else g_Console_Add('player is mortal now');
4810 exit;
4811 end;
4812 // give <health|exit|weapons|air|suit|jetpack|berserk|all>
4813 if cmd = 'give' then
4814 begin
4815 if length(P) < 2 then begin g_Console_Add('give what?!'); exit; end;
4816 for f := 1 to High(P) do
4817 begin
4818 cmd := LowerCase(P[f]);
4819 if cmd = 'health' then begin plr.RestoreHealthArmor(); g_Console_Add('player feels himself better'); continue; end;
4820 if (cmd = 'all') {or (cmd = 'weapons')} then begin plr.AllRulez(False); g_Console_Add('player got the gifts'); continue; end;
4821 if cmd = 'exit' then
4822 begin
4823 if gTriggers <> nil then
4824 begin
4825 for a := 0 to High(gTriggers) do
4826 begin
4827 if gTriggers[a].TriggerType = TRIGGER_EXIT then
4828 begin
4829 g_Console_Add('player left the map');
4830 gExitByTrigger := True;
4831 g_Game_ExitLevel(gTriggers[a].Data.MapName);
4832 break;
4833 end;
4834 end;
4835 end;
4836 continue;
4837 end;
4839 if cmd = 'air' then begin plr.GiveItem(ITEM_OXYGEN); g_Console_Add('player got some air'); continue; end;
4840 if cmd = 'jetpack' then begin plr.GiveItem(ITEM_JETPACK); g_Console_Add('player got a jetpack'); continue; end;
4841 if cmd = 'suit' then begin plr.GiveItem(ITEM_SUIT); g_Console_Add('player got an envirosuit'); continue; end;
4842 if cmd = 'berserk' then begin plr.GiveItem(ITEM_MEDKIT_BLACK); g_Console_Add('player got a berserk pack'); continue; end;
4843 if cmd = 'backpack' then begin plr.GiveItem(ITEM_AMMO_BACKPACK); g_Console_Add('player got a backpack'); continue; end;
4845 if cmd = 'helmet' then begin plr.GiveItem(ITEM_HELMET); g_Console_Add('player got a helmet'); continue; end;
4846 if cmd = 'bottle' then begin plr.GiveItem(ITEM_BOTTLE); g_Console_Add('player got a bottle of health'); continue; end;
4848 if cmd = 'stimpack' then begin plr.GiveItem(ITEM_MEDKIT_SMALL); g_Console_Add('player got a stimpack'); continue; end;
4849 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;
4851 if cmd = 'greenarmor' then begin plr.GiveItem(ITEM_ARMOR_GREEN); g_Console_Add('player got a security armor'); continue; end;
4852 if cmd = 'bluearmor' then begin plr.GiveItem(ITEM_ARMOR_BLUE); g_Console_Add('player got a combat armor'); continue; end;
4854 if (cmd = 'megasphere') or (cmd = 'mega') then begin plr.GiveItem(ITEM_SPHERE_BLUE); g_Console_Add('player got a megasphere'); continue; end;
4855 if (cmd = 'soulsphere') or (cmd = 'soul')then begin plr.GiveItem(ITEM_SPHERE_WHITE); g_Console_Add('player got a soul sphere'); continue; end;
4857 if (cmd = 'invul') or (cmd = 'invulnerability') then begin plr.GiveItem(ITEM_INVUL); g_Console_Add('player got invulnerability'); continue; end;
4858 if (cmd = 'invis') or (cmd = 'invisibility') then begin plr.GiveItem(ITEM_INVIS); g_Console_Add('player got invisibility'); continue; end;
4860 if cmd = 'redkey' then begin plr.GiveItem(ITEM_KEY_RED); g_Console_Add('player got the red key'); continue; end;
4861 if cmd = 'greenkey' then begin plr.GiveItem(ITEM_KEY_GREEN); g_Console_Add('player got the green key'); continue; end;
4862 if cmd = 'bluekey' then begin plr.GiveItem(ITEM_KEY_BLUE); g_Console_Add('player got the blue key'); continue; end;
4864 if (cmd = 'shotgun') or (cmd = 'sg') then begin plr.GiveItem(ITEM_WEAPON_SHOTGUN1); g_Console_Add('player got a shotgun'); continue; end;
4865 if (cmd = 'supershotgun') or (cmd = 'ssg') then begin plr.GiveItem(ITEM_WEAPON_SHOTGUN2); g_Console_Add('player got a supershotgun'); continue; end;
4866 if cmd = 'chaingun' then begin plr.GiveItem(ITEM_WEAPON_CHAINGUN); g_Console_Add('player got a chaingun'); continue; end;
4867 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;
4868 if cmd = 'plasmagun' then begin plr.GiveItem(ITEM_WEAPON_PLASMA); g_Console_Add('player got a plasma gun'); continue; end;
4869 if cmd = 'bfg' then begin plr.GiveItem(ITEM_WEAPON_BFG); g_Console_Add('player got a BFG-9000'); continue; end;
4871 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;
4872 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;
4873 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;
4874 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;
4875 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;
4876 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;
4878 if cmd = 'superchaingun' then begin plr.GiveItem(ITEM_WEAPON_SUPERPULEMET); g_Console_Add('player got a superchaingun'); continue; end;
4879 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;
4881 if cmd = 'chainsaw' then begin plr.GiveItem(ITEM_WEAPON_SAW); g_Console_Add('player got a chainsaw'); continue; end;
4883 if cmd = 'ammo' then
4884 begin
4885 plr.GiveItem(ITEM_AMMO_SHELLS_BOX);
4886 plr.GiveItem(ITEM_AMMO_BULLETS_BOX);
4887 plr.GiveItem(ITEM_AMMO_CELL_BIG);
4888 plr.GiveItem(ITEM_AMMO_ROCKET_BOX);
4889 g_Console_Add('player got some ammo');
4890 continue;
4891 end;
4893 if cmd = 'clip' then begin plr.GiveItem(ITEM_AMMO_BULLETS); g_Console_Add('player got some bullets'); continue; end;
4894 if cmd = 'bullets' then begin plr.GiveItem(ITEM_AMMO_BULLETS_BOX); g_Console_Add('player got a box of bullets'); continue; end;
4896 if cmd = 'shells' then begin plr.GiveItem(ITEM_AMMO_SHELLS); g_Console_Add('player got some shells'); continue; end;
4897 if cmd = 'shellbox' then begin plr.GiveItem(ITEM_AMMO_SHELLS_BOX); g_Console_Add('player got a box of shells'); continue; end;
4899 if cmd = 'cells' then begin plr.GiveItem(ITEM_AMMO_CELL); g_Console_Add('player got some cells'); continue; end;
4900 if cmd = 'battery' then begin plr.GiveItem(ITEM_AMMO_CELL_BIG); g_Console_Add('player got cell battery'); continue; end;
4902 if cmd = 'rocket' then begin plr.GiveItem(ITEM_AMMO_ROCKET); g_Console_Add('player got a rocket'); continue; end;
4903 if cmd = 'rocketbox' then begin plr.GiveItem(ITEM_AMMO_ROCKET_BOX); g_Console_Add('player got some rockets'); continue; end;
4905 if cmd = 'weapons' then
4906 begin
4907 plr.GiveItem(ITEM_WEAPON_SHOTGUN1);
4908 plr.GiveItem(ITEM_WEAPON_SHOTGUN2);
4909 plr.GiveItem(ITEM_WEAPON_CHAINGUN);
4910 plr.GiveItem(ITEM_WEAPON_ROCKETLAUNCHER);
4911 plr.GiveItem(ITEM_WEAPON_PLASMA);
4912 plr.GiveItem(ITEM_WEAPON_BFG);
4913 g_Console_Add('player got weapons');
4914 continue;
4915 end;
4917 if cmd = 'keys' then
4918 begin
4919 plr.GiveItem(ITEM_KEY_RED);
4920 plr.GiveItem(ITEM_KEY_GREEN);
4921 plr.GiveItem(ITEM_KEY_BLUE);
4922 g_Console_Add('player got all keys');
4923 continue;
4924 end;
4926 g_Console_Add('i don''t know how to give '''+cmd+'''!');
4927 end;
4928 exit;
4929 end;
4930 // open
4931 if cmd = 'open' then
4932 begin
4933 g_Console_Add('player activated sesame');
4934 g_Triggers_OpenAll();
4935 exit;
4936 end;
4937 // fly
4938 if cmd = 'fly' then
4939 begin
4940 gFly := not gFly;
4941 if gFly then g_Console_Add('player feels himself lighter') else g_Console_Add('player lost his wings');
4942 exit;
4943 end;
4944 // noclip
4945 if cmd = 'noclip' then
4946 begin
4947 plr.SwitchNoClip;
4948 g_Console_Add('wall hardeness adjusted');
4949 exit;
4950 end;
4951 // notarget
4952 if cmd = 'notarget' then
4953 begin
4954 plr.NoTarget := not plr.NoTarget;
4955 if plr.NoTarget then g_Console_Add('player hides in shadows') else g_Console_Add('player is brave again');
4956 exit;
4957 end;
4958 // noreload
4959 if cmd = 'noreload' then
4960 begin
4961 plr.NoReload := not plr.NoReload;
4962 if plr.NoReload then g_Console_Add('player is action hero now') else g_Console_Add('player is ordinary man now');
4963 exit;
4964 end;
4965 // speedy
4966 if cmd = 'speedy' then
4967 begin
4968 MAX_RUNVEL := 32-MAX_RUNVEL;
4969 g_Console_Add('speed adjusted');
4970 exit;
4971 end;
4972 // jumpy
4973 if cmd = 'jumpy' then
4974 begin
4975 VEL_JUMP := 30-VEL_JUMP;
4976 g_Console_Add('jump height adjusted');
4977 exit;
4978 end;
4979 // automap
4980 if cmd = 'automap' then
4981 begin
4982 gShowMap := not gShowMap;
4983 if gShowMap then g_Console_Add('player gains second sight') else g_Console_Add('player lost second sight');
4984 exit;
4985 end;
4986 // aimline
4987 if cmd = 'aimline' then
4988 begin
4989 gAimLine := not gAimLine;
4990 if gAimLine then g_Console_Add('player gains laser sight') else g_Console_Add('player lost laser sight');
4991 exit;
4992 end;
4993 end;
4995 procedure GameCommands(P: SArray);
4996 var
4997 a, b: Integer;
4998 s, pw: String;
4999 chstr: string;
5000 cmd: string;
5001 pl: pTNetClient = nil;
5002 plr: TPlayer;
5003 prt: Word;
5004 nm: Boolean;
5005 listen: LongWord;
5006 begin
5007 // Îáùèå êîìàíäû:
5008 cmd := LowerCase(P[0]);
5009 chstr := '';
5010 if (cmd = 'quit') or
5011 (cmd = 'exit') then
5012 begin
5013 g_Game_Free();
5014 g_Game_Quit();
5015 Exit;
5016 end
5017 else if cmd = 'pause' then
5018 begin
5019 if (g_ActiveWindow = nil) then
5020 g_Game_Pause(not gPause);
5021 end
5022 else if cmd = 'endgame' then
5023 gExit := EXIT_SIMPLE
5024 else if cmd = 'restart' then
5025 begin
5026 if gGameOn or (gState in [STATE_INTERSINGLE, STATE_INTERCUSTOM]) then
5027 begin
5028 if g_Game_IsClient then
5029 begin
5030 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5031 Exit;
5032 end;
5033 g_Game_Restart();
5034 end else
5035 g_Console_Add(_lc[I_MSG_NOT_GAME]);
5036 end
5037 else if cmd = 'kick' then
5038 begin
5039 if g_Game_IsServer then
5040 begin
5041 if Length(P) < 2 then
5042 begin
5043 g_Console_Add('kick <name>');
5044 Exit;
5045 end;
5046 if P[1] = '' then
5047 begin
5048 g_Console_Add('kick <name>');
5049 Exit;
5050 end;
5052 if g_Game_IsNet then
5053 pl := g_Net_Client_ByName(P[1]);
5054 if (pl <> nil) then
5055 begin
5056 s := g_Net_ClientName_ByID(pl^.ID);
5057 enet_peer_disconnect(pl^.Peer, NET_DISC_KICK);
5058 g_Console_Add(Format(_lc[I_PLAYER_KICK], [s]));
5059 MH_SEND_GameEvent(NET_EV_PLAYER_KICK, 0, s);
5060 if NetUseMaster then
5061 g_Net_Slist_Update;
5062 end else if gPlayers <> nil then
5063 for a := Low(gPlayers) to High(gPlayers) do
5064 if gPlayers[a] <> nil then
5065 if Copy(LowerCase(gPlayers[a].Name), 1, Length(P[1])) = LowerCase(P[1]) then
5066 begin
5067 // Íå îòêëþ÷àòü îñíîâíûõ èãðîêîâ â ñèíãëå
5068 if not(gPlayers[a] is TBot) and (gGameSettings.GameType = GT_SINGLE) then
5069 continue;
5070 gPlayers[a].Lives := 0;
5071 gPlayers[a].Kill(K_SIMPLEKILL, 0, HIT_DISCON);
5072 g_Console_Add(Format(_lc[I_PLAYER_LEAVE], [gPlayers[a].Name]), True);
5073 g_Player_Remove(gPlayers[a].UID);
5074 if NetUseMaster then
5075 g_Net_Slist_Update;
5076 // Åñëè íå ïåðåìåøàòü, ïðè äîáàâëåíèè íîâûõ áîòîâ ïîÿâÿòñÿ ñòàðûå
5077 g_Bot_MixNames();
5078 end;
5079 end else
5080 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5081 end
5082 else if cmd = 'kick_id' then
5083 begin
5084 if g_Game_IsServer and g_Game_IsNet then
5085 begin
5086 if Length(P) < 2 then
5087 begin
5088 g_Console_Add('kick_id <client ID>');
5089 Exit;
5090 end;
5091 if P[1] = '' then
5092 begin
5093 g_Console_Add('kick_id <client ID>');
5094 Exit;
5095 end;
5097 a := StrToIntDef(P[1], 0);
5098 if (NetClients <> nil) and (a <= High(NetClients)) then
5099 begin
5100 if NetClients[a].Used and (NetClients[a].Peer <> nil) then
5101 begin
5102 s := g_Net_ClientName_ByID(NetClients[a].ID);
5103 enet_peer_disconnect(NetClients[a].Peer, NET_DISC_KICK);
5104 g_Console_Add(Format(_lc[I_PLAYER_KICK], [s]));
5105 MH_SEND_GameEvent(NET_EV_PLAYER_KICK, 0, s);
5106 if NetUseMaster then
5107 g_Net_Slist_Update;
5108 end;
5109 end;
5110 end else
5111 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5112 end
5113 else if cmd = 'ban' then
5114 begin
5115 if g_Game_IsServer and g_Game_IsNet then
5116 begin
5117 if Length(P) < 2 then
5118 begin
5119 g_Console_Add('ban <name>');
5120 Exit;
5121 end;
5122 if P[1] = '' then
5123 begin
5124 g_Console_Add('ban <name>');
5125 Exit;
5126 end;
5128 pl := g_Net_Client_ByName(P[1]);
5129 if (pl <> nil) then
5130 begin
5131 s := g_Net_ClientName_ByID(pl^.ID);
5132 g_Net_BanHost(pl^.Peer^.address.host, False);
5133 enet_peer_disconnect(pl^.Peer, NET_DISC_TEMPBAN);
5134 g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
5135 MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
5136 if NetUseMaster then
5137 g_Net_Slist_Update;
5138 end else
5139 g_Console_Add(Format(_lc[I_NET_ERR_NAME404], [P[1]]));
5140 end else
5141 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5142 end
5143 else if cmd = 'ban_id' then
5144 begin
5145 if g_Game_IsServer and g_Game_IsNet then
5146 begin
5147 if Length(P) < 2 then
5148 begin
5149 g_Console_Add('ban_id <client ID>');
5150 Exit;
5151 end;
5152 if P[1] = '' then
5153 begin
5154 g_Console_Add('ban_id <client ID>');
5155 Exit;
5156 end;
5158 a := StrToIntDef(P[1], 0);
5159 if (NetClients <> nil) and (a <= High(NetClients)) then
5160 if NetClients[a].Used and (NetClients[a].Peer <> nil) then
5161 begin
5162 s := g_Net_ClientName_ByID(NetClients[a].ID);
5163 g_Net_BanHost(NetClients[a].Peer^.address.host, False);
5164 enet_peer_disconnect(NetClients[a].Peer, NET_DISC_TEMPBAN);
5165 g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
5166 MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
5167 if NetUseMaster then
5168 g_Net_Slist_Update;
5169 end;
5170 end else
5171 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5172 end
5173 else if cmd = 'permban' then
5174 begin
5175 if g_Game_IsServer and g_Game_IsNet then
5176 begin
5177 if Length(P) < 2 then
5178 begin
5179 g_Console_Add('permban <name>');
5180 Exit;
5181 end;
5182 if P[1] = '' then
5183 begin
5184 g_Console_Add('permban <name>');
5185 Exit;
5186 end;
5188 pl := g_Net_Client_ByName(P[1]);
5189 if (pl <> nil) then
5190 begin
5191 s := g_Net_ClientName_ByID(pl^.ID);
5192 g_Net_BanHost(pl^.Peer^.address.host);
5193 enet_peer_disconnect(pl^.Peer, NET_DISC_BAN);
5194 g_Net_SaveBanList();
5195 g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
5196 MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
5197 if NetUseMaster then
5198 g_Net_Slist_Update;
5199 end else
5200 g_Console_Add(Format(_lc[I_NET_ERR_NAME404], [P[1]]));
5201 end else
5202 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5203 end
5204 else if cmd = 'permban_id' then
5205 begin
5206 if g_Game_IsServer and g_Game_IsNet then
5207 begin
5208 if Length(P) < 2 then
5209 begin
5210 g_Console_Add('permban_id <client ID>');
5211 Exit;
5212 end;
5213 if P[1] = '' then
5214 begin
5215 g_Console_Add('permban_id <client ID>');
5216 Exit;
5217 end;
5219 a := StrToIntDef(P[1], 0);
5220 if (NetClients <> nil) and (a <= High(NetClients)) then
5221 if NetClients[a].Used and (NetClients[a].Peer <> nil) then
5222 begin
5223 s := g_Net_ClientName_ByID(NetClients[a].ID);
5224 g_Net_BanHost(NetClients[a].Peer^.address.host);
5225 enet_peer_disconnect(NetClients[a].Peer, NET_DISC_BAN);
5226 g_Net_SaveBanList();
5227 g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
5228 MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
5229 if NetUseMaster then
5230 g_Net_Slist_Update;
5231 end;
5232 end else
5233 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5234 end
5235 else if cmd = 'unban' then
5236 begin
5237 if g_Game_IsServer and g_Game_IsNet then
5238 begin
5239 if Length(P) < 2 then
5240 begin
5241 g_Console_Add('unban <IP Address>');
5242 Exit;
5243 end;
5244 if P[1] = '' then
5245 begin
5246 g_Console_Add('unban <IP Address>');
5247 Exit;
5248 end;
5250 if g_Net_UnbanHost(P[1]) then
5251 begin
5252 g_Console_Add(Format(_lc[I_MSG_UNBAN_OK], [P[1]]));
5253 g_Net_SaveBanList();
5254 end else
5255 g_Console_Add(Format(_lc[I_MSG_UNBAN_FAIL], [P[1]]));
5256 end else
5257 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5258 end
5259 else if cmd = 'clientlist' then
5260 begin
5261 if g_Game_IsServer and g_Game_IsNet then
5262 begin
5263 b := 0;
5264 if NetClients <> nil then
5265 for a := Low(NetClients) to High(NetClients) do
5266 if NetClients[a].Used and (NetClients[a].Peer <> nil) then
5267 begin
5268 plr := g_Player_Get(NetClients[a].Player);
5269 if plr = nil then continue;
5270 Inc(b);
5271 g_Console_Add(Format('#%2d: %-15s | %s', [a,
5272 IpToStr(NetClients[a].Peer^.address.host), plr.Name]));
5273 end;
5274 if b = 0 then
5275 g_Console_Add(_lc[I_MSG_NOCLIENTS]);
5276 end else
5277 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5278 end
5279 else if cmd = 'connect' then
5280 begin
5281 if (NetMode = NET_NONE) then
5282 begin
5283 if Length(P) < 2 then
5284 begin
5285 g_Console_Add('connect <IP> [port] [password]');
5286 Exit;
5287 end;
5288 if P[1] = '' then
5289 begin
5290 g_Console_Add('connect <IP> [port] [password]');
5291 Exit;
5292 end;
5294 if Length(P) > 2 then
5295 prt := StrToIntDef(P[2], 25666)
5296 else
5297 prt := 25666;
5299 if Length(P) > 3 then
5300 pw := P[3]
5301 else
5302 pw := '';
5304 g_Game_StartClient(P[1], prt, pw);
5305 end;
5306 end
5307 else if cmd = 'disconnect' then
5308 begin
5309 if (NetMode = NET_CLIENT) then
5310 g_Net_Disconnect();
5311 end
5312 else if cmd = 'reconnect' then
5313 begin
5314 if (NetMode = NET_SERVER) then
5315 Exit;
5317 if (NetMode = NET_CLIENT) then
5318 begin
5319 g_Net_Disconnect();
5320 gExit := EXIT_SIMPLE;
5321 EndGame;
5322 end;
5324 //TODO: Use last successful password to reconnect, instead of ''
5325 g_Game_StartClient(NetClientIP, NetClientPort, '');
5326 end
5327 else if (cmd = 'addbot') or
5328 (cmd = 'bot_add') then
5329 begin
5330 if Length(P) > 1 then
5331 g_Bot_Add(TEAM_NONE, StrToIntDef(P[1], 2))
5332 else
5333 g_Bot_Add(TEAM_NONE, 2);
5334 end
5335 else if cmd = 'bot_addlist' then
5336 begin
5337 if Length(P) > 1 then
5338 if Length(P) = 2 then
5339 g_Bot_AddList(TEAM_NONE, P[1], StrToIntDef(P[1], -1))
5340 else
5341 g_Bot_AddList(IfThen(P[2] = 'red', TEAM_RED, TEAM_BLUE), P[1], StrToIntDef(P[1], -1));
5342 end
5343 else if cmd = 'bot_removeall' then
5344 g_Bot_RemoveAll()
5345 else if cmd = 'chat' then
5346 begin
5347 if g_Game_IsNet then
5348 begin
5349 if Length(P) > 1 then
5350 begin
5351 for a := 1 to High(P) do
5352 chstr := chstr + P[a] + ' ';
5354 if Length(chstr) > 200 then SetLength(chstr, 200);
5356 if Length(chstr) < 1 then
5357 begin
5358 g_Console_Add('chat <text>');
5359 Exit;
5360 end;
5362 chstr := b_Text_Format(chstr);
5363 if g_Game_IsClient then
5364 MC_SEND_Chat(chstr, NET_CHAT_PLAYER)
5365 else
5366 MH_SEND_Chat(gPlayer1Settings.Name + ': ' + chstr, NET_CHAT_PLAYER);
5367 end
5368 else
5369 g_Console_Add('chat <text>');
5370 end else
5371 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5372 end
5373 else if cmd = 'teamchat' then
5374 begin
5375 if g_Game_IsNet and (gGameSettings.GameMode in [GM_TDM, GM_CTF]) then
5376 begin
5377 if Length(P) > 1 then
5378 begin
5379 for a := 1 to High(P) do
5380 chstr := chstr + P[a] + ' ';
5382 if Length(chstr) > 200 then SetLength(chstr, 200);
5384 if Length(chstr) < 1 then
5385 begin
5386 g_Console_Add('teamchat <text>');
5387 Exit;
5388 end;
5390 chstr := b_Text_Format(chstr);
5391 if g_Game_IsClient then
5392 MC_SEND_Chat(chstr, NET_CHAT_TEAM)
5393 else
5394 MH_SEND_Chat(gPlayer1Settings.Name + ': ' + chstr, NET_CHAT_TEAM,
5395 gPlayer1Settings.Team);
5396 end
5397 else
5398 g_Console_Add('teamchat <text>');
5399 end else
5400 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5401 end
5402 else if cmd = 'game' then
5403 begin
5404 if gGameSettings.GameType <> GT_NONE then
5405 begin
5406 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5407 Exit;
5408 end;
5409 if Length(P) = 1 then
5410 begin
5411 g_Console_Add(cmd + ' <WAD> [MAP] [# players]');
5412 Exit;
5413 end;
5414 // Èãðà åù¸ íå çàïóùåíà, ñíà÷àëà íàì íàäî çàãðóçèòü êàêîé-òî WAD
5415 P[1] := addWadExtension(P[1]);
5416 if FileExists(MapsDir + P[1]) then
5417 begin
5418 // Åñëè êàðòà íå óêàçàíà, áåð¸ì ïåðâóþ êàðòó â ôàéëå
5419 if Length(P) < 3 then
5420 begin
5421 SetLength(P, 3);
5422 P[2] := g_Game_GetFirstMap(MapsDir + P[1]);
5423 end;
5425 s := P[1] + ':\' + UpperCase(P[2]);
5427 if g_Map_Exist(MapsDir + s) then
5428 begin
5429 // Çàïóñêàåì ñâîþ èãðó
5430 g_Game_Free();
5431 with gGameSettings do
5432 begin
5433 GameMode := g_Game_TextToMode(gcGameMode);
5434 if gSwitchGameMode <> GM_NONE then
5435 GameMode := gSwitchGameMode;
5436 if GameMode = GM_NONE then GameMode := GM_DM;
5437 if GameMode = GM_SINGLE then GameMode := GM_COOP;
5438 b := 1;
5439 if Length(P) >= 4 then
5440 b := StrToIntDef(P[3], 1);
5441 g_Game_StartCustom(s, GameMode, TimeLimit,
5442 GoalLimit, MaxLives, Options, b);
5443 end;
5444 end
5445 else
5446 if P[2] = '' then
5447 g_Console_Add(Format(_lc[I_MSG_NO_MAPS], [P[1]]))
5448 else
5449 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [UpperCase(P[2])]));
5450 end else
5451 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[1]]));
5452 end
5453 else if cmd = 'host' then
5454 begin
5455 if gGameSettings.GameType <> GT_NONE then
5456 begin
5457 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5458 Exit;
5459 end;
5460 if Length(P) < 4 then
5461 begin
5462 g_Console_Add(cmd + ' <listen IP> <port> <WAD> [MAP] [# players]');
5463 Exit;
5464 end;
5465 if not StrToIp(P[1], listen) then
5466 Exit;
5467 prt := StrToIntDef(P[2], 25666);
5469 P[3] := addWadExtension(P[3]);
5470 if FileExists(MapsDir + P[3]) then
5471 begin
5472 // Åñëè êàðòà íå óêàçàíà, áåð¸ì ïåðâóþ êàðòó â ôàéëå
5473 if Length(P) < 5 then
5474 begin
5475 SetLength(P, 5);
5476 P[4] := g_Game_GetFirstMap(MapsDir + P[1]);
5477 end;
5479 s := P[3] + ':\' + UpperCase(P[4]);
5481 if g_Map_Exist(MapsDir + s) then
5482 begin
5483 // Çàïóñêàåì ñâîþ èãðó
5484 g_Game_Free();
5485 with gGameSettings do
5486 begin
5487 GameMode := g_Game_TextToMode(gcGameMode);
5488 if gSwitchGameMode <> GM_NONE then
5489 GameMode := gSwitchGameMode;
5490 if GameMode = GM_NONE then GameMode := GM_DM;
5491 if GameMode = GM_SINGLE then GameMode := GM_COOP;
5492 b := 0;
5493 if Length(P) >= 6 then
5494 b := StrToIntDef(P[5], 0);
5495 g_Game_StartServer(s, GameMode, TimeLimit,
5496 GoalLimit, MaxLives, Options, b, listen, prt);
5497 end;
5498 end
5499 else
5500 if P[4] = '' then
5501 g_Console_Add(Format(_lc[I_MSG_NO_MAPS], [P[3]]))
5502 else
5503 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [UpperCase(P[4])]));
5504 end else
5505 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[3]]));
5506 end
5507 else if cmd = 'map' then
5508 begin
5509 if Length(P) = 1 then
5510 begin
5511 if g_Game_IsServer and (gGameSettings.GameType <> GT_SINGLE) then
5512 begin
5513 g_Console_Add(cmd + ' <MAP>');
5514 g_Console_Add(cmd + ' <WAD> [MAP]');
5515 end else
5516 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5517 end else
5518 if g_Game_IsServer and (gGameSettings.GameType <> GT_SINGLE) then
5519 begin
5520 // Èä¸ò ñâîÿ èãðà èëè ñåðâåð
5521 if Length(P) < 3 then
5522 begin
5523 // Ïåðâûé ïàðàìåòð - ëèáî êàðòà, ëèáî èìÿ WAD ôàéëà
5524 s := UpperCase(P[1]);
5525 if g_Map_Exist(MapsDir + gGameSettings.WAD + ':\' + s) then
5526 begin // Êàðòà íàøëàñü
5527 gExitByTrigger := False;
5528 if gGameOn then
5529 begin // Èä¸ò èãðà - çàâåðøàåì óðîâåíü
5530 gNextMap := s;
5531 gExit := EXIT_ENDLEVELCUSTOM;
5532 end
5533 else // Èíòåðìèññèÿ - ñðàçó çàãðóæàåì êàðòó
5534 g_Game_ChangeMap(s);
5535 end else
5536 begin
5537 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [s]));
5538 // Òàêîé êàðòû íåò, èùåì WAD ôàéë
5539 P[1] := addWadExtension(P[1]);
5540 if FileExists(MapsDir + P[1]) then
5541 begin
5542 // Ïàðàìåòðà êàðòû íåò, ïîýòîìó ñòàâèì ïåðâóþ èç ôàéëà
5543 SetLength(P, 3);
5544 P[2] := g_Game_GetFirstMap(MapsDir + P[1]);
5546 s := P[1] + ':\' + P[2];
5548 if g_Map_Exist(MapsDir + s) then
5549 begin
5550 gExitByTrigger := False;
5551 if gGameOn then
5552 begin // Èä¸ò èãðà - çàâåðøàåì óðîâåíü
5553 gNextMap := s;
5554 gExit := EXIT_ENDLEVELCUSTOM;
5555 end
5556 else // Èíòåðìèññèÿ - ñðàçó çàãðóæàåì êàðòó
5557 g_Game_ChangeMap(s);
5558 end else
5559 if P[2] = '' then
5560 g_Console_Add(Format(_lc[I_MSG_NO_MAPS], [P[1]]))
5561 else
5562 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [P[2]]));
5563 end else
5564 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[1]]));
5565 end;
5566 end else
5567 begin
5568 // Óêàçàíî äâà ïàðàìåòðà, çíà÷èò ïåðâûé - WAD ôàéë, à âòîðîé - êàðòà
5569 P[1] := addWadExtension(P[1]);
5570 if FileExists(MapsDir + P[1]) then
5571 begin
5572 // Íàøëè WAD ôàéë
5573 P[2] := UpperCase(P[2]);
5574 s := P[1] + ':\' + P[2];
5576 if g_Map_Exist(MapsDir + s) then
5577 begin // Íàøëè êàðòó
5578 gExitByTrigger := False;
5579 if gGameOn then
5580 begin // Èä¸ò èãðà - çàâåðøàåì óðîâåíü
5581 gNextMap := s;
5582 gExit := EXIT_ENDLEVELCUSTOM;
5583 end
5584 else // Èíòåðìèññèÿ - ñðàçó çàãðóæàåì êàðòó
5585 g_Game_ChangeMap(s);
5586 end else
5587 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [P[2]]));
5588 end else
5589 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[1]]));
5590 end;
5591 end else
5592 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5593 end
5594 else if cmd = 'nextmap' then
5595 begin
5596 if not(gGameOn or (gState = STATE_INTERCUSTOM)) then
5597 g_Console_Add(_lc[I_MSG_NOT_GAME])
5598 else begin
5599 nm := True;
5600 if Length(P) = 1 then
5601 begin
5602 if g_Game_IsServer and (gGameSettings.GameType <> GT_SINGLE) then
5603 begin
5604 g_Console_Add(cmd + ' <MAP>');
5605 g_Console_Add(cmd + ' <WAD> [MAP]');
5606 end else begin
5607 nm := False;
5608 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5609 end;
5610 end else
5611 begin
5612 nm := False;
5613 if g_Game_IsServer and (gGameSettings.GameType <> GT_SINGLE) then
5614 begin
5615 if Length(P) < 3 then
5616 begin
5617 // Ïåðâûé ïàðàìåòð - ëèáî êàðòà, ëèáî èìÿ WAD ôàéëà
5618 s := UpperCase(P[1]);
5619 if g_Map_Exist(MapsDir + gGameSettings.WAD + ':\' + s) then
5620 begin // Êàðòà íàøëàñü
5621 gExitByTrigger := False;
5622 gNextMap := s;
5623 nm := True;
5624 end else
5625 begin
5626 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [s]));
5627 // Òàêîé êàðòû íåò, èùåì WAD ôàéë
5628 P[1] := addWadExtension(P[1]);
5629 if FileExists(MapsDir + P[1]) then
5630 begin
5631 // Ïàðàìåòðà êàðòû íåò, ïîýòîìó ñòàâèì ïåðâóþ èç ôàéëà
5632 SetLength(P, 3);
5633 P[2] := g_Game_GetFirstMap(MapsDir + P[1]);
5635 s := P[1] + ':\' + P[2];
5637 if g_Map_Exist(MapsDir + s) then
5638 begin // Óñòàíàâëèâàåì êàðòó
5639 gExitByTrigger := False;
5640 gNextMap := s;
5641 nm := True;
5642 end else
5643 if P[2] = '' then
5644 g_Console_Add(Format(_lc[I_MSG_NO_MAPS], [P[1]]))
5645 else
5646 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [P[2]]));
5647 end else
5648 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[1]]));
5649 end;
5650 end else
5651 begin
5652 // Óêàçàíî äâà ïàðàìåòðà, çíà÷èò ïåðâûé - WAD ôàéë, à âòîðîé - êàðòà
5653 P[1] := addWadExtension(P[1]);
5654 if FileExists(MapsDir + P[1]) then
5655 begin
5656 // Íàøëè WAD ôàéë
5657 P[2] := UpperCase(P[2]);
5658 s := P[1] + ':\' + P[2];
5660 if g_Map_Exist(MapsDir + s) then
5661 begin // Íàøëè êàðòó
5662 gExitByTrigger := False;
5663 gNextMap := s;
5664 nm := True;
5665 end else
5666 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [P[2]]));
5667 end else
5668 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[1]]));
5669 end;
5670 end else
5671 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5672 end;
5673 if nm then
5674 if gNextMap = '' then
5675 g_Console_Add(_lc[I_MSG_NEXTMAP_UNSET])
5676 else
5677 g_Console_Add(Format(_lc[I_MSG_NEXTMAP_SET], [gNextMap]));
5678 end;
5679 end
5680 else if (cmd = 'endmap') or (cmd = 'goodbye') then
5681 begin
5682 if not gGameOn then
5683 g_Console_Add(_lc[I_MSG_NOT_GAME])
5684 else
5685 if g_Game_IsServer and (gGameSettings.GameType <> GT_SINGLE) then
5686 begin
5687 gExitByTrigger := False;
5688 // Ñëåäóþùàÿ êàðòà íå çàäàíà, ïðîáóåì íàéòè òðèããåð Âûõîä
5689 if (gNextMap = '') and (gTriggers <> nil) then
5690 for a := 0 to High(gTriggers) do
5691 if gTriggers[a].TriggerType = TRIGGER_EXIT then
5692 begin
5693 gExitByTrigger := True;
5694 gNextMap := gTriggers[a].Data.MapName;
5695 Break;
5696 end;
5697 // Èùåì ñëåäóþùóþ êàðòó â WAD ôàéëå
5698 if gNextMap = '' then
5699 gNextMap := g_Game_GetNextMap();
5700 // Ïðîâåðÿåì, íå çàäàí ëè WAD ôàéë ðåñóðñíîé ñòðîêîé
5701 if Pos(':\', gNextMap) = 0 then
5702 s := gGameSettings.WAD + ':\' + gNextMap
5703 else
5704 s := gNextMap;
5705 // Åñëè êàðòà íàéäåíà, âûõîäèì ñ óðîâíÿ
5706 if g_Map_Exist(MapsDir + s) then
5707 gExit := EXIT_ENDLEVELCUSTOM
5708 else
5709 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [gNextMap]));
5710 end else
5711 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5712 end
5713 else if (cmd = 'event') then
5714 begin
5715 if (Length(P) <= 1) then
5716 begin
5717 for a := 0 to High(gEvents) do
5718 if gEvents[a].Command = '' then
5719 g_Console_Add(gEvents[a].Name + ' <none>')
5720 else
5721 g_Console_Add(gEvents[a].Name + ' "' + gEvents[a].Command + '"');
5722 Exit;
5723 end;
5724 if (Length(P) = 2) then
5725 begin
5726 for a := 0 to High(gEvents) do
5727 if gEvents[a].Name = P[1] then
5728 if gEvents[a].Command = '' then
5729 g_Console_Add(gEvents[a].Name + ' <none>')
5730 else
5731 g_Console_Add(gEvents[a].Name + ' "' + gEvents[a].Command + '"');
5732 Exit;
5733 end;
5734 for a := 0 to High(gEvents) do
5735 if gEvents[a].Name = P[1] then
5736 begin
5737 gEvents[a].Command := '';
5738 for b := 2 to High(P) do
5739 if Pos(' ', P[b]) = 0 then
5740 gEvents[a].Command := gEvents[a].Command + ' ' + P[b]
5741 else
5742 gEvents[a].Command := gEvents[a].Command + ' "' + P[b] + '"';
5743 gEvents[a].Command := Trim(gEvents[a].Command);
5744 Exit;
5745 end;
5746 end
5747 // Êîìàíäû Ñâîåé èãðû:
5748 else if gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT] then
5749 begin
5750 if cmd = 'bot_addred' then
5751 begin
5752 if Length(P) > 1 then
5753 g_Bot_Add(TEAM_RED, StrToIntDef(P[1], 2))
5754 else
5755 g_Bot_Add(TEAM_RED, 2);
5756 end
5757 else if cmd = 'bot_addblue' then
5758 begin
5759 if Length(P) > 1 then
5760 g_Bot_Add(TEAM_BLUE, StrToIntDef(P[1], 2))
5761 else
5762 g_Bot_Add(TEAM_BLUE, 2);
5763 end
5764 else if cmd = 'suicide' then
5765 begin
5766 if gGameOn then
5767 begin
5768 if g_Game_IsClient then
5769 MC_SEND_CheatRequest(NET_CHEAT_SUICIDE)
5770 else
5771 begin
5772 if gPlayer1 <> nil then
5773 gPlayer1.Damage(SUICIDE_DAMAGE, gPlayer1.UID, 0, 0, HIT_SELF);
5774 if gPlayer2 <> nil then
5775 gPlayer2.Damage(SUICIDE_DAMAGE, gPlayer2.UID, 0, 0, HIT_SELF);
5776 end;
5777 end;
5778 end
5779 else if cmd = 'spectate' then
5780 begin
5781 if not gGameOn then
5782 Exit;
5783 g_Game_Spectate();
5784 end
5785 else if cmd = 'say' then
5786 begin
5787 if g_Game_IsServer and g_Game_IsNet then
5788 begin
5789 if Length(P) > 1 then
5790 begin
5791 chstr := '';
5792 for a := 1 to High(P) do
5793 chstr := chstr + P[a] + ' ';
5795 if Length(chstr) > 200 then SetLength(chstr, 200);
5797 if Length(chstr) < 1 then
5798 begin
5799 g_Console_Add('say <text>');
5800 Exit;
5801 end;
5803 chstr := b_Text_Format(chstr);
5804 MH_SEND_Chat(chstr, NET_CHAT_PLAYER);
5805 end
5806 else g_Console_Add('say <text>');
5807 end else
5808 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5809 end
5810 else if cmd = 'tell' then
5811 begin
5812 if g_Game_IsServer and g_Game_IsNet then
5813 begin
5814 if (Length(P) > 2) and (P[1] <> '') then
5815 begin
5816 chstr := '';
5817 for a := 2 to High(P) do
5818 chstr := chstr + P[a] + ' ';
5820 if Length(chstr) > 200 then SetLength(chstr, 200);
5822 if Length(chstr) < 1 then
5823 begin
5824 g_Console_Add('tell <playername> <text>');
5825 Exit;
5826 end;
5828 pl := g_Net_Client_ByName(P[1]);
5829 if pl <> nil then
5830 MH_SEND_Chat(b_Text_Format(chstr), NET_CHAT_PLAYER, pl^.ID)
5831 else
5832 g_Console_Add(Format(_lc[I_NET_ERR_NAME404], [P[1]]));
5833 end
5834 else g_Console_Add('tell <playername> <text>');
5835 end else
5836 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5837 end
5838 else if (cmd = 'overtime') and not g_Game_IsClient then
5839 begin
5840 if (Length(P) = 1) or (StrToIntDef(P[1], -1) <= 0) then
5841 Exit;
5842 // Äîïîëíèòåëüíîå âðåìÿ:
5843 gGameSettings.TimeLimit := (gTime - gGameStartTime) div 1000 + Word(StrToIntDef(P[1], 0));
5845 g_Console_Add(Format(_lc[I_MSG_TIME_LIMIT],
5846 [gGameSettings.TimeLimit div 3600,
5847 (gGameSettings.TimeLimit div 60) mod 60,
5848 gGameSettings.TimeLimit mod 60]));
5849 if g_Game_IsNet then MH_SEND_GameSettings;
5850 end
5851 else if (cmd = 'rcon_password') and g_Game_IsClient then
5852 begin
5853 if (Length(P) <= 1) then
5854 g_Console_Add('rcon_password <password>')
5855 else
5856 MC_SEND_RCONPassword(P[1]);
5857 end
5858 else if cmd = 'rcon' then
5859 begin
5860 if g_Game_IsClient then
5861 begin
5862 if Length(P) > 1 then
5863 begin
5864 chstr := '';
5865 for a := 1 to High(P) do
5866 chstr := chstr + P[a] + ' ';
5868 if Length(chstr) > 200 then SetLength(chstr, 200);
5870 if Length(chstr) < 1 then
5871 begin
5872 g_Console_Add('rcon <command>');
5873 Exit;
5874 end;
5876 MC_SEND_RCONCommand(chstr);
5877 end
5878 else g_Console_Add('rcon <command>');
5879 end;
5880 end
5881 else if cmd = 'ready' then
5882 begin
5883 if g_Game_IsServer and (gLMSRespawn = LMS_RESPAWN_WARMUP) then
5884 gLMSRespawnTime := gTime + 100;
5885 end
5886 else if (cmd = 'callvote') and g_Game_IsNet then
5887 begin
5888 if Length(P) > 1 then
5889 begin
5890 chstr := '';
5891 for a := 1 to High(P) do begin
5892 if a > 1 then chstr := chstr + ' ';
5893 chstr := chstr + P[a];
5894 end;
5896 if Length(chstr) > 200 then SetLength(chstr, 200);
5898 if Length(chstr) < 1 then
5899 begin
5900 g_Console_Add('callvote <command>');
5901 Exit;
5902 end;
5904 if g_Game_IsClient then
5905 MC_SEND_Vote(True, chstr)
5906 else
5907 g_Game_StartVote(chstr, gPlayer1Settings.Name);
5908 g_Console_Process('vote', True);
5909 end
5910 else
5911 g_Console_Add('callvote <command>');
5912 end
5913 else if (cmd = 'vote') and g_Game_IsNet then
5914 begin
5915 if g_Game_IsClient then
5916 MC_SEND_Vote(False)
5917 else if gVoteInProgress then
5918 begin
5919 if (gPlayer1 <> nil) or (gPlayer2 <> nil) then
5920 a := Floor((NetClientCount+1)/2.0) + 1
5921 else
5922 a := Floor(NetClientCount/2.0) + 1;
5923 if gVoted then
5924 begin
5925 Dec(gVoteCount);
5926 gVoted := False;
5927 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_REVOKED], [gPlayer1Settings.Name, gVoteCount, a]), True);
5928 MH_SEND_VoteEvent(NET_VE_REVOKE, gPlayer1Settings.Name, 'a', gVoteCount, a);
5929 end
5930 else
5931 begin
5932 Inc(gVoteCount);
5933 gVoted := True;
5934 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_VOTE], [gPlayer1Settings.Name, gVoteCount, a]), True);
5935 MH_SEND_VoteEvent(NET_VE_VOTE, gPlayer1Settings.Name, 'a', gVoteCount, a);
5936 g_Game_CheckVote;
5937 end;
5938 end;
5939 end
5940 end;
5941 end;
5943 procedure g_TakeScreenShot();
5944 var
5945 a: Word;
5946 FileName: string;
5947 ssdir, t: string;
5948 st: TStream;
5949 ok: Boolean;
5950 begin
5951 if e_NoGraphics then Exit;
5952 ssdir := GameDir+'/screenshots';
5953 if not findFileCI(ssdir, true) then
5954 begin
5955 // try to create dir
5956 try
5957 CreateDir(ssdir);
5958 except
5959 end;
5960 if not findFileCI(ssdir, true) then exit; // alas
5961 end;
5962 try
5963 for a := 1 to High(Word) do
5964 begin
5965 FileName := Format(ssdir+'screenshot%.3d.png', [a]);
5966 t := FileName;
5967 if findFileCI(t, true) then continue;
5968 if not findFileCI(FileName) then
5969 begin
5970 ok := false;
5971 st := createDiskFile(FileName);
5972 try
5973 e_MakeScreenshot(st, gScreenWidth, gScreenHeight);
5974 ok := true;
5975 finally
5976 st.Free();
5977 end;
5978 if not ok then try DeleteFile(FileName); except end else g_Console_Add(Format(_lc[I_CONSOLE_SCREENSHOT], [ExtractFileName(FileName)]));
5979 break;
5980 end;
5981 end;
5982 except
5983 end;
5984 end;
5986 procedure g_Game_InGameMenu(Show: Boolean);
5987 begin
5988 if (g_ActiveWindow = nil) and Show then
5989 begin
5990 if gGameSettings.GameType = GT_SINGLE then
5991 g_GUI_ShowWindow('GameSingleMenu')
5992 else
5993 begin
5994 if g_Game_IsClient then
5995 g_GUI_ShowWindow('GameClientMenu')
5996 else
5997 if g_Game_IsNet then
5998 g_GUI_ShowWindow('GameServerMenu')
5999 else
6000 g_GUI_ShowWindow('GameCustomMenu');
6001 end;
6002 g_Sound_PlayEx('MENU_OPEN');
6004 // Ïàóçà ïðè ìåíþ òîëüêî â îäèíî÷íîé èãðå:
6005 if (not g_Game_IsNet) then
6006 g_Game_Pause(True);
6007 end
6008 else
6009 if (g_ActiveWindow <> nil) and (not Show) then
6010 begin
6011 // Ïàóçà ïðè ìåíþ òîëüêî â îäèíî÷íîé èãðå:
6012 if (not g_Game_IsNet) then
6013 g_Game_Pause(False);
6014 end;
6015 end;
6017 procedure g_Game_Pause(Enable: Boolean);
6018 begin
6019 if not gGameOn then
6020 Exit;
6022 if gPause = Enable then
6023 Exit;
6025 if not (gGameSettings.GameType in [GT_SINGLE, GT_CUSTOM]) then
6026 Exit;
6028 gPause := Enable;
6029 g_Game_PauseAllSounds(Enable);
6030 end;
6032 procedure g_Game_PauseAllSounds(Enable: Boolean);
6033 var
6034 i: Integer;
6035 begin
6036 // Òðèããåðû:
6037 if gTriggers <> nil then
6038 for i := 0 to High(gTriggers) do
6039 with gTriggers[i] do
6040 if (TriggerType = TRIGGER_SOUND) and
6041 (Sound <> nil) and
6042 Sound.IsPlaying() then
6043 begin
6044 Sound.Pause(Enable);
6045 end;
6047 // Çâóêè èãðîêîâ:
6048 if gPlayers <> nil then
6049 for i := 0 to High(gPlayers) do
6050 if gPlayers[i] <> nil then
6051 gPlayers[i].PauseSounds(Enable);
6053 // Ìóçûêà:
6054 if gMusic <> nil then
6055 gMusic.Pause(Enable);
6056 end;
6058 procedure g_Game_StopAllSounds(all: Boolean);
6059 var
6060 i: Integer;
6061 begin
6062 if gTriggers <> nil then
6063 for i := 0 to High(gTriggers) do
6064 with gTriggers[i] do
6065 if (TriggerType = TRIGGER_SOUND) and
6066 (Sound <> nil) then
6067 Sound.Stop();
6069 if gMusic <> nil then
6070 gMusic.Stop();
6072 if all then
6073 e_StopChannels();
6074 end;
6076 procedure g_Game_UpdateTriggerSounds();
6077 var
6078 i: Integer;
6079 begin
6080 if gTriggers <> nil then
6081 for i := 0 to High(gTriggers) do
6082 with gTriggers[i] do
6083 if (TriggerType = TRIGGER_SOUND) and
6084 (Sound <> nil) and
6085 (Data.Local) and
6086 Sound.IsPlaying() then
6087 begin
6088 if ((gPlayer1 <> nil) and g_CollidePoint(gPlayer1.GameX, gPlayer1.GameY, X, Y, Width, Height)) or
6089 ((gPlayer2 <> nil) and g_CollidePoint(gPlayer2.GameX, gPlayer2.GameY, X, Y, Width, Height)) then
6090 begin
6091 Sound.SetPan(0.5 - Data.Pan/255.0);
6092 Sound.SetVolume(Data.Volume/255.0);
6093 end
6094 else
6095 Sound.SetCoords(X+(Width div 2), Y+(Height div 2), Data.Volume/255.0);
6096 end;
6097 end;
6099 function g_Game_IsWatchedPlayer(UID: Word): Boolean;
6100 begin
6101 Result := False;
6102 if (gPlayer1 <> nil) and (gPlayer1.UID = UID) then
6103 begin
6104 Result := True;
6105 Exit;
6106 end;
6107 if (gPlayer2 <> nil) and (gPlayer2.UID = UID) then
6108 begin
6109 Result := True;
6110 Exit;
6111 end;
6112 if gSpectMode <> SPECT_PLAYERS then
6113 Exit;
6114 if gSpectPID1 = UID then
6115 begin
6116 Result := True;
6117 Exit;
6118 end;
6119 if gSpectViewTwo and (gSpectPID2 = UID) then
6120 begin
6121 Result := True;
6122 Exit;
6123 end;
6124 end;
6126 function g_Game_IsWatchedTeam(Team: Byte): Boolean;
6127 var
6128 Pl: TPlayer;
6129 begin
6130 Result := False;
6131 if (gPlayer1 <> nil) and (gPlayer1.Team = Team) then
6132 begin
6133 Result := True;
6134 Exit;
6135 end;
6136 if (gPlayer2 <> nil) and (gPlayer2.Team = Team) then
6137 begin
6138 Result := True;
6139 Exit;
6140 end;
6141 if gSpectMode <> SPECT_PLAYERS then
6142 Exit;
6143 Pl := g_Player_Get(gSpectPID1);
6144 if (Pl <> nil) and (Pl.Team = Team) then
6145 begin
6146 Result := True;
6147 Exit;
6148 end;
6149 if gSpectViewTwo then
6150 begin
6151 Pl := g_Player_Get(gSpectPID2);
6152 if (Pl <> nil) and (Pl.Team = Team) then
6153 begin
6154 Result := True;
6155 Exit;
6156 end;
6157 end;
6158 end;
6160 procedure g_Game_Message(Msg: string; Time: Word);
6161 begin
6162 MessageText := b_Text_Format(Msg);
6163 MessageTime := Time;
6164 end;
6166 procedure g_Game_Announce_GoodShot(SpawnerUID: Word);
6167 var
6168 a: Integer;
6169 begin
6170 case gAnnouncer of
6171 ANNOUNCE_NONE:
6172 Exit;
6173 ANNOUNCE_ME,
6174 ANNOUNCE_MEPLUS:
6175 if not g_Game_IsWatchedPlayer(SpawnerUID) then
6176 Exit;
6177 end;
6178 for a := 0 to 3 do
6179 if goodsnd[a].IsPlaying() then
6180 Exit;
6182 goodsnd[Random(4)].Play();
6183 end;
6185 procedure g_Game_Announce_KillCombo(Param: Integer);
6186 var
6187 UID: Word;
6188 c, n: Byte;
6189 Pl: TPlayer;
6190 Name: String;
6191 begin
6192 UID := Param and $FFFF;
6193 c := Param shr 16;
6194 if c < 2 then
6195 Exit;
6197 Pl := g_Player_Get(UID);
6198 if Pl = nil then
6199 Name := '?'
6200 else
6201 Name := Pl.Name;
6203 case c of
6204 2: begin
6205 n := 0;
6206 g_Console_Add(Format(_lc[I_PLAYER_KILL_2X], [Name]), True);
6207 end;
6208 3: begin
6209 n := 1;
6210 g_Console_Add(Format(_lc[I_PLAYER_KILL_3X], [Name]), True);
6211 end;
6212 4: begin
6213 n := 2;
6214 g_Console_Add(Format(_lc[I_PLAYER_KILL_4X], [Name]), True);
6215 end;
6216 else begin
6217 n := 3;
6218 g_Console_Add(Format(_lc[I_PLAYER_KILL_MX], [Name]), True);
6219 end;
6220 end;
6222 case gAnnouncer of
6223 ANNOUNCE_NONE:
6224 Exit;
6225 ANNOUNCE_ME:
6226 if not g_Game_IsWatchedPlayer(UID) then
6227 Exit;
6228 ANNOUNCE_MEPLUS:
6229 if (not g_Game_IsWatchedPlayer(UID)) and (c < 4) then
6230 Exit;
6231 end;
6233 if killsnd[n].IsPlaying() then
6234 killsnd[n].Stop();
6235 killsnd[n].Play();
6236 end;
6238 procedure g_Game_StartVote(Command, Initiator: string);
6239 var
6240 Need: Integer;
6241 begin
6242 if not gVotesEnabled then Exit;
6243 if gGameSettings.GameType <> GT_SERVER then Exit;
6244 if gVoteInProgress or gVotePassed then
6245 begin
6246 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_INPROGRESS], [gVoteCommand]), True);
6247 MH_SEND_VoteEvent(NET_VE_INPROGRESS, gVoteCommand);
6248 Exit;
6249 end;
6250 gVoteInProgress := True;
6251 gVotePassed := False;
6252 gVoteTimer := gTime + gVoteTimeout * 1000;
6253 gVoteCount := 0;
6254 gVoted := False;
6255 gVoteCommand := Command;
6257 if (gPlayer1 <> nil) or (gPlayer2 <> nil) then
6258 Need := Floor((NetClientCount+1)/2.0)+1
6259 else
6260 Need := Floor(NetClientCount/2.0)+1;
6261 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_STARTED], [Initiator, Command, Need]), True);
6262 MH_SEND_VoteEvent(NET_VE_STARTED, Initiator, Command, Need);
6263 end;
6265 procedure g_Game_CheckVote;
6266 var
6267 I, Need: Integer;
6268 begin
6269 if gGameSettings.GameType <> GT_SERVER then Exit;
6270 if not gVoteInProgress then Exit;
6272 if (gTime >= gVoteTimer) then
6273 begin
6274 if (gPlayer1 <> nil) or (gPlayer2 <> nil) then
6275 Need := Floor((NetClientCount+1)/2.0) + 1
6276 else
6277 Need := Floor(NetClientCount/2.0) + 1;
6278 if gVoteCount >= Need then
6279 begin
6280 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_PASSED], [gVoteCommand]), True);
6281 MH_SEND_VoteEvent(NET_VE_PASSED, gVoteCommand);
6282 gVotePassed := True;
6283 gVoteCmdTimer := gTime + 5000;
6284 end
6285 else
6286 begin
6287 g_Console_Add(_lc[I_MESSAGE_VOTE_FAILED], True);
6288 MH_SEND_VoteEvent(NET_VE_FAILED);
6289 end;
6290 if NetClients <> nil then
6291 for I := Low(NetClients) to High(NetClients) do
6292 if NetClients[i].Used then
6293 NetClients[i].Voted := False;
6294 gVoteInProgress := False;
6295 gVoted := False;
6296 gVoteCount := 0;
6297 end
6298 else
6299 begin
6300 if (gPlayer1 <> nil) or (gPlayer2 <> nil) then
6301 Need := Floor((NetClientCount+1)/2.0) + 1
6302 else
6303 Need := Floor(NetClientCount/2.0) + 1;
6304 if gVoteCount >= Need then
6305 begin
6306 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_PASSED], [gVoteCommand]), True);
6307 MH_SEND_VoteEvent(NET_VE_PASSED, gVoteCommand);
6308 gVoteInProgress := False;
6309 gVotePassed := True;
6310 gVoteCmdTimer := gTime + 5000;
6311 gVoted := False;
6312 gVoteCount := 0;
6313 if NetClients <> nil then
6314 for I := Low(NetClients) to High(NetClients) do
6315 if NetClients[i].Used then
6316 NetClients[i].Voted := False;
6317 end;
6318 end;
6319 end;
6321 procedure g_Game_LoadMapList(FileName: string);
6322 var
6323 ListFile: TextFile;
6324 s: string;
6325 begin
6326 MapList := nil;
6327 MapIndex := -1;
6329 if not FileExists(FileName) then Exit;
6331 AssignFile(ListFile, FileName);
6332 Reset(ListFile);
6333 while not EOF(ListFile) do
6334 begin
6335 ReadLn(ListFile, s);
6337 s := Trim(s);
6338 if s = '' then Continue;
6340 SetLength(MapList, Length(MapList)+1);
6341 MapList[High(MapList)] := s;
6342 end;
6343 CloseFile(ListFile);
6344 end;
6346 procedure g_Game_SetDebugMode();
6347 begin
6348 gDebugMode := True;
6349 // ×èòû (äàæå â ñâîåé èãðå):
6350 gCheats := True;
6351 end;
6353 procedure g_Game_SetLoadingText(Text: String; Max: Integer; reWrite: Boolean);
6354 var
6355 i: Word;
6356 begin
6357 if Length(LoadingStat.Msgs) = 0 then
6358 Exit;
6360 with LoadingStat do
6361 begin
6362 if not reWrite then
6363 begin // Ïåðåõîäèì íà ñëåäóþùóþ ñòðîêó èëè ñêðîëëèðóåì:
6364 if NextMsg = Length(Msgs) then
6365 begin // scroll
6366 for i := 0 to High(Msgs)-1 do
6367 Msgs[i] := Msgs[i+1];
6368 end
6369 else
6370 Inc(NextMsg);
6371 end else
6372 if NextMsg = 0 then
6373 Inc(NextMsg);
6375 Msgs[NextMsg-1] := Text;
6376 CurValue := 0;
6377 MaxValue := Max;
6378 ShowCount := 0;
6379 end;
6381 g_ActiveWindow := nil;
6383 ProcessLoading;
6384 end;
6386 procedure g_Game_StepLoading();
6387 begin
6388 with LoadingStat do
6389 begin
6390 Inc(CurValue);
6391 Inc(ShowCount);
6392 if (ShowCount > LOADING_SHOW_STEP) then
6393 begin
6394 ShowCount := 0;
6395 ProcessLoading;
6396 end;
6397 end;
6398 end;
6400 procedure g_Game_ClearLoading();
6401 var
6402 len: Word;
6403 begin
6404 with LoadingStat do
6405 begin
6406 CurValue := 0;
6407 MaxValue := 0;
6408 ShowCount := 0;
6409 len := ((gScreenHeight div 3)*2 - 50) div LOADING_INTERLINE;
6410 if len < 1 then len := 1;
6411 SetLength(Msgs, len);
6412 for len := Low(Msgs) to High(Msgs) do
6413 Msgs[len] := '';
6414 NextMsg := 0;
6415 end;
6416 end;
6418 procedure Parse_Params(var pars: TParamStrValues);
6419 var
6420 i: Integer;
6421 s: String;
6422 begin
6423 SetLength(pars, 0);
6424 i := 1;
6425 while i <= ParamCount do
6426 begin
6427 s := ParamStr(i);
6428 if (s[1] = '-') and (Length(s) > 1) then
6429 begin
6430 if (s[2] = '-') and (Length(s) > 2) then
6431 begin // Îäèíî÷íûé ïàðàìåòð
6432 SetLength(pars, Length(pars) + 1);
6433 with pars[High(pars)] do
6434 begin
6435 Name := LowerCase(s);
6436 Value := '+';
6437 end;
6438 end
6439 else
6440 if (i < ParamCount) then
6441 begin // Ïàðàìåòð ñî çíà÷åíèåì
6442 Inc(i);
6443 SetLength(pars, Length(pars) + 1);
6444 with pars[High(pars)] do
6445 begin
6446 Name := LowerCase(s);
6447 Value := LowerCase(ParamStr(i));
6448 end;
6449 end;
6450 end;
6452 Inc(i);
6453 end;
6454 end;
6456 function Find_Param_Value(var pars: TParamStrValues; aName: String): String;
6457 var
6458 i: Integer;
6459 begin
6460 Result := '';
6461 for i := 0 to High(pars) do
6462 if pars[i].Name = aName then
6463 begin
6464 Result := pars[i].Value;
6465 Break;
6466 end;
6467 end;
6469 procedure g_Game_Process_Params();
6470 var
6471 pars: TParamStrValues;
6472 map: String;
6473 GMode, n: Byte;
6474 LimT, LimS: Integer;
6475 Opt: LongWord;
6476 Lives: Integer;
6477 s: String;
6478 Port: Integer;
6479 ip: String;
6480 F: TextFile;
6481 begin
6482 Parse_Params(pars);
6484 // Debug mode:
6485 s := Find_Param_Value(pars, '--debug');
6486 if (s <> '') then
6487 g_Game_SetDebugMode();
6489 // Connect when game loads
6490 ip := Find_Param_Value(pars, '-connect');
6492 if ip <> '' then
6493 begin
6494 s := Find_Param_Value(pars, '-port');
6495 if (s = '') or not TryStrToInt(s, Port) then
6496 Port := 25666;
6498 s := Find_Param_Value(pars, '-pw');
6500 g_Game_StartClient(ip, Port, s);
6501 Exit;
6502 end;
6504 // Start map when game loads:
6505 map := LowerCase(Find_Param_Value(pars, '-map'));
6506 if isWadPath(map) then
6507 begin
6508 // Game mode:
6509 s := Find_Param_Value(pars, '-gm');
6510 GMode := g_Game_TextToMode(s);
6511 if GMode = GM_NONE then GMode := GM_DM;
6512 if GMode = GM_SINGLE then GMode := GM_COOP;
6514 // Time limit:
6515 s := Find_Param_Value(pars, '-limt');
6516 if (s = '') or (not TryStrToInt(s, LimT)) then
6517 LimT := 0;
6518 if LimT < 0 then
6519 LimT := 0;
6521 // Goal limit:
6522 s := Find_Param_Value(pars, '-lims');
6523 if (s = '') or (not TryStrToInt(s, LimS)) then
6524 LimS := 0;
6525 if LimS < 0 then
6526 LimS := 0;
6528 // Lives limit:
6529 s := Find_Param_Value(pars, '-lives');
6530 if (s = '') or (not TryStrToInt(s, Lives)) then
6531 Lives := 0;
6532 if Lives < 0 then
6533 Lives := 0;
6535 // Options:
6536 s := Find_Param_Value(pars, '-opt');
6537 if (s = '') then
6538 Opt := GAME_OPTION_ALLOWEXIT or GAME_OPTION_BOTVSPLAYER or GAME_OPTION_BOTVSMONSTER
6539 else
6540 Opt := StrToIntDef(s, 0);
6541 if Opt = 0 then
6542 Opt := GAME_OPTION_ALLOWEXIT or GAME_OPTION_BOTVSPLAYER or GAME_OPTION_BOTVSMONSTER;
6544 // Close after map:
6545 s := Find_Param_Value(pars, '--close');
6546 if (s <> '') then
6547 gMapOnce := True;
6549 // Delete test map after play:
6550 s := Find_Param_Value(pars, '--testdelete');
6551 if (s <> '') then
6552 begin
6553 gMapToDelete := MapsDir + map;
6554 e_WriteLog('"--testdelete" is deprecated, use --tempdelete.', MSG_FATALERROR);
6555 Halt(1);
6556 end;
6558 // Delete temporary WAD after play:
6559 s := Find_Param_Value(pars, '--tempdelete');
6560 if (s <> '') then
6561 begin
6562 gMapToDelete := MapsDir + map;
6563 gTempDelete := True;
6564 end;
6566 // Number of players:
6567 s := Find_Param_Value(pars, '-pl');
6568 if (s = '') then
6569 n := 1
6570 else
6571 n := StrToIntDef(s, 1);
6573 // Start:
6574 s := Find_Param_Value(pars, '-port');
6575 if (s = '') or not TryStrToInt(s, Port) then
6576 g_Game_StartCustom(map, GMode, LimT, LimS, Lives, Opt, n)
6577 else
6578 g_Game_StartServer(map, GMode, LimT, LimS, Lives, Opt, n, 0, Port);
6579 end;
6581 // Execute script when game loads:
6582 s := Find_Param_Value(pars, '-exec');
6583 if s <> '' then
6584 begin
6585 if Pos(':\', s) = 0 then
6586 s := GameDir + '/' + s;
6588 {$I-}
6589 AssignFile(F, s);
6590 Reset(F);
6591 if IOResult <> 0 then
6592 begin
6593 e_WriteLog(Format(_lc[I_SIMPLE_ERROR], ['Failed to read file: ' + s]), MSG_WARNING);
6594 g_Console_Add(Format(_lc[I_CONSOLE_ERROR_READ], [s]));
6595 CloseFile(F);
6596 Exit;
6597 end;
6598 e_WriteLog('Executing script: ' + s, MSG_NOTIFY);
6599 g_Console_Add(Format(_lc[I_CONSOLE_EXEC], [s]));
6601 while not EOF(F) do
6602 begin
6603 ReadLn(F, s);
6604 if IOResult <> 0 then
6605 begin
6606 e_WriteLog(Format(_lc[I_SIMPLE_ERROR], ['Failed to read file: ' + s]), MSG_WARNING);
6607 g_Console_Add(Format(_lc[I_CONSOLE_ERROR_READ], [s]));
6608 CloseFile(F);
6609 Exit;
6610 end;
6611 if Pos('#', s) <> 1 then // script comment
6612 g_Console_Process(s, True);
6613 end;
6615 CloseFile(F);
6616 {$I+}
6617 end;
6619 SetLength(pars, 0);
6620 end;
6622 end.