DEADSOFTWARE

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