DEADSOFTWARE

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