DEADSOFTWARE

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