DEADSOFTWARE

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