DEADSOFTWARE

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