DEADSOFTWARE

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