DEADSOFTWARE

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