DEADSOFTWARE

more buffer fixes (?)
[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;
18
19 interface
20
21 uses
22 g_basic, g_player, e_graphics, Classes, g_res_downloader,
23 SysUtils, g_sound, g_gui, MAPSTRUCT, wadreader, md5;
24
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;
36
37 TGameEvent = record
38 Name: String;
39 Command: String;
40 end;
41
42 TDelayedEvent = record
43 Pending: Boolean;
44 Time: LongWord;
45 DEType: Byte;
46 DENum: Integer;
47 DEStr: String;
48 end;
49
50 TPlayerSettings = record
51 Name: String;
52 Model: String;
53 Color: TRGB;
54 Team: Byte;
55 end;
56
57 TMegaWADInfo = record
58 Name: String;
59 Description: String;
60 Author: String;
61 Pic: String;
62 end;
63
64 THearPoint = record
65 Active: Boolean;
66 Coords: TPoint;
67 end;
68
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();
133
134 { procedure SetWinPause(Enable: Boolean); }
135
136 const
137 GAME_TICK = 28;
138
139 LOADING_SHOW_STEP = 100;
140 LOADING_INTERLINE = 20;
141
142 GT_NONE = 0;
143 GT_SINGLE = 1;
144 GT_CUSTOM = 2;
145 GT_SERVER = 3;
146 GT_CLIENT = 4;
147
148 GM_NONE = 0;
149 GM_DM = 1;
150 GM_TDM = 2;
151 GM_CTF = 3;
152 GM_COOP = 4;
153 GM_SINGLE = 5;
154
155 MESSAGE_DIKEY = WM_USER + 1;
156
157 EXIT_QUIT = 1;
158 EXIT_SIMPLE = 2;
159 EXIT_RESTART = 3;
160 EXIT_ENDLEVELSINGLE = 4;
161 EXIT_ENDLEVELCUSTOM = 5;
162
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;
170
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;
180
181 LMS_RESPAWN_NONE = 0;
182 LMS_RESPAWN_WARMUP = 1;
183 LMS_RESPAWN_FINAL = 2;
184
185 SPECT_NONE = 0;
186 SPECT_STATS = 1;
187 SPECT_MAPVIEW = 2;
188 SPECT_PLAYERS = 3;
189
190 DE_GLOBEVENT = 0;
191 DE_BFGHIT = 1;
192 DE_KILLCOMBO = 2;
193
194 ANNOUNCE_NONE = 0;
195 ANNOUNCE_ME = 1;
196 ANNOUNCE_MEPLUS = 2;
197 ANNOUNCE_ALL = 3;
198
199 CONFIG_FILENAME = 'Doom2DF.cfg';
200 LOG_FILENAME = 'Doom2DF.log';
201
202 TEST_MAP_NAME = '$$$_TEST_$$$';
203
204 STD_PLAYER_MODEL = 'Doomer';
205
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;
302
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;
311
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);
315
316 implementation
317
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;
326
327 type
328 TDynLight = record
329 x, y, radius: Integer;
330 r, g, b, a: Single;
331 exploCount: Integer;
332 exploRadius: Integer;
333 end;
334
335 var
336 g_dynLights: array of TDynLight = nil;
337 g_dynLightCount: Integer = 0;
338 g_playerLight: Boolean = false;
339
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;
368
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;
383
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;
399
400
401 type
402 TEndCustomGameStat = record
403 PlayerStat: TPlayerStatArray;
404 TeamStat: TTeamStat;
405 GameTime: LongWord;
406 GameMode: Byte;
407 Map, MapName: String;
408 end;
409
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;
419
420 TLoadingStat = record
421 CurValue: Integer;
422 MaxValue: Integer;
423 ShowCount: Integer;
424 Msgs: Array of String;
425 NextMsg: Word;
426 end;
427
428 TParamStrValue = record
429 Name: String;
430 Value: String;
431 end;
432
433 TParamStrValues = Array of TParamStrValue;
434
435 const
436 INTER_ACTION_TEXT = 1;
437 INTER_ACTION_PIC = 2;
438 INTER_ACTION_MUSIC = 3;
439
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;
483
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;
495
496 procedure SortGameStat(var stat: TPlayerStatArray);
497 var
498 I, J: Integer;
499 T: TPlayerStat;
500 begin
501 if stat = nil then Exit;
502
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;
512
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;
524
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;
555
556 function g_Game_IsNet(): Boolean;
557 begin
558 Result := (gGameSettings.GameType in [GT_SERVER, GT_CLIENT]);
559 end;
560
561 function g_Game_IsServer(): Boolean;
562 begin
563 Result := (gGameSettings.GameType in [GT_SINGLE, GT_CUSTOM, GT_SERVER]);
564 end;
565
566 function g_Game_IsClient(): Boolean;
567 begin
568 Result := (gGameSettings.GameType = GT_CLIENT);
569 end;
570
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 := '';
581
582 w := TWADFile.Create();
583 w.ReadFile(WAD);
584
585 if not w.GetResource('INTERSCRIPT', p, len) then
586 begin
587 w.Free();
588 Exit;
589 end;
590
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();
597
598 FreeMem(p);
599 end;
600
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]);
608
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]);
612
613 MegaWAD.res.pic := nil;
614 MegaWAD.res.text := nil;
615 MegaWAD.res.anim := nil;
616 MegaWAD.res.mus := nil;
617 MegaWAD.triggers := nil;
618
619 g_Texture_Delete('TEXTURE_endpic');
620 g_Sound_Delete('MUSIC_endmus');
621
622 ZeroMemory(@MegaWAD, SizeOf(MegaWAD));
623 gGameSettings.WAD := '';
624 end;
625
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;
638
639 MegaWAD.info := g_Game_GetMegaWADInfo(MapsDir + WAD);
640
641 w := TWADFile.Create();
642 w.ReadFile(MapsDir + WAD);
643
644 if not w.GetResource('INTERSCRIPT', p, len) then
645 begin
646 w.Free();
647 Exit;
648 end;
649
650 cfg := TConfig.CreateMem(p, len);
651
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;
658
659 SetLength(MegaWAD.res.pic, Length(MegaWAD.res.pic)+1);
660 MegaWAD.res.pic[High(MegaWAD.res.pic)] := s;
661
662 g_Texture_CreateWADEx(s, s);
663 end;
664
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;
671
672 SetLength(MegaWAD.res.mus, Length(MegaWAD.res.mus)+1);
673 MegaWAD.res.mus[High(MegaWAD.res.mus)] := s;
674
675 g_Music_CreateWADEx(s, s);
676 end;}
677
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;
692
693 cfg.Free();
694 FreeMem(p);
695 w.Free();
696 end;
697
698 {procedure start_trigger(t: string);
699 begin
700 end;
701
702 function next_trigger(): Boolean;
703 begin
704 end;}
705
706 procedure DisableCheats();
707 begin
708 MAX_RUNVEL := 8;
709 VEL_JUMP := 10;
710 gFly := False;
711
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;
717
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;
734
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;
762
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));
770
771 // Ñòîï èãðà:
772 gPause := False;
773 gGameOn := False;
774
775 g_Game_StopAllSounds(False);
776
777 MessageTime := 0;
778 MessageText := '';
779
780 EndingGameCounter := 0;
781 g_ActiveWindow := nil;
782
783 gLMSRespawn := LMS_RESPAWN_NONE;
784 gLMSRespawnTime := 0;
785
786 case gExit of
787 EXIT_SIMPLE: // Âûõîä ÷åðåç ìåíþ èëè êîíåö òåñòà
788 begin
789 g_Game_Free();
790
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;
815
816 g_Game_ExecuteEvent('ongameend');
817 end;
818 end;
819
820 EXIT_RESTART: // Íà÷àòü óðîâåíü ñíà÷àëà
821 begin
822 if not g_Game_IsClient then g_Game_Restart();
823 end;
824
825 EXIT_ENDLEVELCUSTOM: // Çàêîí÷èëñÿ óðîâåíü â Ñâîåé èãðå
826 begin
827 // Ñòàòèñòèêà Ñâîåé èãðû:
828 FileName := g_ExtractWadName(gMapInfo.Map);
829
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;
836
837 CustomStat.PlayerStat := nil;
838
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;
857
858 SortGameStat(CustomStat.PlayerStat);
859 end;
860
861 g_Game_ExecuteEvent('onmapend');
862
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;
872
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;
888
889 g_Game_ExecuteEvent('onmapend');
890
891 // Åñòü åùå êàðòû:
892 if gNextMap <> '' then
893 begin
894 gMusic.SetByName('MUSIC_INTERMUS');
895 gMusic.Play();
896 gState := STATE_INTERSINGLE;
897
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;
908
909 // Îêîí÷àíèå îáðàáîòàíî:
910 if gExit <> EXIT_QUIT then
911 gExit := 0;
912 end;
913
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);
931
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);
939
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);
942
943 wad := g_ExtractWadNameNoPath(gMapInfo.Map);
944 map := g_ExtractFileName(gMapInfo.Map);
945 mapstr := wad + ':\' + map + ' - ' + gMapInfo.Name;
946
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;
957
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;
967
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;
974
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;
984
985 else
986 begin
987 s1 := '';
988 s2 := '';
989 end;
990 end;
991
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);
998
999 e_TextureFontPrintEx(x+w-16-(Length(s3))*cw, _y, s3,
1000 gStdFont, 200, 200, 200, 1);
1001
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);
1008
1009 if pc = 0 then
1010 Exit;
1011 stat := g_Player_GetStats();
1012 SortGameStat(stat);
1013
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; // îñòàâøååñÿ ïðîñòðàíñòâî - äëÿ öâåòà è èìåíè èãðîêà
1018
1019 if gGameSettings.GameMode in [GM_TDM, GM_CTF] then
1020 begin
1021 _y := _y+ch+ch;
1022
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;
1039
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);
1043
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);
1047
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;
1074
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);
1085
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;
1115
1116 procedure g_Game_Init();
1117 var
1118 SR: TSearchRec;
1119 begin
1120 gExit := 0;
1121 gMapToDelete := '';
1122 gTempDelete := False;
1123
1124 sfsGCDisable(); // temporary disable removing of temporary volumes
1125
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');
1131
1132 LoadStdFont('STDTXT', 'STDFONT', gStdFont);
1133 LoadFont('MENUTXT', 'MENUFONT', gMenuFont);
1134 LoadFont('SMALLTXT', 'SMALLFONT', gMenuSmallFont);
1135
1136 g_Game_ClearLoading();
1137 g_Game_SetLoadingText(Format('Doom 2D: Forever %s', [GAME_VERSION]), 0, False);
1138 g_Game_SetLoadingText('', 0, False);
1139
1140 g_Game_SetLoadingText(_lc[I_LOAD_CONSOLE], 0, False);
1141 g_Console_Init();
1142
1143 g_Game_SetLoadingText(_lc[I_LOAD_MODELS], 0, False);
1144 g_PlayerModel_LoadData();
1145
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);
1152
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);
1159
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);
1166
1167 gGameOn := False;
1168 gPause := False;
1169 gTime := 0;
1170 LastScreenShot := 0;
1171
1172 {e_MouseInfo.Accel := 1.0;}
1173
1174 g_Game_SetLoadingText(_lc[I_LOAD_GAME_DATA], 0, False);
1175 g_Game_LoadData();
1176
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);
1182
1183 g_Game_SetLoadingText(_lc[I_LOAD_MENUS], 0, False);
1184 g_Menu_Init();
1185
1186 gMusic := TMusic.Create();
1187 gMusic.SetByName('MUSIC_MENU');
1188 gMusic.Play();
1189
1190 gGameSettings.WarmupTime := 30;
1191
1192 gState := STATE_MENU;
1193
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;
1205
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();
1210
1211 g_Map_Free();
1212 g_Player_Free();
1213 g_Player_RemoveAllCorpses();
1214
1215 gGameSettings.GameType := GT_NONE;
1216 if gGameSettings.GameMode = GM_SINGLE then
1217 gGameSettings.GameMode := GM_DM;
1218 gSwitchGameMode := gGameSettings.GameMode;
1219
1220 gChatShow := False;
1221 gExitByTrigger := False;
1222 end;
1223
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;
1231
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;
1250
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;
1276
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;
1302
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;
1309
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; // Íå íàæàòû íè "Âëåâî", íè "Âïðàâî"
1325
1326 // Ñåé÷àñ èëè ðàíüøå áûëè íàæàòû "Âëåâî"/"Âïðàâî" => ïåðåäàåì èãðîêó:
1327 if MoveButton = 1 then plr.PressKey(KEY_LEFT, time)
1328 else if MoveButton = 2 then plr.PressKey(KEY_RIGHT, time);
1329
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;
1349
1350 // fix movebutton state
1351 MoveButton := MoveButton or (strafeDir shl 4);
1352
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);
1361
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;
1366
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;
1379
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;
1382
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;
1402
1403 // ×èòàåì êëàâèàòóðó è äæîéñòèê, åñëè îêíî àêòèâíî:
1404 e_PollInput();
1405
1406 // Îáíîâëÿåì êîíñîëü (äâèæåíèå è ñîîáùåíèÿ):
1407 g_Console_Update();
1408
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;
1415
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;
1432
1433 if (not g_Game_IsClient) and
1434 (
1435 (
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)
1439 )
1440 or (g_Game_IsNet and (gInterTime > gInterEndTime))
1441 )
1442 then
1443 begin // Íàæàëè <Enter>/<Ïðîáåë> èëè ïðîøëî äîñòàòî÷íî âðåìåíè:
1444 g_Game_StopAllSounds(True);
1445
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;
1473
1474 Exit;
1475 end;
1476
1477 if gState = STATE_INTERTEXT then
1478 if InterText.counter > 0 then
1479 InterText.counter := InterText.counter - 1;
1480 end;
1481
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');
1497
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;
1512
1513 STATE_ENDPIC: // Êàðòèíêà îêîí÷àíèÿ ìåãàÂàäà
1514 begin
1515 if gMapOnce then // Ýòî áûë òåñò
1516 begin
1517 gExit := EXIT_SIMPLE;
1518 Exit;
1519 end;
1520 end;
1521
1522 STATE_SLIST:
1523 g_Serverlist_Control(slCurrent);
1524 end;
1525
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;
1543
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);
1549
1550 // Èãðà èäåò:
1551 if gGameOn and not gPause and (gState <> STATE_FOLD) then
1552 begin
1553 // Âðåìÿ += 28 ìèëëèñåêóíä:
1554 gTime := gTime + GAME_TICK;
1555
1556 // Ñîîáùåíèå ïîñåðåäèíå ýêðàíà:
1557 if MessageTime = 0 then
1558 MessageText := '';
1559 if MessageTime > 0 then
1560 MessageTime := MessageTime - 1;
1561
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;
1571
1572 // Íàäî ðåñïàâíèòü èãðîêîâ â LMS:
1573 if (gLMSRespawn > LMS_RESPAWN_NONE) and (gLMSRespawnTime < gTime) then
1574 g_Game_RestartRound(gLMSSoftSpawn);
1575
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;
1585
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;
1591
1592 // Áûë çàäàí ëèìèò ïîáåä:
1593 if (gGameSettings.GoalLimit > 0) then
1594 begin
1595 b := 0;
1596
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;
1609
1610 // Ëèìèò ïîáåä íàáðàí => êîíåö óðîâíÿ:
1611 if b >= gGameSettings.GoalLimit then
1612 begin
1613 g_Game_NextLevel();
1614 Exit;
1615 end;
1616 end;
1617
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
1632
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;
1723
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;
1740
1741 if (gSoundTriggerTime > 8) then
1742 begin
1743 g_Game_UpdateTriggerSounds();
1744 gSoundTriggerTime := 0;
1745 end
1746 else
1747 Inc(gSoundTriggerTime);
1748
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);
1758
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;
1775
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);
1785
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;
1802
1803 NetTimeToUpdate := 0;
1804 end;
1805
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]);
1812
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 ...
1821
1822 // Àêòèâíî îêíî èíòåðôåéñà - ïåðåäàåì êëàâèøè åìó:
1823 if g_ActiveWindow <> nil then
1824 begin
1825 w := e_GetFirstKeyPressed();
1826
1827 if (w <> IK_INVALID) then
1828 begin
1829 Msg.Msg := MESSAGE_DIKEY;
1830 Msg.wParam := w;
1831 g_ActiveWindow.OnMessage(Msg);
1832 end;
1833
1834 // Åñëè îíî îò ýòîãî íå çàêðûëîñü, òî îáíîâëÿåì:
1835 if g_ActiveWindow <> nil then
1836 g_ActiveWindow.Update();
1837
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;
1845
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;
1856
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;
1864
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;
1873
1874 Time := GetTimer() {div 1000};
1875
1876 // Îáðàáîòêà îòëîæåííûõ ñîáûòèé:
1877 if gDelayedEvents <> nil then
1878 for a := 0 to High(gDelayedEvents) do
1879 if gDelayedEvents[a].Pending and
1880 (
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;
1901
1902 // Êàæäóþ ñåêóíäó îáíîâëÿåì ñ÷åò÷èê îáíîâëåíèé:
1903 UPSCounter := UPSCounter + 1;
1904 if Time - UPSTime >= 1000 then
1905 begin
1906 UPS := UPSCounter;
1907 UPSCounter := 0;
1908 UPSTime := Time;
1909 end;
1910
1911 if gGameOn then g_Weapon_AddDynLights();
1912 end;
1913
1914 procedure g_Game_LoadData();
1915 begin
1916 if DataLoaded then Exit;
1917
1918 e_WriteLog('Loading game data...', MSG_NOTIFY);
1919
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');
1954
1955 goodsnd[0] := TPlayableSound.Create();
1956 goodsnd[1] := TPlayableSound.Create();
1957 goodsnd[2] := TPlayableSound.Create();
1958 goodsnd[3] := TPlayableSound.Create();
1959
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');
1964
1965 killsnd[0] := TPlayableSound.Create();
1966 killsnd[1] := TPlayableSound.Create();
1967 killsnd[2] := TPlayableSound.Create();
1968 killsnd[3] := TPlayableSound.Create();
1969
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');
1974
1975 g_Game_SetLoadingText(_lc[I_LOAD_ITEMS_DATA], 0, False);
1976 g_Items_LoadData();
1977
1978 g_Game_SetLoadingText(_lc[I_LOAD_WEAPONS_DATA], 0, False);
1979 g_Weapon_LoadData();
1980
1981 g_Monsters_LoadData();
1982
1983 DataLoaded := True;
1984 end;
1985
1986 procedure g_Game_FreeData();
1987 begin
1988 if not DataLoaded then Exit;
1989
1990 g_Items_FreeData();
1991 g_Weapon_FreeData();
1992 g_Monsters_FreeData();
1993
1994 e_WriteLog('Releasing game data...', MSG_NOTIFY);
1995
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');
2019
2020 goodsnd[0].Free();
2021 goodsnd[1].Free();
2022 goodsnd[2].Free();
2023 goodsnd[3].Free();
2024
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');
2029
2030 killsnd[0].Free();
2031 killsnd[1].Free();
2032 killsnd[2].Free();
2033 killsnd[3].Free();
2034
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');
2039
2040 DataLoaded := False;
2041 end;
2042
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);
2053
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;
2065
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;
2075
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];
2085
2086 e_CharFont_GetSize(gMenuFont, topstr, ww1, hh1);
2087 e_CharFont_Print(gMenuFont, (gScreenWidth div 2)-(ww1 div 2), 16, topstr);
2088
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;
2096
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);
2104
2105 x := 32;
2106 y := 16+hh1+16;
2107
2108 w := gScreenWidth-x*2;
2109
2110 w2 := (w-16) div 6;
2111 w3 := w2;
2112 w1 := w-16-w2-w3;
2113
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);
2116
2117 m := Max(Length(_lc[I_MENU_MAP])+1, Length(_lc[I_GAME_GAME_TIME])+1)*ww2;
2118
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;
2144
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;
2148
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);
2152
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);
2158
2159 pc := Length(CustomStat.PlayerStat);
2160 if pc = 0 then Exit;
2161
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;
2186
2187 if CustomStat.GameMode in [GM_TDM, GM_CTF] then
2188 begin
2189 _y := _y+16+16;
2190
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];
2195
2196 e_TextureFontPrintEx(x+8+(w div 2)-(Length(s1)*ww2 div 2), _y, s1, gStdFont, 255, 255, 255, 1);
2197 _y := _y+40;
2198
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;
2221
2222 e_DrawLine(1, x+8, _y+20, x-8+w, _y+20, r, g, b);
2223 _y := _y+24;
2224
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;
2246
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);
2256
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);
2262
2263 if Spectator then
2264 r := 127
2265 else
2266 r := 255;
2267
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;
2275
2276 procedure DrawSingleStat();
2277 var
2278 tm, key_x, val_x, y: Integer;
2279 w1, w2, h: Word;
2280 s1, s2: String;
2281
2282 procedure player_stat(n: Integer);
2283 var
2284 kpm: Real;
2285
2286 begin
2287 // "Kills: # / #":
2288 s1 := Format(' %d ', [SingleStat.PlayerStat[n].Kills]);
2289 s2 := Format(' %d', [gTotalMonsters]);
2290
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));
2298
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]);
2306
2307 e_CharFont_Print(gMenuFont, key_x, y+32, s1);
2308 e_CharFont_PrintEx(gMenuFont, val_x, y+32, s2, _RGB(255, 0, 0));
2309
2310 // "Secrets found: # / #":
2311 s1 := Format(' %d ', [SingleStat.PlayerStat[n].Secrets]);
2312 s2 := Format(' %d', [SingleStat.TotalSecrets]);
2313
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;
2322
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]);
2327
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);
2334
2335 key_x := (gScreenWidth-w1-w2) div 2;
2336 val_x := key_x + w1;
2337
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]);
2342
2343 e_CharFont_Print(gMenuFont, key_x, 80, s1);
2344 e_CharFont_PrintEx(gMenuFont, val_x, 80, s2, _RGB(255, 0, 0));
2345
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);
2352
2353 // Ñòàòèñòèêà ïåðâîãî èãðîêà:
2354 y := 176;
2355 player_stat(0);
2356
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);
2361
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;
2373
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;
2382
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);
2387
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];
2395
2396 e_CharFont_PrintEx(gMenuSmallFont, xx, yy, s, _RGB(255, 0, 0));
2397 yy := yy + LOADING_INTERLINE;
2398 end;
2399 end;
2400
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);
2416
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;
2433
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;
2457
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;
2477
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;
2502
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;
2522
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;
2542
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;
2561
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;
2587
2588 e_DrawFillQuad(aX, aY, aX2, aY2, 255, 255, 0, 0);
2589 end;
2590 end;
2591 end;
2592 end;
2593
2594 procedure DrawMapView(x, y, w, h: Integer);
2595 var
2596 bx, by: Integer;
2597 begin
2598 glPushMatrix();
2599
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);
2603
2604 sX := x;
2605 sY := y;
2606 sWidth := w;
2607 sHeight := h;
2608
2609 glTranslatef(-x, -y, 0);
2610
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;
2632
2633 glPopMatrix();
2634 end;
2635
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;
2650
2651 gPlayerDrawn := p;
2652
2653 glPushMatrix();
2654
2655 px := p.GameX + PLAYER_RECT_CX;
2656 py := p.GameY + PLAYER_RECT_CY;
2657
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;
2674
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;
2682
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;
2688
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;
2693
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;
2699
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));
2708
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));
2717
2718 g_Map_DrawBack(-c, -d);
2719
2720 sX := -a;
2721 sY := -(b+p.IncCam);
2722 sWidth := gPlayerScreenSize.X;
2723 sHeight := gPlayerScreenSize.Y;
2724
2725 glTranslatef(a, b+p.IncCam, 0);
2726
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);
2742
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);
2754
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;
2761
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;
2766
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;
2793
2794 // done
2795 glDisable(GL_STENCIL_TEST);
2796 glDisable(GL_BLEND);
2797 glDisable(GL_SCISSOR_TEST);
2798 glScissor(0, 0, sWidth, sHeight);
2799 end;
2800
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;
2807
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);
2812 {
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;
2821
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;
2828 }
2829
2830 glPopMatrix();
2831
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;
2840
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;
2852
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;
2861
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;
2893
2894 if (plView1 = nil) and (plView2 = nil) and (gSpectMode = SPECT_NONE) then
2895 gSpectMode := SPECT_STATS;
2896
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;
2916
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);
2931
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;
2947
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;
2958
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);
2964
2965 DrawPlayer(plView1);
2966 gPlayer1ScreenCoord.X := sX;
2967 gPlayer1ScreenCoord.Y := sY;
2968
2969 if Split then
2970 begin
2971 e_SetViewPort(0, 0, gPlayerScreenSize.X+196, gPlayerScreenSize.Y);
2972
2973 DrawPlayer(plView2);
2974 gPlayer2ScreenCoord.X := sX;
2975 gPlayer2ScreenCoord.Y := sY;
2976 end;
2977
2978 e_SetViewPort(0, 0, gScreenWidth, gScreenHeight);
2979
2980 if Split then
2981 e_DrawLine(2, 0, gScreenHeight div 2, gScreenWidth, gScreenHeight div 2, 0, 0, 0);
2982 end;
2983
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;
2996
2997 if IsDrawStat or (gSpectMode = 1) then DrawStat();
2998
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;
3041
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);
3045
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;
3050
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;
3064
3065 if gState = STATE_FOLD then
3066 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 0, 0, 0, EndingGameCounter);
3067
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';
3078
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);
3083
3084 DrawCustomStat();
3085
3086 if g_ActiveWindow <> nil then
3087 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
3088 end;
3089
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';
3097
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);
3102
3103 DrawSingleStat();
3104
3105 if g_ActiveWindow <> nil then
3106 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
3107 end;
3108 end;
3109
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);
3115
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);
3120
3121 if g_ActiveWindow <> nil then
3122 e_DrawFillQuad(0, 0, gScreenWidth-1, gScreenHeight-1, 48, 48, 48, 180);
3123 end;
3124
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;
3135
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;
3142
3143 g_Console_Draw();
3144
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;
3151
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;
3157
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;
3163
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();
3174
3175 if NetInitDone then g_Net_Free;
3176
3177 // Íàäî óäàëèòü êàðòó ïîñëå òåñòà:
3178 if gMapToDelete <> '' then
3179 g_Game_DeleteTestMap();
3180
3181 gExit := EXIT_QUIT;
3182 PushExitEvent();
3183 end;
3184
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);
3189
3190 gExit := EXIT_SIMPLE;
3191 end;
3192
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;
3198
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;
3209
3210 // Ðàçìåð çàäíåãî ïëàíà:
3211 if BackID <> DWORD(-1) then
3212 begin
3213 d := SKY_STRETCH;
3214
3215 if (gScreenWidth*d > gMapInfo.Width) or
3216 (gScreenHeight*d > gMapInfo.Height) then
3217 d := 1.0;
3218
3219 gBackSize.X := Round(gScreenWidth*d);
3220 gBackSize.Y := Round(gScreenHeight*d);
3221 end;
3222 end;
3223
3224 procedure g_Game_ChangeResolution(newWidth, newHeight: Word; nowFull, nowMax: Boolean);
3225 begin
3226 g_Window_SetSize(newWidth, newHeight, nowFull);
3227 end;
3228
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;
3245
3246 if not (Team in [TEAM_RED, TEAM_BLUE]) then
3247 Team := gPlayer1Settings.Team;
3248
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);
3262
3263 if g_Game_IsNet and NetUseMaster then
3264 g_Net_Slist_Update;
3265 end;
3266
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;
3277
3278 if not (Team in [TEAM_RED, TEAM_BLUE]) then
3279 Team := gPlayer2Settings.Team;
3280
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);
3294
3295 if g_Game_IsNet and NetUseMaster then
3296 g_Net_Slist_Update;
3297 end;
3298
3299 Exit;
3300 end;
3301 end;
3302
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);
3319
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);
3335
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;
3346
3347 procedure g_Game_Spectate();
3348 begin
3349 g_Game_RemovePlayer();
3350 if gPlayer1 <> nil then
3351 g_Game_RemovePlayer();
3352 end;
3353
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;
3359
3360 procedure g_Game_StartSingle(Map: String; TwoPlayers: Boolean; nPlayers: Byte);
3361 var
3362 i, nPl: Integer;
3363 begin
3364 g_Game_Free();
3365
3366 e_WriteLog('Starting singleplayer game...', MSG_NOTIFY);
3367
3368 g_Game_ClearLoading();
3369
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;
3380
3381 g_Game_ExecuteEvent('ongamestart');
3382
3383 // Óñòàíîâêà ðàçìåðîâ îêîí èãðîêîâ:
3384 g_Game_SetupScreenSize();
3385
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;
3395
3396 gPlayer1.Name := gPlayer1Settings.Name;
3397 nPl := 1;
3398
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;
3410
3411 gPlayer2.Name := gPlayer2Settings.Name;
3412 Inc(nPl);
3413 end;
3414
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;
3421
3422 // Íàñòðîéêè èãðîêîâ è áîòîâ:
3423 g_Player_Init();
3424
3425 // Ñîçäàåì áîòîâ:
3426 for i := nPl+1 to nPlayers do
3427 g_Player_Create(STD_PLAYER_MODEL, _RGB(0, 0, 0), 0, True);
3428 end;
3429
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();
3438
3439 e_WriteLog('Starting custom game...', MSG_NOTIFY);
3440
3441 g_Game_ClearLoading();
3442
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;
3451
3452 gCoopTotalMonstersKilled := 0;
3453 gCoopTotalSecretsFound := 0;
3454 gCoopTotalMonsters := 0;
3455 gCoopTotalSecrets := 0;
3456 gAimLine := False;
3457 gShowMap := False;
3458
3459 g_Game_ExecuteEvent('ongamestart');
3460
3461 // Óñòàíîâêà ðàçìåðîâ îêîí èãðîêîâ:
3462 g_Game_SetupScreenSize();
3463
3464 // Ðåæèì íàáëþäàòåëÿ:
3465 if nPlayers = 0 then
3466 begin
3467 gPlayer1 := nil;
3468 gPlayer2 := nil;
3469 end;
3470
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;
3483
3484 gPlayer1.Name := gPlayer1Settings.Name;
3485 Inc(nPl);
3486 end;
3487
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;
3499
3500 gPlayer2.Name := gPlayer2Settings.Name;
3501 Inc(nPl);
3502 end;
3503
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;
3510
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;
3521
3522 // Íàñòðîéêè èãðîêîâ è áîòîâ:
3523 g_Player_Init();
3524
3525 // Ñîçäàåì áîòîâ:
3526 for i := nPl+1 to nPlayers do
3527 g_Player_Create(STD_PLAYER_MODEL, _RGB(0, 0, 0), 0, True);
3528 end;
3529
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();
3536
3537 e_WriteLog('Starting net game (server)...', MSG_NOTIFY);
3538
3539 g_Game_ClearLoading();
3540
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;
3549
3550 gCoopTotalMonstersKilled := 0;
3551 gCoopTotalSecretsFound := 0;
3552 gCoopTotalMonsters := 0;
3553 gCoopTotalSecrets := 0;
3554 gAimLine := False;
3555 gShowMap := False;
3556
3557 g_Game_ExecuteEvent('ongamestart');
3558
3559 // Óñòàíîâêà ðàçìåðîâ îêíà èãðîêà
3560 g_Game_SetupScreenSize();
3561
3562 // Ðåæèì íàáëþäàòåëÿ:
3563 if nPlayers = 0 then
3564 begin
3565 gPlayer1 := nil;
3566 gPlayer2 := nil;
3567 end;
3568
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;
3580
3581 gPlayer1.Name := gPlayer1Settings.Name;
3582 end;
3583
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;
3595
3596 gPlayer2.Name := gPlayer2Settings.Name;
3597 end;
3598
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;
3605
3606 g_Net_Slist_Set(NetSlistIP, NetSlistPort);
3607
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;
3614
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;
3625
3626 // Íàñòðîéêè èãðîêîâ è áîòîâ:
3627 g_Player_Init();
3628
3629 NetState := NET_STATE_GAME;
3630 end;
3631
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();
3645
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);
3649
3650 g_Game_ClearLoading();
3651
3652 // Íàñòðîéêè èãðû:
3653 gGameSettings.GameType := GT_CLIENT;
3654
3655 gCoopTotalMonstersKilled := 0;
3656 gCoopTotalSecretsFound := 0;
3657 gCoopTotalMonsters := 0;
3658 gCoopTotalSecrets := 0;
3659 gAimLine := False;
3660 gShowMap := False;
3661
3662 g_Game_ExecuteEvent('ongamestart');
3663
3664 // Óñòàíîâêà ðàçìåðîâ îêîí èãðîêîâ:
3665 g_Game_SetupScreenSize();
3666
3667 NetState := NET_STATE_AUTH;
3668
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;
3677
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);
3681
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);
3691
3692 while (State = 0) and (RawPos < NetEvent.packet^.dataLength) do
3693 begin
3694 Len := e_Raw_Read_Word(Ptr);
3695 if Len = 0 then break;
3696
3697 MID := e_Raw_Read_Byte(Ptr);
3698 if NetDump then
3699 g_Net_DumpRecvBuffer(NetEvent.packet^.data, NetEvent.packet^.dataLength);
3700
3701 if (MID = NET_MSG_INFO) and (State = 0) then
3702 begin
3703 NetMyID := e_Raw_Read_Byte(Ptr);
3704 NetPlrUID1 := e_Raw_Read_Word(Ptr);
3705
3706 WadName := e_Raw_Read_String(Ptr);
3707 Map := e_Raw_Read_String(Ptr);
3708
3709 gWADHash := e_Raw_Read_MD5(Ptr);
3710
3711 gGameSettings.GameMode := e_Raw_Read_Byte(Ptr);
3712 gSwitchGameMode := gGameSettings.GameMode;
3713 gGameSettings.GoalLimit := e_Raw_Read_Word(Ptr);
3714 gGameSettings.TimeLimit := e_Raw_Read_Word(Ptr);
3715 gGameSettings.MaxLives := e_Raw_Read_Byte(Ptr);
3716 gGameSettings.Options := e_Raw_Read_LongWord(Ptr);
3717 T := e_Raw_Read_LongWord(Ptr);
3718
3719 newResPath := g_Res_SearchSameWAD(MapsDir, WadName, gWADHash);
3720 if newResPath = '' then
3721 begin
3722 g_Game_SetLoadingText(_lc[I_LOAD_DL_RES], 0, False);
3723 newResPath := ''; //g_Res_DownloadWAD(WadName);
3724 if newResPath = '' then
3725 begin
3726 g_FatalError(_lc[I_NET_ERR_HASH]);
3727 enet_packet_destroy(NetEvent.packet);
3728 NetState := NET_STATE_NONE;
3729 Exit;
3730 end;
3731 end;
3732 newResPath := ExtractRelativePath(MapsDir, newResPath);
3733
3734 gPlayer1 := g_Player_Get(g_Player_Create(gPlayer1Settings.Model,
3735 gPlayer1Settings.Color,
3736 gPlayer1Settings.Team, False));
3737
3738 if gPlayer1 = nil then
3739 begin
3740 g_FatalError(Format(_lc[I_GAME_ERROR_PLAYER_CREATE], [1]));
3741
3742 enet_packet_destroy(NetEvent.packet);
3743 NetState := NET_STATE_NONE;
3744 Exit;
3745 end;
3746
3747 gPlayer1.Name := gPlayer1Settings.Name;
3748 gPlayer1.UID := NetPlrUID1;
3749 gPlayer1.Reset(True);
3750
3751 if not g_Game_StartMap(newResPath + ':\' + Map, True) then
3752 begin
3753 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [WadName + ':\' + Map]));
3754
3755 enet_packet_destroy(NetEvent.packet);
3756 NetState := NET_STATE_NONE;
3757 Exit;
3758 end;
3759
3760 gTime := T;
3761
3762 State := 1;
3763 OuterLoop := False;
3764 enet_packet_destroy(NetEvent.packet);
3765 break;
3766 end
3767 else
3768 RawPos := RawPos + Len-1;
3769 end;
3770 if State = 1 then break;
3771 end
3772 else
3773 if (NetEvent.kind = ENET_EVENT_TYPE_DISCONNECT) then
3774 begin
3775 State := 0;
3776 if (NetEvent.data <= NET_DISC_MAX) then
3777 g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_ERR_CONN] + ' ' +
3778 _lc[TStrings_Locale(Cardinal(I_NET_DISC_NONE) + NetEvent.data)], True);
3779 OuterLoop := False;
3780 Break;
3781 end;
3782 end;
3783
3784 ProcessLoading();
3785
3786 e_PollInput();
3787
3788 if e_KeyPressed(IK_ESCAPE) or e_KeyPressed(IK_SPACE) then
3789 begin
3790 State := 0;
3791 break;
3792 end;
3793 end;
3794
3795 if State <> 1 then
3796 begin
3797 g_FatalError(_lc[I_NET_MSG] + _lc[I_NET_ERR_CONN]);
3798 NetState := NET_STATE_NONE;
3799 Exit;
3800 end;
3801
3802 gLMSRespawn := LMS_RESPAWN_NONE;
3803 gLMSRespawnTime := 0;
3804
3805 g_Player_Init();
3806 NetState := NET_STATE_GAME;
3807 MC_SEND_FullStateRequest();
3808 e_WriteLog('NET: Connection successful.', MSG_NOTIFY);
3809 end;
3810
3811 procedure g_Game_SaveOptions();
3812 begin
3813 g_Options_Write_Video(GameDir+'/'+CONFIG_FILENAME);
3814 end;
3815
3816 procedure g_Game_ChangeMap(MapPath: String);
3817 var
3818 Force: Boolean;
3819 begin
3820 g_Game_ClearLoading();
3821
3822 Force := gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF];
3823 // Åñëè óðîâåíü çàâåðøèëñÿ ïî òðèããåðó Âûõîä, íå î÷èùàòü èíâåíòàðü
3824 if gExitByTrigger then
3825 begin
3826 Force := False;
3827 gExitByTrigger := False;
3828 end;
3829 if not g_Game_StartMap(MapPath, Force) then
3830 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_LOAD], [MapPath]));
3831 end;
3832
3833 procedure g_Game_Restart();
3834 var
3835 Map: string;
3836 begin
3837 if g_Game_IsClient then
3838 Exit;
3839 map := g_ExtractFileName(gMapInfo.Map);
3840
3841 MessageTime := 0;
3842 gGameOn := False;
3843 g_Game_ClearLoading();
3844 g_Game_StartMap(Map, True);
3845 end;
3846
3847 function g_Game_StartMap(Map: String; Force: Boolean = False): Boolean;
3848 var
3849 NewWAD, ResName: String;
3850 I: Integer;
3851 begin
3852 g_Map_Free();
3853 g_Player_RemoveAllCorpses();
3854
3855 if (not g_Game_IsClient) and
3856 (gSwitchGameMode <> gGameSettings.GameMode) and
3857 (gGameSettings.GameMode <> GM_SINGLE) then
3858 begin
3859 if gSwitchGameMode = GM_CTF then
3860 gGameSettings.MaxLives := 0;
3861 gGameSettings.GameMode := gSwitchGameMode;
3862 Force := True;
3863 end else
3864 gSwitchGameMode := gGameSettings.GameMode;
3865
3866 g_Player_ResetTeams();
3867
3868 if Pos(':\', Map) > 0 then
3869 begin
3870 NewWAD := g_ExtractWadName(Map);
3871 ResName := g_ExtractFileName(Map);
3872 if g_Game_IsServer then
3873 begin
3874 gWADHash := MD5File(MapsDir + NewWAD);
3875 g_Game_LoadWAD(NewWAD);
3876 end else
3877 // hash recieved in MC_RECV_GameEvent -> NET_EV_MAPSTART
3878 g_Game_ClientWAD(NewWAD, gWADHash);
3879 end else
3880 ResName := Map;
3881
3882 Result := g_Map_Load(MapsDir + gGameSettings.WAD + ':\' + ResName);
3883 if Result then
3884 begin
3885 g_Player_ResetAll(Force or gLastMap, gGameSettings.GameType = GT_SINGLE);
3886
3887 gState := STATE_NONE;
3888 g_ActiveWindow := nil;
3889 gGameOn := True;
3890
3891 DisableCheats();
3892 ResetTimer();
3893
3894 if gGameSettings.GameMode = GM_CTF then
3895 begin
3896 g_Map_ResetFlag(FLAG_RED);
3897 g_Map_ResetFlag(FLAG_BLUE);
3898 // CTF, à ôëàãîâ íåò:
3899 if not g_Map_HaveFlagPoints() then
3900 g_SimpleError(_lc[I_GAME_ERROR_CTF]);
3901 end;
3902 end
3903 else
3904 begin
3905 gState := STATE_MENU;
3906 gGameOn := False;
3907 end;
3908
3909 gExit := 0;
3910 gPause := False;
3911 gTime := 0;
3912 NetTimeToUpdate := 1;
3913 NetTimeToReliable := 0;
3914 NetTimeToMaster := NetMasterRate;
3915 gLMSRespawn := LMS_RESPAWN_NONE;
3916 gLMSRespawnTime := 0;
3917 gMissionFailed := False;
3918 gNextMap := '';
3919
3920 gCoopMonstersKilled := 0;
3921 gCoopSecretsFound := 0;
3922
3923 gVoteInProgress := False;
3924 gVotePassed := False;
3925 gVoteCount := 0;
3926 gVoted := False;
3927
3928 gStatsOff := False;
3929
3930 if not gGameOn then Exit;
3931
3932 g_Game_SpectateCenterView();
3933
3934 if (gGameSettings.MaxLives > 0) and (gGameSettings.WarmupTime > 0) then
3935 begin
3936 gLMSRespawn := LMS_RESPAWN_WARMUP;
3937 gLMSRespawnTime := gTime + gGameSettings.WarmupTime*1000;
3938 gLMSSoftSpawn := True;
3939 if NetMode = NET_SERVER then
3940 MH_SEND_GameEvent(NET_EV_LMS_WARMUP, (gLMSRespawnTime - gTime) div 1000)
3941 else
3942 g_Console_Add(Format(_lc[I_MSG_WARMUP_START], [(gLMSRespawnTime - gTime) div 1000]), True);
3943 end;
3944
3945 if NetMode = NET_SERVER then
3946 begin
3947 MH_SEND_GameEvent(NET_EV_MAPSTART, gGameSettings.GameMode, Map);
3948
3949 // Ìàñòåðñåðâåð
3950 if NetUseMaster then
3951 begin
3952 if (NetMHost = nil) or (NetMPeer = nil) then
3953 if not g_Net_Slist_Connect then
3954 g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_SLIST_ERROR]);
3955
3956 g_Net_Slist_Update;
3957 end;
3958
3959 if NetClients <> nil then
3960 for I := 0 to High(NetClients) do
3961 if NetClients[I].Used then
3962 begin
3963 NetClients[I].Voted := False;
3964 if NetClients[I].RequestedFullUpdate then
3965 begin
3966 MH_SEND_Everything((NetClients[I].State = NET_STATE_AUTH), I);
3967 NetClients[I].RequestedFullUpdate := False;
3968 end;
3969 end;
3970
3971 g_Net_UnbanNonPermHosts();
3972 end;
3973
3974 if gLastMap then
3975 begin
3976 gCoopTotalMonstersKilled := 0;
3977 gCoopTotalSecretsFound := 0;
3978 gCoopTotalMonsters := 0;
3979 gCoopTotalSecrets := 0;
3980 gLastMap := False;
3981 end;
3982
3983 g_Game_ExecuteEvent('onmapstart');
3984 end;
3985
3986 procedure SetFirstLevel();
3987 begin
3988 gNextMap := '';
3989
3990 MapList := g_Map_GetMapsList(MapsDir + gGameSettings.WAD);
3991 if MapList = nil then
3992 Exit;
3993
3994 SortSArray(MapList);
3995 gNextMap := MapList[Low(MapList)];
3996
3997 MapList := nil;
3998 end;
3999
4000 procedure g_Game_ExitLevel(Map: Char16);
4001 begin
4002 gNextMap := Map;
4003
4004 gCoopTotalMonstersKilled := gCoopTotalMonstersKilled + gCoopMonstersKilled;
4005 gCoopTotalSecretsFound := gCoopTotalSecretsFound + gCoopSecretsFound;
4006 gCoopTotalMonsters := gCoopTotalMonsters + gTotalMonsters;
4007 gCoopTotalSecrets := gCoopTotalSecrets + gSecretsCount;
4008
4009 // Âûøëè â âûõîä â Îäèíî÷íîé èãðå:
4010 if gGameSettings.GameType = GT_SINGLE then
4011 gExit := EXIT_ENDLEVELSINGLE
4012 else // Âûøëè â âûõîä â Ñâîåé èãðå
4013 begin
4014 gExit := EXIT_ENDLEVELCUSTOM;
4015 if gGameSettings.GameMode = GM_COOP then
4016 g_Player_RememberAll;
4017
4018 if not g_Map_Exist(MapsDir + gGameSettings.WAD + ':\' + gNextMap) then
4019 begin
4020 gLastMap := True;
4021 if gGameSettings.GameMode = GM_COOP then
4022 gStatsOff := True;
4023
4024 gStatsPressed := True;
4025 gNextMap := 'MAP01';
4026
4027 if not g_Map_Exist(MapsDir + gGameSettings.WAD + ':\' + gNextMap) then
4028 g_Game_NextLevel;
4029
4030 if g_Game_IsNet then
4031 begin
4032 MH_SEND_GameStats();
4033 MH_SEND_CoopStats();
4034 end;
4035 end;
4036 end;
4037 end;
4038
4039 procedure g_Game_RestartLevel();
4040 var
4041 Map: string;
4042 begin
4043 if gGameSettings.GameMode = GM_SINGLE then
4044 begin
4045 g_Game_Restart();
4046 Exit;
4047 end;
4048 gExit := EXIT_ENDLEVELCUSTOM;
4049 Map := g_ExtractFileName(gMapInfo.Map);
4050 gNextMap := Map;
4051 end;
4052
4053 procedure g_Game_ClientWAD(NewWAD: String; WHash: TMD5Digest);
4054 var
4055 gWAD: String;
4056 begin
4057 if LowerCase(NewWAD) = LowerCase(gGameSettings.WAD) then
4058 Exit;
4059 if not g_Game_IsClient then
4060 Exit;
4061 gWAD := g_Res_SearchSameWAD(MapsDir, ExtractFileName(NewWAD), WHash);
4062 if gWAD = '' then
4063 begin
4064 g_Game_SetLoadingText(_lc[I_LOAD_DL_RES], 0, False);
4065 gWAD := g_Res_DownloadWAD(ExtractFileName(NewWAD));
4066 if gWAD = '' then
4067 begin
4068 g_Game_Free();
4069 g_FatalError(Format(_lc[I_GAME_ERROR_MAP_WAD], [ExtractFileName(NewWAD)]));
4070 Exit;
4071 end;
4072 end;
4073 NewWAD := ExtractRelativePath(MapsDir, gWAD);
4074 g_Game_LoadWAD(NewWAD);
4075 end;
4076
4077 procedure g_Game_RestartRound(NoMapRestart: Boolean = False);
4078 var
4079 i, n, nb, nr: Integer;
4080 begin
4081 if not g_Game_IsServer then Exit;
4082 if gLMSRespawn = LMS_RESPAWN_NONE then Exit;
4083 gLMSRespawn := LMS_RESPAWN_NONE;
4084 gLMSRespawnTime := 0;
4085 MessageTime := 0;
4086
4087 if (gGameSettings.GameMode = GM_COOP) and not NoMapRestart then
4088 begin
4089 gMissionFailed := True;
4090 g_Game_RestartLevel;
4091 Exit;
4092 end;
4093
4094 n := 0; nb := 0; nr := 0;
4095 for i := Low(gPlayers) to High(gPlayers) do
4096 if (gPlayers[i] <> nil) and
4097 ((not gPlayers[i].FSpectator) or gPlayers[i].FWantsInGame or
4098 (gPlayers[i] is TBot)) then
4099 begin
4100 Inc(n);
4101 if gPlayers[i].Team = TEAM_RED then Inc(nr)
4102 else if gPlayers[i].Team = TEAM_BLUE then Inc(nb)
4103 end;
4104
4105 if (n < 2) or ((gGameSettings.GameMode = GM_TDM) and ((nr = 0) or (nb = 0))) then
4106 begin
4107 // wait a second until the fuckers finally decide to join
4108 gLMSRespawn := LMS_RESPAWN_WARMUP;
4109 gLMSRespawnTime := gTime + 1000;
4110 gLMSSoftSpawn := NoMapRestart;
4111 Exit;
4112 end;
4113
4114 g_Player_RemoveAllCorpses;
4115 g_Game_Message(_lc[I_MESSAGE_LMS_START], 144);
4116 if g_Game_IsNet then
4117 MH_SEND_GameEvent(NET_EV_LMS_START);
4118
4119 for i := Low(gPlayers) to High(gPlayers) do
4120 begin
4121 if gPlayers[i] = nil then continue;
4122 if gPlayers[i] is TBot then gPlayers[i].FWantsInGame := True;
4123 // don't touch normal spectators
4124 if gPlayers[i].FSpectator and not gPlayers[i].FWantsInGame then
4125 begin
4126 gPlayers[i].FNoRespawn := True;
4127 gPlayers[i].Lives := 0;
4128 if g_Game_IsNet then
4129 MH_SEND_PlayerStats(gPlayers[I].UID);
4130 continue;
4131 end;
4132 gPlayers[i].FNoRespawn := False;
4133 gPlayers[i].Lives := gGameSettings.MaxLives;
4134 gPlayers[i].Respawn(False, True);
4135 if gGameSettings.GameMode = GM_COOP then
4136 begin
4137 gPlayers[i].Frags := 0;
4138 gPlayers[i].RecallState;
4139 end;
4140 if (gPlayer1 = nil) and (gLMSPID1 > 0) then
4141 gPlayer1 := g_Player_Get(gLMSPID1);
4142 if (gPlayer2 = nil) and (gLMSPID2 > 0) then
4143 gPlayer2 := g_Player_Get(gLMSPID2);
4144 end;
4145
4146 for i := Low(gItems) to High(gItems) do
4147 begin
4148 if gItems[i].Respawnable then
4149 begin
4150 gItems[i].QuietRespawn := True;
4151 gItems[i].RespawnTime := 0;
4152 end
4153 else
4154 begin
4155 g_Items_Remove(i);
4156 if g_Game_IsNet then MH_SEND_ItemDestroy(True, i);
4157 end;
4158 end;
4159
4160 for i := Low(gMonsters) to High(gMonsters) do
4161 begin
4162 if (gMonsters[i] <> nil) and not gMonsters[i].FNoRespawn then
4163 gMonsters[i].Respawn;
4164 end;
4165
4166 gLMSSoftSpawn := False;
4167 end;
4168
4169 function g_Game_GetFirstMap(WAD: String): String;
4170 begin
4171 Result := '';
4172
4173 MapList := g_Map_GetMapsList(WAD);
4174 if MapList = nil then
4175 Exit;
4176
4177 SortSArray(MapList);
4178 Result := MapList[Low(MapList)];
4179
4180 if not g_Map_Exist(WAD + ':\' + Result) then
4181 Result := '';
4182
4183 MapList := nil;
4184 end;
4185
4186 function g_Game_GetNextMap(): String;
4187 var
4188 I: Integer;
4189 Map: string;
4190 begin
4191 Result := '';
4192
4193 MapList := g_Map_GetMapsList(MapsDir + gGameSettings.WAD);
4194 if MapList = nil then
4195 Exit;
4196
4197 Map := g_ExtractFileName(gMapInfo.Map);
4198
4199 SortSArray(MapList);
4200 MapIndex := -255;
4201 for I := Low(MapList) to High(MapList) do
4202 if Map = MapList[I] then
4203 begin
4204 MapIndex := I;
4205 Break;
4206 end;
4207
4208 if MapIndex <> -255 then
4209 begin
4210 if MapIndex = High(MapList) then
4211 Result := MapList[Low(MapList)]
4212 else
4213 Result := MapList[MapIndex + 1];
4214
4215 if not g_Map_Exist(MapsDir + gGameSettings.WAD + ':\' + Result) then Result := Map;
4216 end;
4217
4218 MapList := nil;
4219 end;
4220
4221 procedure g_Game_NextLevel();
4222 begin
4223 if gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF, GM_COOP] then
4224 gExit := EXIT_ENDLEVELCUSTOM
4225 else
4226 begin
4227 gExit := EXIT_ENDLEVELSINGLE;
4228 Exit;
4229 end;
4230
4231 if gNextMap <> '' then Exit;
4232 gNextMap := g_Game_GetNextMap();
4233 end;
4234
4235 function g_Game_IsTestMap(): Boolean;
4236 begin
4237 result := StrEquCI1251(TEST_MAP_NAME, g_ExtractFileName(gMapInfo.Map));
4238 end;
4239
4240 procedure g_Game_DeleteTestMap();
4241 var
4242 a: Integer;
4243 MapName: Char16;
4244 WadName: string;
4245 {
4246 WAD: TWADFile;
4247 MapList: SArray;
4248 time: Integer;
4249 }
4250 begin
4251 a := Pos('.wad:\', gMapToDelete);
4252 if a = 0 then
4253 Exit;
4254
4255 // Âûäåëÿåì èìÿ wad-ôàéëà è èìÿ êàðòû:
4256 WadName := Copy(gMapToDelete, 1, a + 3);
4257 Delete(gMapToDelete, 1, a + 5);
4258 gMapToDelete := UpperCase(gMapToDelete);
4259 MapName := '';
4260 CopyMemory(@MapName[0], @gMapToDelete[1], Min(16, Length(gMapToDelete)));
4261
4262 {
4263 // Èìÿ êàðòû íå ñòàíäàðòíîå òåñòîâîå:
4264 if MapName <> TEST_MAP_NAME then
4265 Exit;
4266
4267 if not gTempDelete then
4268 begin
4269 time := g_GetFileTime(WadName);
4270 WAD := TWADFile.Create();
4271
4272 // ×èòàåì Wad-ôàéë:
4273 if not WAD.ReadFile(WadName) then
4274 begin // Íåò òàêîãî WAD-ôàéëà
4275 WAD.Free();
4276 Exit;
4277 end;
4278
4279 // Ñîñòàâëÿåì ñïèñîê êàðò è èùåì íóæíóþ:
4280 WAD.CreateImage();
4281 MapList := WAD.GetResourcesList('');
4282
4283 if MapList <> nil then
4284 for a := 0 to High(MapList) do
4285 if MapList[a] = MapName then
4286 begin
4287 // Óäàëÿåì è ñîõðàíÿåì:
4288 WAD.RemoveResource('', MapName);
4289 WAD.SaveTo(WadName);
4290 Break;
4291 end;
4292
4293 WAD.Free();
4294 g_SetFileTime(WadName, time);
4295 end else
4296 }
4297 if gTempDelete then DeleteFile(WadName);
4298 end;
4299
4300 procedure GameCVars(P: SArray);
4301 var
4302 a, b: Integer;
4303 stat: TPlayerStatArray;
4304 cmd, s: string;
4305 config: TConfig;
4306 begin
4307 stat := nil;
4308 cmd := LowerCase(P[0]);
4309 if cmd = 'r_showfps' then
4310 begin
4311 if (Length(P) > 1) and
4312 ((P[1] = '1') or (P[1] = '0')) then
4313 gShowFPS := (P[1][1] = '1');
4314
4315 if gShowFPS then
4316 g_Console_Add(_lc[I_MSG_SHOW_FPS_ON])
4317 else
4318 g_Console_Add(_lc[I_MSG_SHOW_FPS_OFF]);
4319 end
4320 else if (cmd = 'g_friendlyfire') and not g_Game_IsClient then
4321 begin
4322 with gGameSettings do
4323 begin
4324 if (Length(P) > 1) and
4325 ((P[1] = '1') or (P[1] = '0')) then
4326 begin
4327 if (P[1][1] = '1') then
4328 Options := Options or GAME_OPTION_TEAMDAMAGE
4329 else
4330 Options := Options and (not GAME_OPTION_TEAMDAMAGE);
4331 end;
4332
4333 if (LongBool(Options and GAME_OPTION_TEAMDAMAGE)) then
4334 g_Console_Add(_lc[I_MSG_FRIENDLY_FIRE_ON])
4335 else
4336 g_Console_Add(_lc[I_MSG_FRIENDLY_FIRE_OFF]);
4337
4338 if g_Game_IsNet then MH_SEND_GameSettings;
4339 end;
4340 end
4341 else if (cmd = 'g_weaponstay') and not g_Game_IsClient then
4342 begin
4343 with gGameSettings do
4344 begin
4345 if (Length(P) > 1) and
4346 ((P[1] = '1') or (P[1] = '0')) then
4347 begin
4348 if (P[1][1] = '1') then
4349 Options := Options or GAME_OPTION_WEAPONSTAY
4350 else
4351 Options := Options and (not GAME_OPTION_WEAPONSTAY);
4352 end;
4353
4354 if (LongBool(Options and GAME_OPTION_WEAPONSTAY)) then
4355 g_Console_Add(_lc[I_MSG_WEAPONSTAY_ON])
4356 else
4357 g_Console_Add(_lc[I_MSG_WEAPONSTAY_OFF]);
4358
4359 if g_Game_IsNet then MH_SEND_GameSettings;
4360 end;
4361 end
4362 else if cmd = 'g_gamemode' then
4363 begin
4364 a := g_Game_TextToMode(P[1]);
4365 if a = GM_SINGLE then a := GM_COOP;
4366 if (Length(P) > 1) and (a <> GM_NONE) and (not g_Game_IsClient) then
4367 begin
4368 gSwitchGameMode := a;
4369 if (gGameOn and (gGameSettings.GameMode = GM_SINGLE)) or
4370 (gState = STATE_INTERSINGLE) then
4371 gSwitchGameMode := GM_SINGLE;
4372 if not gGameOn then
4373 gGameSettings.GameMode := gSwitchGameMode;
4374 end;
4375 if gSwitchGameMode = gGameSettings.GameMode then
4376 g_Console_Add(Format(_lc[I_MSG_GAMEMODE_CURRENT],
4377 [g_Game_ModeToText(gGameSettings.GameMode)]))
4378 else
4379 g_Console_Add(Format(_lc[I_MSG_GAMEMODE_CHANGE],
4380 [g_Game_ModeToText(gGameSettings.GameMode),
4381 g_Game_ModeToText(gSwitchGameMode)]));
4382 end
4383 else if (cmd = 'g_allow_exit') and not g_Game_IsClient then
4384 begin
4385 with gGameSettings do
4386 begin
4387 if (Length(P) > 1) and
4388 ((P[1] = '1') or (P[1] = '0')) then
4389 begin
4390 if (P[1][1] = '1') then
4391 Options := Options or GAME_OPTION_ALLOWEXIT
4392 else
4393 Options := Options and (not GAME_OPTION_ALLOWEXIT);
4394 end;
4395
4396 if (LongBool(Options and GAME_OPTION_ALLOWEXIT)) then
4397 g_Console_Add(_lc[I_MSG_ALLOWEXIT_ON])
4398 else
4399 g_Console_Add(_lc[I_MSG_ALLOWEXIT_OFF]);
4400 g_Console_Add(_lc[I_MSG_ONMAPCHANGE]);
4401
4402 if g_Game_IsNet then MH_SEND_GameSettings;
4403 end;
4404 end
4405 else if (cmd = 'g_allow_monsters') and not g_Game_IsClient then
4406 begin
4407 with gGameSettings do
4408 begin
4409 if (Length(P) > 1) and
4410 ((P[1] = '1') or (P[1] = '0')) then
4411 begin
4412 if (P[1][1] = '1') then
4413 Options := Options or GAME_OPTION_MONSTERS
4414 else
4415 Options := Options and (not GAME_OPTION_MONSTERS);
4416 end;
4417
4418 if (LongBool(Options and GAME_OPTION_MONSTERS)) then
4419 g_Console_Add(_lc[I_MSG_ALLOWMON_ON])
4420 else
4421 g_Console_Add(_lc[I_MSG_ALLOWMON_OFF]);
4422 g_Console_Add(_lc[I_MSG_ONMAPCHANGE]);
4423
4424 if g_Game_IsNet then MH_SEND_GameSettings;
4425 end;
4426 end
4427 else if (cmd = 'g_bot_vsplayers') and not g_Game_IsClient then
4428 begin
4429 with gGameSettings do
4430 begin
4431 if (Length(P) > 1) and
4432 ((P[1] = '1') or (P[1] = '0')) then
4433 begin
4434 if (P[1][1] = '1') then
4435 Options := Options or GAME_OPTION_BOTVSPLAYER
4436 else
4437 Options := Options and (not GAME_OPTION_BOTVSPLAYER);
4438 end;
4439
4440 if (LongBool(Options and GAME_OPTION_BOTVSPLAYER)) then
4441 g_Console_Add(_lc[I_MSG_BOTSVSPLAYERS_ON])
4442 else
4443 g_Console_Add(_lc[I_MSG_BOTSVSPLAYERS_OFF]);
4444
4445 if g_Game_IsNet then MH_SEND_GameSettings;
4446 end;
4447 end
4448 else if (cmd = 'g_bot_vsmonsters') and not g_Game_IsClient then
4449 begin
4450 with gGameSettings do
4451 begin
4452 if (Length(P) > 1) and
4453 ((P[1] = '1') or (P[1] = '0')) then
4454 begin
4455 if (P[1][1] = '1') then
4456 Options := Options or GAME_OPTION_BOTVSMONSTER
4457 else
4458 Options := Options and (not GAME_OPTION_BOTVSMONSTER);
4459 end;
4460
4461 if (LongBool(Options and GAME_OPTION_BOTVSMONSTER)) then
4462 g_Console_Add(_lc[I_MSG_BOTSVSMONSTERS_ON])
4463 else
4464 g_Console_Add(_lc[I_MSG_BOTSVSMONSTERS_OFF]);
4465
4466 if g_Game_IsNet then MH_SEND_GameSettings;
4467 end;
4468 end
4469 else if (cmd = 'g_warmuptime') and not g_Game_IsClient then
4470 begin
4471 if Length(P) > 1 then
4472 begin
4473 if StrToIntDef(P[1], gGameSettings.WarmupTime) = 0 then
4474 gGameSettings.WarmupTime := 30
4475 else
4476 gGameSettings.WarmupTime := StrToIntDef(P[1], gGameSettings.WarmupTime);
4477 end;
4478
4479 g_Console_Add(Format(_lc[I_MSG_WARMUP],
4480 [gGameSettings.WarmupTime]));
4481 g_Console_Add(_lc[I_MSG_ONMAPCHANGE]);
4482 end
4483 else if cmd = 'net_interp' then
4484 begin
4485 if (Length(P) > 1) then
4486 NetInterpLevel := StrToIntDef(P[1], NetInterpLevel);
4487
4488 g_Console_Add('net_interp = ' + IntToStr(NetInterpLevel));
4489 config := TConfig.CreateFile(GameDir+'/'+CONFIG_FILENAME);
4490 config.WriteInt('Client', 'InterpolationSteps', NetInterpLevel);
4491 config.SaveFile(GameDir+'/'+CONFIG_FILENAME);
4492 config.Free();
4493 end
4494 else if cmd = 'net_forceplayerupdate' then
4495 begin
4496 if (Length(P) > 1) and
4497 ((P[1] = '1') or (P[1] = '0')) then
4498 NetForcePlayerUpdate := (P[1][1] = '1');
4499
4500 if NetForcePlayerUpdate then
4501 g_Console_Add('net_forceplayerupdate = 1')
4502 else
4503 g_Console_Add('net_forceplayerupdate = 0');
4504 config := TConfig.CreateFile(GameDir+'/'+CONFIG_FILENAME);
4505 config.WriteBool('Client', 'ForcePlayerUpdate', NetForcePlayerUpdate);
4506 config.SaveFile(GameDir+'/'+CONFIG_FILENAME);
4507 config.Free();
4508 end
4509 else if cmd = 'net_predictself' then
4510 begin
4511 if (Length(P) > 1) and
4512 ((P[1] = '1') or (P[1] = '0')) then
4513 NetPredictSelf := (P[1][1] = '1');
4514
4515 if NetPredictSelf then
4516 g_Console_Add('net_predictself = 1')
4517 else
4518 g_Console_Add('net_predictself = 0');
4519 config := TConfig.CreateFile(GameDir+'/'+CONFIG_FILENAME);
4520 config.WriteBool('Client', 'PredictSelf', NetPredictSelf);
4521 config.SaveFile(GameDir+'/'+CONFIG_FILENAME);
4522 config.Free();
4523 end
4524 else if cmd = 'sv_name' then
4525 begin
4526 if (Length(P) > 1) and (Length(P[1]) > 0) then
4527 begin
4528 NetServerName := P[1];
4529 if Length(NetServerName) > 64 then
4530 SetLength(NetServerName, 64);
4531 if g_Game_IsServer and g_Game_IsNet and NetUseMaster then
4532 g_Net_Slist_Update;
4533 end;
4534
4535 g_Console_Add(cmd + ' = "' + NetServerName + '"');
4536 end
4537 else if cmd = 'sv_passwd' then
4538 begin
4539 if (Length(P) > 1) and (Length(P[1]) > 0) then
4540 begin
4541 NetPassword := P[1];
4542 if Length(NetPassword) > 24 then
4543 SetLength(NetPassword, 24);
4544 if g_Game_IsServer and g_Game_IsNet and NetUseMaster then
4545 g_Net_Slist_Update;
4546 end;
4547
4548 g_Console_Add(cmd + ' = "' + AnsiLowerCase(NetPassword) + '"');
4549 end
4550 else if cmd = 'sv_maxplrs' then
4551 begin
4552 if (Length(P) > 1) then
4553 begin
4554 NetMaxClients := Min(Max(StrToIntDef(P[1], NetMaxClients), 1), NET_MAXCLIENTS);
4555 if g_Game_IsServer and g_Game_IsNet then
4556 begin
4557 b := 0;
4558 for a := 0 to High(NetClients) do
4559 if NetClients[a].Used then
4560 begin
4561 Inc(b);
4562 if b > NetMaxClients then
4563 begin
4564 s := g_Player_Get(NetClients[a].Player).Name;
4565 enet_peer_disconnect(NetClients[a].Peer, NET_DISC_FULL);
4566 g_Console_Add(Format(_lc[I_PLAYER_KICK], [s]));
4567 MH_SEND_GameEvent(NET_EV_PLAYER_KICK, 0, s);
4568 end;
4569 end;
4570 if NetUseMaster then
4571 g_Net_Slist_Update;
4572 end;
4573 end;
4574
4575 g_Console_Add(cmd + ' = ' + IntToStr(NetMaxClients));
4576 end
4577 else if cmd = 'sv_public' then
4578 begin
4579 if (Length(P) > 1) then
4580 begin
4581 NetUseMaster := StrToIntDef(P[1], Byte(NetUseMaster)) > 0;
4582 if g_Game_IsServer and g_Game_IsNet then
4583 if NetUseMaster then
4584 begin
4585 if NetMPeer = nil then
4586 if not g_Net_Slist_Connect() then
4587 g_Console_Add(_lc[I_NET_MSG_ERROR] + _lc[I_NET_SLIST_ERROR]);
4588 g_Net_Slist_Update();
4589 end
4590 else
4591 if NetMPeer <> nil then
4592 g_Net_Slist_Disconnect();
4593 end;
4594
4595 g_Console_Add(cmd + ' = ' + IntToStr(Byte(NetUseMaster)));
4596 end
4597 else if cmd = 'sv_intertime' then
4598 begin
4599 if (Length(P) > 1) then
4600 gDefInterTime := Min(Max(StrToIntDef(P[1], gDefInterTime), -1), 120);
4601
4602 g_Console_Add(cmd + ' = ' + IntToStr(gDefInterTime));
4603 end
4604 else if cmd = 'p1_name' then
4605 begin
4606 if (Length(P) > 1) and gGameOn then
4607 begin
4608 if g_Game_IsClient then
4609 begin
4610 gPlayer1Settings.Name := b_Text_Unformat(P[1]);
4611 MC_SEND_PlayerSettings;
4612 end
4613 else
4614 if gPlayer1 <> nil then
4615 begin
4616 gPlayer1.Name := b_Text_Unformat(P[1]);
4617 if g_Game_IsNet then MH_SEND_PlayerSettings(gPlayer1.UID);
4618 end
4619 else
4620 gPlayer1Settings.Name := b_Text_Unformat(P[1]);
4621 end;
4622 end
4623 else if cmd = 'p2_name' then
4624 begin
4625 if (Length(P) > 1) and gGameOn then
4626 begin
4627 if g_Game_IsClient then
4628 begin
4629 gPlayer2Settings.Name := b_Text_Unformat(P[1]);
4630 MC_SEND_PlayerSettings;
4631 end
4632 else
4633 if gPlayer2 <> nil then
4634 begin
4635 gPlayer2.Name := b_Text_Unformat(P[1]);
4636 if g_Game_IsNet then MH_SEND_PlayerSettings(gPlayer2.UID);
4637 end
4638 else
4639 gPlayer2Settings.Name := b_Text_Unformat(P[1]);
4640 end;
4641 end
4642 else if cmd = 'p1_color' then
4643 begin
4644 if Length(P) > 3 then
4645 if g_Game_IsClient then
4646 begin
4647 gPlayer1Settings.Color := _RGB(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4648 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4649 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4650 MC_SEND_PlayerSettings;
4651 end
4652 else
4653 if gPlayer1 <> nil then
4654 begin
4655 gPlayer1.Model.SetColor(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4656 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4657 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4658 if g_Game_IsNet then MH_SEND_PlayerSettings(gPlayer1.UID);
4659 end
4660 else
4661 gPlayer1Settings.Color := _RGB(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4662 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4663 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4664 end
4665 else if (cmd = 'p2_color') and not g_Game_IsNet then
4666 begin
4667 if Length(P) > 3 then
4668 if g_Game_IsClient then
4669 begin
4670 gPlayer2Settings.Color := _RGB(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4671 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4672 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4673 MC_SEND_PlayerSettings;
4674 end
4675 else
4676 if gPlayer2 <> nil then
4677 begin
4678 gPlayer2.Model.SetColor(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4679 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4680 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4681 if g_Game_IsNet then MH_SEND_PlayerSettings(gPlayer2.UID);
4682 end
4683 else
4684 gPlayer2Settings.Color := _RGB(EnsureRange(StrToIntDef(P[1], 0), 0, 255),
4685 EnsureRange(StrToIntDef(P[2], 0), 0, 255),
4686 EnsureRange(StrToIntDef(P[3], 0), 0, 255));
4687 end
4688 else if gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT] then
4689 begin
4690 if cmd = 'r_showtime' then
4691 begin
4692 if (Length(P) > 1) and
4693 ((P[1] = '1') or (P[1] = '0')) then
4694 gShowTime := (P[1][1] = '1');
4695
4696 if gShowTime then
4697 g_Console_Add(_lc[I_MSG_TIME_ON])
4698 else
4699 g_Console_Add(_lc[I_MSG_TIME_OFF]);
4700 end
4701 else if cmd = 'r_showscore' then
4702 begin
4703 if (Length(P) > 1) and
4704 ((P[1] = '1') or (P[1] = '0')) then
4705 gShowGoals := (P[1][1] = '1');
4706
4707 if gShowGoals then
4708 g_Console_Add(_lc[I_MSG_SCORE_ON])
4709 else
4710 g_Console_Add(_lc[I_MSG_SCORE_OFF]);
4711 end
4712 else if cmd = 'r_showstat' then
4713 begin
4714 if (Length(P) > 1) and
4715 ((P[1] = '1') or (P[1] = '0')) then
4716 gShowStat := (P[1][1] = '1');
4717
4718 if gShowStat then
4719 g_Console_Add(_lc[I_MSG_STATS_ON])
4720 else
4721 g_Console_Add(_lc[I_MSG_STATS_OFF]);
4722 end
4723 else if cmd = 'r_showkillmsg' then
4724 begin
4725 if (Length(P) > 1) and
4726 ((P[1] = '1') or (P[1] = '0')) then
4727 gShowKillMsg := (P[1][1] = '1');
4728
4729 if gShowKillMsg then
4730 g_Console_Add(_lc[I_MSG_KILL_MSGS_ON])
4731 else
4732 g_Console_Add(_lc[I_MSG_KILL_MSGS_OFF]);
4733 end
4734 else if cmd = 'r_showlives' then
4735 begin
4736 if (Length(P) > 1) and
4737 ((P[1] = '1') or (P[1] = '0')) then
4738 gShowLives := (P[1][1] = '1');
4739
4740 if gShowLives then
4741 g_Console_Add(_lc[I_MSG_LIVES_ON])
4742 else
4743 g_Console_Add(_lc[I_MSG_LIVES_OFF]);
4744 end
4745 else if cmd = 'r_showspect' then
4746 begin
4747 if (Length(P) > 1) and
4748 ((P[1] = '1') or (P[1] = '0')) then
4749 gSpectHUD := (P[1][1] = '1');
4750
4751 if gSpectHUD then
4752 g_Console_Add(_lc[I_MSG_SPECT_HUD_ON])
4753 else
4754 g_Console_Add(_lc[I_MSG_SPECT_HUD_OFF]);
4755 end
4756 else if cmd = 'r_showping' then
4757 begin
4758 if (Length(P) > 1) and
4759 ((P[1] = '1') or (P[1] = '0')) then
4760 gShowPing := (P[1][1] = '1');
4761
4762 if gShowPing then
4763 g_Console_Add(_lc[I_MSG_PING_ON])
4764 else
4765 g_Console_Add(_lc[I_MSG_PING_OFF]);
4766 end
4767 else if (cmd = 'g_scorelimit') and not g_Game_IsClient then
4768 begin
4769 if Length(P) > 1 then
4770 begin
4771 if StrToIntDef(P[1], gGameSettings.GoalLimit) = 0 then
4772 gGameSettings.GoalLimit := 0
4773 else
4774 begin
4775 b := 0;
4776
4777 if gGameSettings.GameMode = GM_DM then
4778 begin // DM
4779 stat := g_Player_GetStats();
4780 if stat <> nil then
4781 for a := 0 to High(stat) do
4782 if stat[a].Frags > b then
4783 b := stat[a].Frags;
4784 end
4785 else // TDM/CTF
4786 b := Max(gTeamStat[TEAM_RED].Goals, gTeamStat[TEAM_BLUE].Goals);
4787
4788 gGameSettings.GoalLimit := Max(StrToIntDef(P[1], gGameSettings.GoalLimit), b);
4789 end;
4790
4791 if g_Game_IsNet then MH_SEND_GameSettings;
4792 end;
4793
4794 g_Console_Add(Format(_lc[I_MSG_SCORE_LIMIT], [gGameSettings.GoalLimit]));
4795 end
4796 else if (cmd = 'g_timelimit') and not g_Game_IsClient then
4797 begin
4798 if (Length(P) > 1) and (StrToIntDef(P[1], -1) >= 0) then
4799 gGameSettings.TimeLimit := StrToIntDef(P[1], -1);
4800
4801 g_Console_Add(Format(_lc[I_MSG_TIME_LIMIT],
4802 [gGameSettings.TimeLimit div 3600,
4803 (gGameSettings.TimeLimit div 60) mod 60,
4804 gGameSettings.TimeLimit mod 60]));
4805 if g_Game_IsNet then MH_SEND_GameSettings;
4806 end
4807 else if (cmd = 'g_maxlives') and not g_Game_IsClient then
4808 begin
4809 if Length(P) > 1 then
4810 begin
4811 if StrToIntDef(P[1], gGameSettings.MaxLives) = 0 then
4812 gGameSettings.MaxLives := 0
4813 else
4814 begin
4815 b := 0;
4816 stat := g_Player_GetStats();
4817 if stat <> nil then
4818 for a := 0 to High(stat) do
4819 if stat[a].Lives > b then
4820 b := stat[a].Lives;
4821 gGameSettings.MaxLives :=
4822 Max(StrToIntDef(P[1], gGameSettings.MaxLives), b);
4823 end;
4824 end;
4825
4826 g_Console_Add(Format(_lc[I_MSG_LIVES],
4827 [gGameSettings.MaxLives]));
4828 if g_Game_IsNet then MH_SEND_GameSettings;
4829 end;
4830 end;
4831 end;
4832
4833 procedure DebugCommands(P: SArray);
4834 var
4835 a, b: Integer;
4836 cmd: string;
4837 //pt: TPoint;
4838 begin
4839 // Êîìàíäû îòëàäî÷íîãî ðåæèìà:
4840 if gDebugMode then
4841 begin
4842 cmd := LowerCase(P[0]);
4843 if cmd = 'd_window' then
4844 begin
4845 g_Console_Add(Format('gWinPosX = %d, gWinPosY %d', [gWinPosX, gWinPosY]));
4846 g_Console_Add(Format('gWinRealPosX = %d, gWinRealPosY %d', [gWinRealPosX, gWinRealPosY]));
4847 g_Console_Add(Format('gScreenWidth = %d, gScreenHeight = %d', [gScreenWidth, gScreenHeight]));
4848 g_Console_Add(Format('gWinSizeX = %d, gWinSizeY = %d', [gWinSizeX, gWinSizeY]));
4849 g_Console_Add(Format('Frame X = %d, Y = %d, Caption Y = %d', [gWinFrameX, gWinFrameY, gWinCaption]));
4850 end
4851 else if cmd = 'd_sounds' then
4852 begin
4853 if (Length(P) > 1) and
4854 ((P[1] = '1') or (P[1] = '0')) then
4855 g_Debug_Sounds := (P[1][1] = '1');
4856
4857 g_Console_Add(Format('d_sounds is %d', [Byte(g_Debug_Sounds)]));
4858 end
4859 else if cmd = 'd_frames' then
4860 begin
4861 if (Length(P) > 1) and
4862 ((P[1] = '1') or (P[1] = '0')) then
4863 g_Debug_Frames := (P[1][1] = '1');
4864
4865 g_Console_Add(Format('d_frames is %d', [Byte(g_Debug_Frames)]));
4866 end
4867 else if cmd = 'd_winmsg' then
4868 begin
4869 if (Length(P) > 1) and
4870 ((P[1] = '1') or (P[1] = '0')) then
4871 g_Debug_WinMsgs := (P[1][1] = '1');
4872
4873 g_Console_Add(Format('d_winmsg is %d', [Byte(g_Debug_WinMsgs)]));
4874 end
4875 else if (cmd = 'd_monoff') and not g_Game_IsNet then
4876 begin
4877 if (Length(P) > 1) and
4878 ((P[1] = '1') or (P[1] = '0')) then
4879 g_Debug_MonsterOff := (P[1][1] = '1');
4880
4881 g_Console_Add(Format('d_monoff is %d', [Byte(g_debug_MonsterOff)]));
4882 end
4883 else if (cmd = 'd_botoff') and not g_Game_IsNet then
4884 begin
4885 if Length(P) > 1 then
4886 case P[1][1] of
4887 '0': g_debug_BotAIOff := 0;
4888 '1': g_debug_BotAIOff := 1;
4889 '2': g_debug_BotAIOff := 2;
4890 '3': g_debug_BotAIOff := 3;
4891 end;
4892
4893 g_Console_Add(Format('d_botoff is %d', [g_debug_BotAIOff]));
4894 end
4895 else if cmd = 'd_monster' then
4896 begin
4897 if gGameOn and (gPlayer1 <> nil) and (gPlayer1.Live) and (not g_Game_IsNet) then
4898 if Length(P) < 2 then
4899 begin
4900 g_Console_Add(cmd + ' [ID | Name] [behaviour]');
4901 g_Console_Add('ID | Name');
4902 for b := MONSTER_DEMON to MONSTER_MAN do
4903 g_Console_Add(Format('%2d | %s', [b, g_Monsters_GetNameByID(b)]));
4904 end else
4905 begin
4906 a := StrToIntDef(P[1], 0);
4907 if (a < MONSTER_DEMON) or (a > MONSTER_MAN) then
4908 a := g_Monsters_GetIDByName(P[1]);
4909
4910 if (a < MONSTER_DEMON) or (a > MONSTER_MAN) then
4911 g_Console_Add(Format(_lc[I_MSG_NO_MONSTER], [P[1]]))
4912 else
4913 begin
4914 with gPlayer1.Obj do
4915 b := g_Monsters_Create(a,
4916 X + Rect.X + (Rect.Width div 2),
4917 Y + Rect.Y + Rect.Height,
4918 gPlayer1.Direction, True);
4919 if (Length(P) > 2) and (b >= 0) then
4920 gMonsters[b].MonsterBehaviour := Min(Max(StrToIntDef(P[2], BH_NORMAL), BH_NORMAL), BH_GOOD);
4921 end;
4922 end;
4923 end
4924 else if (cmd = 'd_health') then
4925 begin
4926 if (Length(P) > 1) and
4927 ((P[1] = '1') or (P[1] = '0')) then
4928 g_debug_HealthBar := (P[1][1] = '1');
4929
4930 g_Console_Add(Format('d_health is %d', [Byte(g_debug_HealthBar)]));
4931 end
4932 else if (cmd = 'd_player') then
4933 begin
4934 if (Length(P) > 1) and
4935 ((P[1] = '1') or (P[1] = '0')) then
4936 g_debug_Player := (P[1][1] = '1');
4937
4938 g_Console_Add(Format(cmd + ' is %d', [Byte(g_Debug_Player)]));
4939 end
4940 else if (cmd = 'd_joy') then
4941 begin
4942 for a := 1 to 8 do
4943 g_Console_Add(e_JoystickStateToString(a));
4944 end;
4945 end
4946 else
4947 g_Console_Add(_lc[I_MSG_NOT_DEBUG]);
4948 end;
4949
4950
4951 procedure GameCheats(P: SArray);
4952 var
4953 cmd: string;
4954 f, a: Integer;
4955 plr: TPlayer;
4956 begin
4957 if (not gGameOn) or (not gCheats) or ((gGameSettings.GameType <> GT_SINGLE) and
4958 (gGameSettings.GameMode <> GM_COOP) and (not gDebugMode)) or g_Game_IsNet then
4959 begin
4960 g_Console_Add('not available');
4961 exit;
4962 end;
4963 plr := gPlayer1;
4964 if plr = nil then
4965 begin
4966 g_Console_Add('where is the player?!');
4967 exit;
4968 end;
4969 cmd := LowerCase(P[0]);
4970 // god
4971 if cmd = 'god' then
4972 begin
4973 plr.GodMode := not plr.GodMode;
4974 if plr.GodMode then g_Console_Add('player is godlike now') else g_Console_Add('player is mortal now');
4975 exit;
4976 end;
4977 // give <health|exit|weapons|air|suit|jetpack|berserk|all>
4978 if cmd = 'give' then
4979 begin
4980 if length(P) < 2 then begin g_Console_Add('give what?!'); exit; end;
4981 for f := 1 to High(P) do
4982 begin
4983 cmd := LowerCase(P[f]);
4984 if cmd = 'health' then begin plr.RestoreHealthArmor(); g_Console_Add('player feels himself better'); continue; end;
4985 if (cmd = 'all') {or (cmd = 'weapons')} then begin plr.AllRulez(False); g_Console_Add('player got the gifts'); continue; end;
4986 if cmd = 'exit' then
4987 begin
4988 if gTriggers <> nil then
4989 begin
4990 for a := 0 to High(gTriggers) do
4991 begin
4992 if gTriggers[a].TriggerType = TRIGGER_EXIT then
4993 begin
4994 g_Console_Add('player left the map');
4995 gExitByTrigger := True;
4996 g_Game_ExitLevel(gTriggers[a].Data.MapName);
4997 break;
4998 end;
4999 end;
5000 end;
5001 continue;
5002 end;
5003
5004 if cmd = 'air' then begin plr.GiveItem(ITEM_OXYGEN); g_Console_Add('player got some air'); continue; end;
5005 if cmd = 'jetpack' then begin plr.GiveItem(ITEM_JETPACK); g_Console_Add('player got a jetpack'); continue; end;
5006 if cmd = 'suit' then begin plr.GiveItem(ITEM_SUIT); g_Console_Add('player got an envirosuit'); continue; end;
5007 if cmd = 'berserk' then begin plr.GiveItem(ITEM_MEDKIT_BLACK); g_Console_Add('player got a berserk pack'); continue; end;
5008 if cmd = 'backpack' then begin plr.GiveItem(ITEM_AMMO_BACKPACK); g_Console_Add('player got a backpack'); continue; end;
5009
5010 if cmd = 'helmet' then begin plr.GiveItem(ITEM_HELMET); g_Console_Add('player got a helmet'); continue; end;
5011 if cmd = 'bottle' then begin plr.GiveItem(ITEM_BOTTLE); g_Console_Add('player got a bottle of health'); continue; end;
5012
5013 if cmd = 'stimpack' then begin plr.GiveItem(ITEM_MEDKIT_SMALL); g_Console_Add('player got a stimpack'); continue; end;
5014 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;
5015
5016 if cmd = 'greenarmor' then begin plr.GiveItem(ITEM_ARMOR_GREEN); g_Console_Add('player got a security armor'); continue; end;
5017 if cmd = 'bluearmor' then begin plr.GiveItem(ITEM_ARMOR_BLUE); g_Console_Add('player got a combat armor'); continue; end;
5018
5019 if (cmd = 'megasphere') or (cmd = 'mega') then begin plr.GiveItem(ITEM_SPHERE_BLUE); g_Console_Add('player got a megasphere'); continue; end;
5020 if (cmd = 'soulsphere') or (cmd = 'soul')then begin plr.GiveItem(ITEM_SPHERE_WHITE); g_Console_Add('player got a soul sphere'); continue; end;
5021
5022 if (cmd = 'invul') or (cmd = 'invulnerability') then begin plr.GiveItem(ITEM_INVUL); g_Console_Add('player got invulnerability'); continue; end;
5023 if (cmd = 'invis') or (cmd = 'invisibility') then begin plr.GiveItem(ITEM_INVIS); g_Console_Add('player got invisibility'); continue; end;
5024
5025 if cmd = 'redkey' then begin plr.GiveItem(ITEM_KEY_RED); g_Console_Add('player got the red key'); continue; end;
5026 if cmd = 'greenkey' then begin plr.GiveItem(ITEM_KEY_GREEN); g_Console_Add('player got the green key'); continue; end;
5027 if cmd = 'bluekey' then begin plr.GiveItem(ITEM_KEY_BLUE); g_Console_Add('player got the blue key'); continue; end;
5028
5029 if (cmd = 'shotgun') or (cmd = 'sg') then begin plr.GiveItem(ITEM_WEAPON_SHOTGUN1); g_Console_Add('player got a shotgun'); continue; end;
5030 if (cmd = 'supershotgun') or (cmd = 'ssg') then begin plr.GiveItem(ITEM_WEAPON_SHOTGUN2); g_Console_Add('player got a supershotgun'); continue; end;
5031 if cmd = 'chaingun' then begin plr.GiveItem(ITEM_WEAPON_CHAINGUN); g_Console_Add('player got a chaingun'); continue; end;
5032 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;
5033 if cmd = 'plasmagun' then begin plr.GiveItem(ITEM_WEAPON_PLASMA); g_Console_Add('player got a plasma gun'); continue; end;
5034 if cmd = 'bfg' then begin plr.GiveItem(ITEM_WEAPON_BFG); g_Console_Add('player got a BFG-9000'); continue; end;
5035
5036 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;
5037 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;
5038 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;
5039 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;
5040 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;
5041 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;
5042
5043 if cmd = 'superchaingun' then begin plr.GiveItem(ITEM_WEAPON_SUPERPULEMET); g_Console_Add('player got a superchaingun'); continue; end;
5044 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;
5045
5046 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;
5047 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;
5048
5049 if cmd = 'chainsaw' then begin plr.GiveItem(ITEM_WEAPON_SAW); g_Console_Add('player got a chainsaw'); continue; end;
5050
5051 if cmd = 'ammo' then
5052 begin
5053 plr.GiveItem(ITEM_AMMO_SHELLS_BOX);
5054 plr.GiveItem(ITEM_AMMO_BULLETS_BOX);
5055 plr.GiveItem(ITEM_AMMO_CELL_BIG);
5056 plr.GiveItem(ITEM_AMMO_ROCKET_BOX);
5057 plr.GiveItem(ITEM_AMMO_FUELCAN);
5058 g_Console_Add('player got some ammo');
5059 continue;
5060 end;
5061
5062 if cmd = 'clip' then begin plr.GiveItem(ITEM_AMMO_BULLETS); g_Console_Add('player got some bullets'); continue; end;
5063 if cmd = 'bullets' then begin plr.GiveItem(ITEM_AMMO_BULLETS_BOX); g_Console_Add('player got a box of bullets'); continue; end;
5064
5065 if cmd = 'shells' then begin plr.GiveItem(ITEM_AMMO_SHELLS); g_Console_Add('player got some shells'); continue; end;
5066 if cmd = 'shellbox' then begin plr.GiveItem(ITEM_AMMO_SHELLS_BOX); g_Console_Add('player got a box of shells'); continue; end;
5067
5068 if cmd = 'cells' then begin plr.GiveItem(ITEM_AMMO_CELL); g_Console_Add('player got some cells'); continue; end;
5069 if cmd = 'battery' then begin plr.GiveItem(ITEM_AMMO_CELL_BIG); g_Console_Add('player got cell battery'); continue; end;
5070
5071 if cmd = 'rocket' then begin plr.GiveItem(ITEM_AMMO_ROCKET); g_Console_Add('player got a rocket'); continue; end;
5072 if cmd = 'rocketbox' then begin plr.GiveItem(ITEM_AMMO_ROCKET_BOX); g_Console_Add('player got some rockets'); continue; end;
5073
5074 if (cmd = 'fuel') or (cmd = 'fuelcan') then begin plr.GiveItem(ITEM_AMMO_FUELCAN); g_Console_Add('player got fuel canister'); continue; end;
5075
5076 if cmd = 'weapons' then
5077 begin
5078 plr.GiveItem(ITEM_WEAPON_SHOTGUN1);
5079 plr.GiveItem(ITEM_WEAPON_SHOTGUN2);
5080 plr.GiveItem(ITEM_WEAPON_CHAINGUN);
5081 plr.GiveItem(ITEM_WEAPON_ROCKETLAUNCHER);
5082 plr.GiveItem(ITEM_WEAPON_PLASMA);
5083 plr.GiveItem(ITEM_WEAPON_BFG);
5084 g_Console_Add('player got weapons');
5085 continue;
5086 end;
5087
5088 if cmd = 'keys' then
5089 begin
5090 plr.GiveItem(ITEM_KEY_RED);
5091 plr.GiveItem(ITEM_KEY_GREEN);
5092 plr.GiveItem(ITEM_KEY_BLUE);
5093 g_Console_Add('player got all keys');
5094 continue;
5095 end;
5096
5097 g_Console_Add('i don''t know how to give '''+cmd+'''!');
5098 end;
5099 exit;
5100 end;
5101 // open
5102 if cmd = 'open' then
5103 begin
5104 g_Console_Add('player activated sesame');
5105 g_Triggers_OpenAll();
5106 exit;
5107 end;
5108 // fly
5109 if cmd = 'fly' then
5110 begin
5111 gFly := not gFly;
5112 if gFly then g_Console_Add('player feels himself lighter') else g_Console_Add('player lost his wings');
5113 exit;
5114 end;
5115 // noclip
5116 if cmd = 'noclip' then
5117 begin
5118 plr.SwitchNoClip;
5119 g_Console_Add('wall hardeness adjusted');
5120 exit;
5121 end;
5122 // notarget
5123 if cmd = 'notarget' then
5124 begin
5125 plr.NoTarget := not plr.NoTarget;
5126 if plr.NoTarget then g_Console_Add('player hides in shadows') else g_Console_Add('player is brave again');
5127 exit;
5128 end;
5129 // noreload
5130 if cmd = 'noreload' then
5131 begin
5132 plr.NoReload := not plr.NoReload;
5133 if plr.NoReload then g_Console_Add('player is action hero now') else g_Console_Add('player is ordinary man now');
5134 exit;
5135 end;
5136 // speedy
5137 if cmd = 'speedy' then
5138 begin
5139 MAX_RUNVEL := 32-MAX_RUNVEL;
5140 g_Console_Add('speed adjusted');
5141 exit;
5142 end;
5143 // jumpy
5144 if cmd = 'jumpy' then
5145 begin
5146 VEL_JUMP := 30-VEL_JUMP;
5147 g_Console_Add('jump height adjusted');
5148 exit;
5149 end;
5150 // automap
5151 if cmd = 'automap' then
5152 begin
5153 gShowMap := not gShowMap;
5154 if gShowMap then g_Console_Add('player gains second sight') else g_Console_Add('player lost second sight');
5155 exit;
5156 end;
5157 // aimline
5158 if cmd = 'aimline' then
5159 begin
5160 gAimLine := not gAimLine;
5161 if gAimLine then g_Console_Add('player gains laser sight') else g_Console_Add('player lost laser sight');
5162 exit;
5163 end;
5164 end;
5165
5166 procedure GameCommands(P: SArray);
5167 var
5168 a, b: Integer;
5169 s, pw: String;
5170 chstr: string;
5171 cmd: string;
5172 pl: pTNetClient = nil;
5173 plr: TPlayer;
5174 prt: Word;
5175 nm: Boolean;
5176 listen: LongWord;
5177 begin
5178 // Îáùèå êîìàíäû:
5179 cmd := LowerCase(P[0]);
5180 chstr := '';
5181 if (cmd = 'quit') or
5182 (cmd = 'exit') then
5183 begin
5184 g_Game_Free();
5185 g_Game_Quit();
5186 Exit;
5187 end
5188 else if cmd = 'pause' then
5189 begin
5190 if (g_ActiveWindow = nil) then
5191 g_Game_Pause(not gPause);
5192 end
5193 else if cmd = 'endgame' then
5194 gExit := EXIT_SIMPLE
5195 else if cmd = 'restart' then
5196 begin
5197 if gGameOn or (gState in [STATE_INTERSINGLE, STATE_INTERCUSTOM]) then
5198 begin
5199 if g_Game_IsClient then
5200 begin
5201 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5202 Exit;
5203 end;
5204 g_Game_Restart();
5205 end else
5206 g_Console_Add(_lc[I_MSG_NOT_GAME]);
5207 end
5208 else if cmd = 'kick' then
5209 begin
5210 if g_Game_IsServer then
5211 begin
5212 if Length(P) < 2 then
5213 begin
5214 g_Console_Add('kick <name>');
5215 Exit;
5216 end;
5217 if P[1] = '' then
5218 begin
5219 g_Console_Add('kick <name>');
5220 Exit;
5221 end;
5222
5223 if g_Game_IsNet then
5224 pl := g_Net_Client_ByName(P[1]);
5225 if (pl <> nil) then
5226 begin
5227 s := g_Net_ClientName_ByID(pl^.ID);
5228 enet_peer_disconnect(pl^.Peer, NET_DISC_KICK);
5229 g_Console_Add(Format(_lc[I_PLAYER_KICK], [s]));
5230 MH_SEND_GameEvent(NET_EV_PLAYER_KICK, 0, s);
5231 if NetUseMaster then
5232 g_Net_Slist_Update;
5233 end else if gPlayers <> nil then
5234 for a := Low(gPlayers) to High(gPlayers) do
5235 if gPlayers[a] <> nil then
5236 if Copy(LowerCase(gPlayers[a].Name), 1, Length(P[1])) = LowerCase(P[1]) then
5237 begin
5238 // Íå îòêëþ÷àòü îñíîâíûõ èãðîêîâ â ñèíãëå
5239 if not(gPlayers[a] is TBot) and (gGameSettings.GameType = GT_SINGLE) then
5240 continue;
5241 gPlayers[a].Lives := 0;
5242 gPlayers[a].Kill(K_SIMPLEKILL, 0, HIT_DISCON);
5243 g_Console_Add(Format(_lc[I_PLAYER_LEAVE], [gPlayers[a].Name]), True);
5244 g_Player_Remove(gPlayers[a].UID);
5245 if NetUseMaster then
5246 g_Net_Slist_Update;
5247 // Åñëè íå ïåðåìåøàòü, ïðè äîáàâëåíèè íîâûõ áîòîâ ïîÿâÿòñÿ ñòàðûå
5248 g_Bot_MixNames();
5249 end;
5250 end else
5251 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5252 end
5253 else if cmd = 'kick_id' then
5254 begin
5255 if g_Game_IsServer and g_Game_IsNet then
5256 begin
5257 if Length(P) < 2 then
5258 begin
5259 g_Console_Add('kick_id <client ID>');
5260 Exit;
5261 end;
5262 if P[1] = '' then
5263 begin
5264 g_Console_Add('kick_id <client ID>');
5265 Exit;
5266 end;
5267
5268 a := StrToIntDef(P[1], 0);
5269 if (NetClients <> nil) and (a <= High(NetClients)) then
5270 begin
5271 if NetClients[a].Used and (NetClients[a].Peer <> nil) then
5272 begin
5273 s := g_Net_ClientName_ByID(NetClients[a].ID);
5274 enet_peer_disconnect(NetClients[a].Peer, NET_DISC_KICK);
5275 g_Console_Add(Format(_lc[I_PLAYER_KICK], [s]));
5276 MH_SEND_GameEvent(NET_EV_PLAYER_KICK, 0, s);
5277 if NetUseMaster then
5278 g_Net_Slist_Update;
5279 end;
5280 end;
5281 end else
5282 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5283 end
5284 else if cmd = 'ban' then
5285 begin
5286 if g_Game_IsServer and g_Game_IsNet then
5287 begin
5288 if Length(P) < 2 then
5289 begin
5290 g_Console_Add('ban <name>');
5291 Exit;
5292 end;
5293 if P[1] = '' then
5294 begin
5295 g_Console_Add('ban <name>');
5296 Exit;
5297 end;
5298
5299 pl := g_Net_Client_ByName(P[1]);
5300 if (pl <> nil) then
5301 begin
5302 s := g_Net_ClientName_ByID(pl^.ID);
5303 g_Net_BanHost(pl^.Peer^.address.host, False);
5304 enet_peer_disconnect(pl^.Peer, NET_DISC_TEMPBAN);
5305 g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
5306 MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
5307 if NetUseMaster then
5308 g_Net_Slist_Update;
5309 end else
5310 g_Console_Add(Format(_lc[I_NET_ERR_NAME404], [P[1]]));
5311 end else
5312 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5313 end
5314 else if cmd = 'ban_id' then
5315 begin
5316 if g_Game_IsServer and g_Game_IsNet then
5317 begin
5318 if Length(P) < 2 then
5319 begin
5320 g_Console_Add('ban_id <client ID>');
5321 Exit;
5322 end;
5323 if P[1] = '' then
5324 begin
5325 g_Console_Add('ban_id <client ID>');
5326 Exit;
5327 end;
5328
5329 a := StrToIntDef(P[1], 0);
5330 if (NetClients <> nil) and (a <= High(NetClients)) then
5331 if NetClients[a].Used and (NetClients[a].Peer <> nil) then
5332 begin
5333 s := g_Net_ClientName_ByID(NetClients[a].ID);
5334 g_Net_BanHost(NetClients[a].Peer^.address.host, False);
5335 enet_peer_disconnect(NetClients[a].Peer, NET_DISC_TEMPBAN);
5336 g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
5337 MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
5338 if NetUseMaster then
5339 g_Net_Slist_Update;
5340 end;
5341 end else
5342 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5343 end
5344 else if cmd = 'permban' then
5345 begin
5346 if g_Game_IsServer and g_Game_IsNet then
5347 begin
5348 if Length(P) < 2 then
5349 begin
5350 g_Console_Add('permban <name>');
5351 Exit;
5352 end;
5353 if P[1] = '' then
5354 begin
5355 g_Console_Add('permban <name>');
5356 Exit;
5357 end;
5358
5359 pl := g_Net_Client_ByName(P[1]);
5360 if (pl <> nil) then
5361 begin
5362 s := g_Net_ClientName_ByID(pl^.ID);
5363 g_Net_BanHost(pl^.Peer^.address.host);
5364 enet_peer_disconnect(pl^.Peer, NET_DISC_BAN);
5365 g_Net_SaveBanList();
5366 g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
5367 MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
5368 if NetUseMaster then
5369 g_Net_Slist_Update;
5370 end else
5371 g_Console_Add(Format(_lc[I_NET_ERR_NAME404], [P[1]]));
5372 end else
5373 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5374 end
5375 else if cmd = 'permban_id' then
5376 begin
5377 if g_Game_IsServer and g_Game_IsNet then
5378 begin
5379 if Length(P) < 2 then
5380 begin
5381 g_Console_Add('permban_id <client ID>');
5382 Exit;
5383 end;
5384 if P[1] = '' then
5385 begin
5386 g_Console_Add('permban_id <client ID>');
5387 Exit;
5388 end;
5389
5390 a := StrToIntDef(P[1], 0);
5391 if (NetClients <> nil) and (a <= High(NetClients)) then
5392 if NetClients[a].Used and (NetClients[a].Peer <> nil) then
5393 begin
5394 s := g_Net_ClientName_ByID(NetClients[a].ID);
5395 g_Net_BanHost(NetClients[a].Peer^.address.host);
5396 enet_peer_disconnect(NetClients[a].Peer, NET_DISC_BAN);
5397 g_Net_SaveBanList();
5398 g_Console_Add(Format(_lc[I_PLAYER_BAN], [s]));
5399 MH_SEND_GameEvent(NET_EV_PLAYER_BAN, 0, s);
5400 if NetUseMaster then
5401 g_Net_Slist_Update;
5402 end;
5403 end else
5404 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5405 end
5406 else if cmd = 'unban' then
5407 begin
5408 if g_Game_IsServer and g_Game_IsNet then
5409 begin
5410 if Length(P) < 2 then
5411 begin
5412 g_Console_Add('unban <IP Address>');
5413 Exit;
5414 end;
5415 if P[1] = '' then
5416 begin
5417 g_Console_Add('unban <IP Address>');
5418 Exit;
5419 end;
5420
5421 if g_Net_UnbanHost(P[1]) then
5422 begin
5423 g_Console_Add(Format(_lc[I_MSG_UNBAN_OK], [P[1]]));
5424 g_Net_SaveBanList();
5425 end else
5426 g_Console_Add(Format(_lc[I_MSG_UNBAN_FAIL], [P[1]]));
5427 end else
5428 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5429 end
5430 else if cmd = 'clientlist' then
5431 begin
5432 if g_Game_IsServer and g_Game_IsNet then
5433 begin
5434 b := 0;
5435 if NetClients <> nil then
5436 for a := Low(NetClients) to High(NetClients) do
5437 if NetClients[a].Used and (NetClients[a].Peer <> nil) then
5438 begin
5439 plr := g_Player_Get(NetClients[a].Player);
5440 if plr = nil then continue;
5441 Inc(b);
5442 g_Console_Add(Format('#%2d: %-15s | %s', [a,
5443 IpToStr(NetClients[a].Peer^.address.host), plr.Name]));
5444 end;
5445 if b = 0 then
5446 g_Console_Add(_lc[I_MSG_NOCLIENTS]);
5447 end else
5448 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5449 end
5450 else if cmd = 'connect' then
5451 begin
5452 if (NetMode = NET_NONE) then
5453 begin
5454 if Length(P) < 2 then
5455 begin
5456 g_Console_Add('connect <IP> [port] [password]');
5457 Exit;
5458 end;
5459 if P[1] = '' then
5460 begin
5461 g_Console_Add('connect <IP> [port] [password]');
5462 Exit;
5463 end;
5464
5465 if Length(P) > 2 then
5466 prt := StrToIntDef(P[2], 25666)
5467 else
5468 prt := 25666;
5469
5470 if Length(P) > 3 then
5471 pw := P[3]
5472 else
5473 pw := '';
5474
5475 g_Game_StartClient(P[1], prt, pw);
5476 end;
5477 end
5478 else if cmd = 'disconnect' then
5479 begin
5480 if (NetMode = NET_CLIENT) then
5481 g_Net_Disconnect();
5482 end
5483 else if cmd = 'reconnect' then
5484 begin
5485 if (NetMode = NET_SERVER) then
5486 Exit;
5487
5488 if (NetMode = NET_CLIENT) then
5489 begin
5490 g_Net_Disconnect();
5491 gExit := EXIT_SIMPLE;
5492 EndGame;
5493 end;
5494
5495 //TODO: Use last successful password to reconnect, instead of ''
5496 g_Game_StartClient(NetClientIP, NetClientPort, '');
5497 end
5498 else if (cmd = 'addbot') or
5499 (cmd = 'bot_add') then
5500 begin
5501 if Length(P) > 1 then
5502 g_Bot_Add(TEAM_NONE, StrToIntDef(P[1], 2))
5503 else
5504 g_Bot_Add(TEAM_NONE, 2);
5505 end
5506 else if cmd = 'bot_addlist' then
5507 begin
5508 if Length(P) > 1 then
5509 if Length(P) = 2 then
5510 g_Bot_AddList(TEAM_NONE, P[1], StrToIntDef(P[1], -1))
5511 else
5512 g_Bot_AddList(IfThen(P[2] = 'red', TEAM_RED, TEAM_BLUE), P[1], StrToIntDef(P[1], -1));
5513 end
5514 else if cmd = 'bot_removeall' then
5515 g_Bot_RemoveAll()
5516 else if cmd = 'chat' then
5517 begin
5518 if g_Game_IsNet then
5519 begin
5520 if Length(P) > 1 then
5521 begin
5522 for a := 1 to High(P) do
5523 chstr := chstr + P[a] + ' ';
5524
5525 if Length(chstr) > 200 then SetLength(chstr, 200);
5526
5527 if Length(chstr) < 1 then
5528 begin
5529 g_Console_Add('chat <text>');
5530 Exit;
5531 end;
5532
5533 chstr := b_Text_Format(chstr);
5534 if g_Game_IsClient then
5535 MC_SEND_Chat(chstr, NET_CHAT_PLAYER)
5536 else
5537 MH_SEND_Chat(gPlayer1Settings.Name + ': ' + chstr, NET_CHAT_PLAYER);
5538 end
5539 else
5540 g_Console_Add('chat <text>');
5541 end else
5542 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5543 end
5544 else if cmd = 'teamchat' then
5545 begin
5546 if g_Game_IsNet and (gGameSettings.GameMode in [GM_TDM, GM_CTF]) then
5547 begin
5548 if Length(P) > 1 then
5549 begin
5550 for a := 1 to High(P) do
5551 chstr := chstr + P[a] + ' ';
5552
5553 if Length(chstr) > 200 then SetLength(chstr, 200);
5554
5555 if Length(chstr) < 1 then
5556 begin
5557 g_Console_Add('teamchat <text>');
5558 Exit;
5559 end;
5560
5561 chstr := b_Text_Format(chstr);
5562 if g_Game_IsClient then
5563 MC_SEND_Chat(chstr, NET_CHAT_TEAM)
5564 else
5565 MH_SEND_Chat(gPlayer1Settings.Name + ': ' + chstr, NET_CHAT_TEAM,
5566 gPlayer1Settings.Team);
5567 end
5568 else
5569 g_Console_Add('teamchat <text>');
5570 end else
5571 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5572 end
5573 else if cmd = 'game' then
5574 begin
5575 if gGameSettings.GameType <> GT_NONE then
5576 begin
5577 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5578 Exit;
5579 end;
5580 if Length(P) = 1 then
5581 begin
5582 g_Console_Add(cmd + ' <WAD> [MAP] [# players]');
5583 Exit;
5584 end;
5585 // Èãðà åù¸ íå çàïóùåíà, ñíà÷àëà íàì íàäî çàãðóçèòü êàêîé-òî WAD
5586 P[1] := addWadExtension(P[1]);
5587 if FileExists(MapsDir + P[1]) then
5588 begin
5589 // Åñëè êàðòà íå óêàçàíà, áåð¸ì ïåðâóþ êàðòó â ôàéëå
5590 if Length(P) < 3 then
5591 begin
5592 SetLength(P, 3);
5593 P[2] := g_Game_GetFirstMap(MapsDir + P[1]);
5594 end;
5595
5596 s := P[1] + ':\' + UpperCase(P[2]);
5597
5598 if g_Map_Exist(MapsDir + s) then
5599 begin
5600 // Çàïóñêàåì ñâîþ èãðó
5601 g_Game_Free();
5602 with gGameSettings do
5603 begin
5604 GameMode := g_Game_TextToMode(gcGameMode);
5605 if gSwitchGameMode <> GM_NONE then
5606 GameMode := gSwitchGameMode;
5607 if GameMode = GM_NONE then GameMode := GM_DM;
5608 if GameMode = GM_SINGLE then GameMode := GM_COOP;
5609 b := 1;
5610 if Length(P) >= 4 then
5611 b := StrToIntDef(P[3], 1);
5612 g_Game_StartCustom(s, GameMode, TimeLimit,
5613 GoalLimit, MaxLives, Options, b);
5614 end;
5615 end
5616 else
5617 if P[2] = '' then
5618 g_Console_Add(Format(_lc[I_MSG_NO_MAPS], [P[1]]))
5619 else
5620 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [UpperCase(P[2])]));
5621 end else
5622 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[1]]));
5623 end
5624 else if cmd = 'host' then
5625 begin
5626 if gGameSettings.GameType <> GT_NONE then
5627 begin
5628 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5629 Exit;
5630 end;
5631 if Length(P) < 4 then
5632 begin
5633 g_Console_Add(cmd + ' <listen IP> <port> <WAD> [MAP] [# players]');
5634 Exit;
5635 end;
5636 if not StrToIp(P[1], listen) then
5637 Exit;
5638 prt := StrToIntDef(P[2], 25666);
5639
5640 P[3] := addWadExtension(P[3]);
5641 if FileExists(MapsDir + P[3]) then
5642 begin
5643 // Åñëè êàðòà íå óêàçàíà, áåð¸ì ïåðâóþ êàðòó â ôàéëå
5644 if Length(P) < 5 then
5645 begin
5646 SetLength(P, 5);
5647 P[4] := g_Game_GetFirstMap(MapsDir + P[1]);
5648 end;
5649
5650 s := P[3] + ':\' + UpperCase(P[4]);
5651
5652 if g_Map_Exist(MapsDir + s) then
5653 begin
5654 // Çàïóñêàåì ñâîþ èãðó
5655 g_Game_Free();
5656 with gGameSettings do
5657 begin
5658 GameMode := g_Game_TextToMode(gcGameMode);
5659 if gSwitchGameMode <> GM_NONE then
5660 GameMode := gSwitchGameMode;
5661 if GameMode = GM_NONE then GameMode := GM_DM;
5662 if GameMode = GM_SINGLE then GameMode := GM_COOP;
5663 b := 0;
5664 if Length(P) >= 6 then
5665 b := StrToIntDef(P[5], 0);
5666 g_Game_StartServer(s, GameMode, TimeLimit,
5667 GoalLimit, MaxLives, Options, b, listen, prt);
5668 end;
5669 end
5670 else
5671 if P[4] = '' then
5672 g_Console_Add(Format(_lc[I_MSG_NO_MAPS], [P[3]]))
5673 else
5674 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [UpperCase(P[4])]));
5675 end else
5676 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[3]]));
5677 end
5678 else if cmd = 'map' then
5679 begin
5680 if Length(P) = 1 then
5681 begin
5682 if g_Game_IsServer and (gGameSettings.GameType <> GT_SINGLE) then
5683 begin
5684 g_Console_Add(cmd + ' <MAP>');
5685 g_Console_Add(cmd + ' <WAD> [MAP]');
5686 end else
5687 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5688 end else
5689 if g_Game_IsServer and (gGameSettings.GameType <> GT_SINGLE) then
5690 begin
5691 // Èä¸ò ñâîÿ èãðà èëè ñåðâåð
5692 if Length(P) < 3 then
5693 begin
5694 // Ïåðâûé ïàðàìåòð - ëèáî êàðòà, ëèáî èìÿ WAD ôàéëà
5695 s := UpperCase(P[1]);
5696 if g_Map_Exist(MapsDir + gGameSettings.WAD + ':\' + s) then
5697 begin // Êàðòà íàøëàñü
5698 gExitByTrigger := False;
5699 if gGameOn then
5700 begin // Èä¸ò èãðà - çàâåðøàåì óðîâåíü
5701 gNextMap := s;
5702 gExit := EXIT_ENDLEVELCUSTOM;
5703 end
5704 else // Èíòåðìèññèÿ - ñðàçó çàãðóæàåì êàðòó
5705 g_Game_ChangeMap(s);
5706 end else
5707 begin
5708 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [s]));
5709 // Òàêîé êàðòû íåò, èùåì WAD ôàéë
5710 P[1] := addWadExtension(P[1]);
5711 if FileExists(MapsDir + P[1]) then
5712 begin
5713 // Ïàðàìåòðà êàðòû íåò, ïîýòîìó ñòàâèì ïåðâóþ èç ôàéëà
5714 SetLength(P, 3);
5715 P[2] := g_Game_GetFirstMap(MapsDir + P[1]);
5716
5717 s := P[1] + ':\' + P[2];
5718
5719 if g_Map_Exist(MapsDir + s) then
5720 begin
5721 gExitByTrigger := False;
5722 if gGameOn then
5723 begin // Èä¸ò èãðà - çàâåðøàåì óðîâåíü
5724 gNextMap := s;
5725 gExit := EXIT_ENDLEVELCUSTOM;
5726 end
5727 else // Èíòåðìèññèÿ - ñðàçó çàãðóæàåì êàðòó
5728 g_Game_ChangeMap(s);
5729 end else
5730 if P[2] = '' then
5731 g_Console_Add(Format(_lc[I_MSG_NO_MAPS], [P[1]]))
5732 else
5733 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [P[2]]));
5734 end else
5735 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[1]]));
5736 end;
5737 end else
5738 begin
5739 // Óêàçàíî äâà ïàðàìåòðà, çíà÷èò ïåðâûé - WAD ôàéë, à âòîðîé - êàðòà
5740 P[1] := addWadExtension(P[1]);
5741 if FileExists(MapsDir + P[1]) then
5742 begin
5743 // Íàøëè WAD ôàéë
5744 P[2] := UpperCase(P[2]);
5745 s := P[1] + ':\' + P[2];
5746
5747 if g_Map_Exist(MapsDir + s) then
5748 begin // Íàøëè êàðòó
5749 gExitByTrigger := False;
5750 if gGameOn then
5751 begin // Èä¸ò èãðà - çàâåðøàåì óðîâåíü
5752 gNextMap := s;
5753 gExit := EXIT_ENDLEVELCUSTOM;
5754 end
5755 else // Èíòåðìèññèÿ - ñðàçó çàãðóæàåì êàðòó
5756 g_Game_ChangeMap(s);
5757 end else
5758 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [P[2]]));
5759 end else
5760 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[1]]));
5761 end;
5762 end else
5763 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5764 end
5765 else if cmd = 'nextmap' then
5766 begin
5767 if not(gGameOn or (gState = STATE_INTERCUSTOM)) then
5768 g_Console_Add(_lc[I_MSG_NOT_GAME])
5769 else begin
5770 nm := True;
5771 if Length(P) = 1 then
5772 begin
5773 if g_Game_IsServer and (gGameSettings.GameType <> GT_SINGLE) then
5774 begin
5775 g_Console_Add(cmd + ' <MAP>');
5776 g_Console_Add(cmd + ' <WAD> [MAP]');
5777 end else begin
5778 nm := False;
5779 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5780 end;
5781 end else
5782 begin
5783 nm := False;
5784 if g_Game_IsServer and (gGameSettings.GameType <> GT_SINGLE) then
5785 begin
5786 if Length(P) < 3 then
5787 begin
5788 // Ïåðâûé ïàðàìåòð - ëèáî êàðòà, ëèáî èìÿ WAD ôàéëà
5789 s := UpperCase(P[1]);
5790 if g_Map_Exist(MapsDir + gGameSettings.WAD + ':\' + s) then
5791 begin // Êàðòà íàøëàñü
5792 gExitByTrigger := False;
5793 gNextMap := s;
5794 nm := True;
5795 end else
5796 begin
5797 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [s]));
5798 // Òàêîé êàðòû íåò, èùåì WAD ôàéë
5799 P[1] := addWadExtension(P[1]);
5800 if FileExists(MapsDir + P[1]) then
5801 begin
5802 // Ïàðàìåòðà êàðòû íåò, ïîýòîìó ñòàâèì ïåðâóþ èç ôàéëà
5803 SetLength(P, 3);
5804 P[2] := g_Game_GetFirstMap(MapsDir + P[1]);
5805
5806 s := P[1] + ':\' + P[2];
5807
5808 if g_Map_Exist(MapsDir + s) then
5809 begin // Óñòàíàâëèâàåì êàðòó
5810 gExitByTrigger := False;
5811 gNextMap := s;
5812 nm := True;
5813 end else
5814 if P[2] = '' then
5815 g_Console_Add(Format(_lc[I_MSG_NO_MAPS], [P[1]]))
5816 else
5817 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [P[2]]));
5818 end else
5819 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[1]]));
5820 end;
5821 end else
5822 begin
5823 // Óêàçàíî äâà ïàðàìåòðà, çíà÷èò ïåðâûé - WAD ôàéë, à âòîðîé - êàðòà
5824 P[1] := addWadExtension(P[1]);
5825 if FileExists(MapsDir + P[1]) then
5826 begin
5827 // Íàøëè WAD ôàéë
5828 P[2] := UpperCase(P[2]);
5829 s := P[1] + ':\' + P[2];
5830
5831 if g_Map_Exist(MapsDir + s) then
5832 begin // Íàøëè êàðòó
5833 gExitByTrigger := False;
5834 gNextMap := s;
5835 nm := True;
5836 end else
5837 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [P[2]]));
5838 end else
5839 g_Console_Add(Format(_lc[I_MSG_NO_WAD], [P[1]]));
5840 end;
5841 end else
5842 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5843 end;
5844 if nm then
5845 if gNextMap = '' then
5846 g_Console_Add(_lc[I_MSG_NEXTMAP_UNSET])
5847 else
5848 g_Console_Add(Format(_lc[I_MSG_NEXTMAP_SET], [gNextMap]));
5849 end;
5850 end
5851 else if (cmd = 'endmap') or (cmd = 'goodbye') then
5852 begin
5853 if not gGameOn then
5854 g_Console_Add(_lc[I_MSG_NOT_GAME])
5855 else
5856 if g_Game_IsServer and (gGameSettings.GameType <> GT_SINGLE) then
5857 begin
5858 gExitByTrigger := False;
5859 // Ñëåäóþùàÿ êàðòà íå çàäàíà, ïðîáóåì íàéòè òðèããåð Âûõîä
5860 if (gNextMap = '') and (gTriggers <> nil) then
5861 for a := 0 to High(gTriggers) do
5862 if gTriggers[a].TriggerType = TRIGGER_EXIT then
5863 begin
5864 gExitByTrigger := True;
5865 gNextMap := gTriggers[a].Data.MapName;
5866 Break;
5867 end;
5868 // Èùåì ñëåäóþùóþ êàðòó â WAD ôàéëå
5869 if gNextMap = '' then
5870 gNextMap := g_Game_GetNextMap();
5871 // Ïðîâåðÿåì, íå çàäàí ëè WAD ôàéë ðåñóðñíîé ñòðîêîé
5872 if Pos(':\', gNextMap) = 0 then
5873 s := gGameSettings.WAD + ':\' + gNextMap
5874 else
5875 s := gNextMap;
5876 // Åñëè êàðòà íàéäåíà, âûõîäèì ñ óðîâíÿ
5877 if g_Map_Exist(MapsDir + s) then
5878 gExit := EXIT_ENDLEVELCUSTOM
5879 else
5880 g_Console_Add(Format(_lc[I_MSG_NO_MAP], [gNextMap]));
5881 end else
5882 g_Console_Add(_lc[I_MSG_GM_UNAVAIL]);
5883 end
5884 else if (cmd = 'event') then
5885 begin
5886 if (Length(P) <= 1) then
5887 begin
5888 for a := 0 to High(gEvents) do
5889 if gEvents[a].Command = '' then
5890 g_Console_Add(gEvents[a].Name + ' <none>')
5891 else
5892 g_Console_Add(gEvents[a].Name + ' "' + gEvents[a].Command + '"');
5893 Exit;
5894 end;
5895 if (Length(P) = 2) then
5896 begin
5897 for a := 0 to High(gEvents) do
5898 if gEvents[a].Name = P[1] then
5899 if gEvents[a].Command = '' then
5900 g_Console_Add(gEvents[a].Name + ' <none>')
5901 else
5902 g_Console_Add(gEvents[a].Name + ' "' + gEvents[a].Command + '"');
5903 Exit;
5904 end;
5905 for a := 0 to High(gEvents) do
5906 if gEvents[a].Name = P[1] then
5907 begin
5908 gEvents[a].Command := '';
5909 for b := 2 to High(P) do
5910 if Pos(' ', P[b]) = 0 then
5911 gEvents[a].Command := gEvents[a].Command + ' ' + P[b]
5912 else
5913 gEvents[a].Command := gEvents[a].Command + ' "' + P[b] + '"';
5914 gEvents[a].Command := Trim(gEvents[a].Command);
5915 Exit;
5916 end;
5917 end
5918 // Êîìàíäû Ñâîåé èãðû:
5919 else if gGameSettings.GameType in [GT_CUSTOM, GT_SERVER, GT_CLIENT] then
5920 begin
5921 if cmd = 'bot_addred' then
5922 begin
5923 if Length(P) > 1 then
5924 g_Bot_Add(TEAM_RED, StrToIntDef(P[1], 2))
5925 else
5926 g_Bot_Add(TEAM_RED, 2);
5927 end
5928 else if cmd = 'bot_addblue' then
5929 begin
5930 if Length(P) > 1 then
5931 g_Bot_Add(TEAM_BLUE, StrToIntDef(P[1], 2))
5932 else
5933 g_Bot_Add(TEAM_BLUE, 2);
5934 end
5935 else if cmd = 'suicide' then
5936 begin
5937 if gGameOn then
5938 begin
5939 if g_Game_IsClient then
5940 MC_SEND_CheatRequest(NET_CHEAT_SUICIDE)
5941 else
5942 begin
5943 if gPlayer1 <> nil then
5944 gPlayer1.Damage(SUICIDE_DAMAGE, gPlayer1.UID, 0, 0, HIT_SELF);
5945 if gPlayer2 <> nil then
5946 gPlayer2.Damage(SUICIDE_DAMAGE, gPlayer2.UID, 0, 0, HIT_SELF);
5947 end;
5948 end;
5949 end
5950 else if cmd = 'spectate' then
5951 begin
5952 if not gGameOn then
5953 Exit;
5954 g_Game_Spectate();
5955 end
5956 else if cmd = 'say' then
5957 begin
5958 if g_Game_IsServer and g_Game_IsNet then
5959 begin
5960 if Length(P) > 1 then
5961 begin
5962 chstr := '';
5963 for a := 1 to High(P) do
5964 chstr := chstr + P[a] + ' ';
5965
5966 if Length(chstr) > 200 then SetLength(chstr, 200);
5967
5968 if Length(chstr) < 1 then
5969 begin
5970 g_Console_Add('say <text>');
5971 Exit;
5972 end;
5973
5974 chstr := b_Text_Format(chstr);
5975 MH_SEND_Chat(chstr, NET_CHAT_PLAYER);
5976 end
5977 else g_Console_Add('say <text>');
5978 end else
5979 g_Console_Add(_lc[I_MSG_SERVERONLY]);
5980 end
5981 else if cmd = 'tell' then
5982 begin
5983 if g_Game_IsServer and g_Game_IsNet then
5984 begin
5985 if (Length(P) > 2) and (P[1] <> '') then
5986 begin
5987 chstr := '';
5988 for a := 2 to High(P) do
5989 chstr := chstr + P[a] + ' ';
5990
5991 if Length(chstr) > 200 then SetLength(chstr, 200);
5992
5993 if Length(chstr) < 1 then
5994 begin
5995 g_Console_Add('tell <playername> <text>');
5996 Exit;
5997 end;
5998
5999 pl := g_Net_Client_ByName(P[1]);
6000 if pl <> nil then
6001 MH_SEND_Chat(b_Text_Format(chstr), NET_CHAT_PLAYER, pl^.ID)
6002 else
6003 g_Console_Add(Format(_lc[I_NET_ERR_NAME404], [P[1]]));
6004 end
6005 else g_Console_Add('tell <playername> <text>');
6006 end else
6007 g_Console_Add(_lc[I_MSG_SERVERONLY]);
6008 end
6009 else if (cmd = 'overtime') and not g_Game_IsClient then
6010 begin
6011 if (Length(P) = 1) or (StrToIntDef(P[1], -1) <= 0) then
6012 Exit;
6013 // Äîïîëíèòåëüíîå âðåìÿ:
6014 gGameSettings.TimeLimit := (gTime - gGameStartTime) div 1000 + Word(StrToIntDef(P[1], 0));
6015
6016 g_Console_Add(Format(_lc[I_MSG_TIME_LIMIT],
6017 [gGameSettings.TimeLimit div 3600,
6018 (gGameSettings.TimeLimit div 60) mod 60,
6019 gGameSettings.TimeLimit mod 60]));
6020 if g_Game_IsNet then MH_SEND_GameSettings;
6021 end
6022 else if (cmd = 'rcon_password') and g_Game_IsClient then
6023 begin
6024 if (Length(P) <= 1) then
6025 g_Console_Add('rcon_password <password>')
6026 else
6027 MC_SEND_RCONPassword(P[1]);
6028 end
6029 else if cmd = 'rcon' then
6030 begin
6031 if g_Game_IsClient then
6032 begin
6033 if Length(P) > 1 then
6034 begin
6035 chstr := '';
6036 for a := 1 to High(P) do
6037 chstr := chstr + P[a] + ' ';
6038
6039 if Length(chstr) > 200 then SetLength(chstr, 200);
6040
6041 if Length(chstr) < 1 then
6042 begin
6043 g_Console_Add('rcon <command>');
6044 Exit;
6045 end;
6046
6047 MC_SEND_RCONCommand(chstr);
6048 end
6049 else g_Console_Add('rcon <command>');
6050 end;
6051 end
6052 else if cmd = 'ready' then
6053 begin
6054 if g_Game_IsServer and (gLMSRespawn = LMS_RESPAWN_WARMUP) then
6055 gLMSRespawnTime := gTime + 100;
6056 end
6057 else if (cmd = 'callvote') and g_Game_IsNet then
6058 begin
6059 if Length(P) > 1 then
6060 begin
6061 chstr := '';
6062 for a := 1 to High(P) do begin
6063 if a > 1 then chstr := chstr + ' ';
6064 chstr := chstr + P[a];
6065 end;
6066
6067 if Length(chstr) > 200 then SetLength(chstr, 200);
6068
6069 if Length(chstr) < 1 then
6070 begin
6071 g_Console_Add('callvote <command>');
6072 Exit;
6073 end;
6074
6075 if g_Game_IsClient then
6076 MC_SEND_Vote(True, chstr)
6077 else
6078 g_Game_StartVote(chstr, gPlayer1Settings.Name);
6079 g_Console_Process('vote', True);
6080 end
6081 else
6082 g_Console_Add('callvote <command>');
6083 end
6084 else if (cmd = 'vote') and g_Game_IsNet then
6085 begin
6086 if g_Game_IsClient then
6087 MC_SEND_Vote(False)
6088 else if gVoteInProgress then
6089 begin
6090 if (gPlayer1 <> nil) or (gPlayer2 <> nil) then
6091 a := Floor((NetClientCount+1)/2.0) + 1
6092 else
6093 a := Floor(NetClientCount/2.0) + 1;
6094 if gVoted then
6095 begin
6096 Dec(gVoteCount);
6097 gVoted := False;
6098 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_REVOKED], [gPlayer1Settings.Name, gVoteCount, a]), True);
6099 MH_SEND_VoteEvent(NET_VE_REVOKE, gPlayer1Settings.Name, 'a', gVoteCount, a);
6100 end
6101 else
6102 begin
6103 Inc(gVoteCount);
6104 gVoted := True;
6105 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_VOTE], [gPlayer1Settings.Name, gVoteCount, a]), True);
6106 MH_SEND_VoteEvent(NET_VE_VOTE, gPlayer1Settings.Name, 'a', gVoteCount, a);
6107 g_Game_CheckVote;
6108 end;
6109 end;
6110 end
6111 end;
6112 end;
6113
6114 procedure g_TakeScreenShot();
6115 var
6116 a: Word;
6117 FileName: string;
6118 ssdir, t: string;
6119 st: TStream;
6120 ok: Boolean;
6121 begin
6122 if e_NoGraphics then Exit;
6123 ssdir := GameDir+'/screenshots';
6124 if not findFileCI(ssdir, true) then
6125 begin
6126 // try to create dir
6127 try
6128 CreateDir(ssdir);
6129 except
6130 end;
6131 if not findFileCI(ssdir, true) then exit; // alas
6132 end;
6133 try
6134 for a := 1 to High(Word) do
6135 begin
6136 FileName := Format(ssdir+'screenshot%.3d.png', [a]);
6137 t := FileName;
6138 if findFileCI(t, true) then continue;
6139 if not findFileCI(FileName) then
6140 begin
6141 ok := false;
6142 st := createDiskFile(FileName);
6143 try
6144 e_MakeScreenshot(st, gScreenWidth, gScreenHeight);
6145 ok := true;
6146 finally
6147 st.Free();
6148 end;
6149 if not ok then try DeleteFile(FileName); except end else g_Console_Add(Format(_lc[I_CONSOLE_SCREENSHOT], [ExtractFileName(FileName)]));
6150 break;
6151 end;
6152 end;
6153 except
6154 end;
6155 end;
6156
6157 procedure g_Game_InGameMenu(Show: Boolean);
6158 begin
6159 if (g_ActiveWindow = nil) and Show then
6160 begin
6161 if gGameSettings.GameType = GT_SINGLE then
6162 g_GUI_ShowWindow('GameSingleMenu')
6163 else
6164 begin
6165 if g_Game_IsClient then
6166 g_GUI_ShowWindow('GameClientMenu')
6167 else
6168 if g_Game_IsNet then
6169 g_GUI_ShowWindow('GameServerMenu')
6170 else
6171 g_GUI_ShowWindow('GameCustomMenu');
6172 end;
6173 g_Sound_PlayEx('MENU_OPEN');
6174
6175 // Ïàóçà ïðè ìåíþ òîëüêî â îäèíî÷íîé èãðå:
6176 if (not g_Game_IsNet) then
6177 g_Game_Pause(True);
6178 end
6179 else
6180 if (g_ActiveWindow <> nil) and (not Show) then
6181 begin
6182 // Ïàóçà ïðè ìåíþ òîëüêî â îäèíî÷íîé èãðå:
6183 if (not g_Game_IsNet) then
6184 g_Game_Pause(False);
6185 end;
6186 end;
6187
6188 procedure g_Game_Pause(Enable: Boolean);
6189 begin
6190 if not gGameOn then
6191 Exit;
6192
6193 if gPause = Enable then
6194 Exit;
6195
6196 if not (gGameSettings.GameType in [GT_SINGLE, GT_CUSTOM]) then
6197 Exit;
6198
6199 gPause := Enable;
6200 g_Game_PauseAllSounds(Enable);
6201 end;
6202
6203 procedure g_Game_PauseAllSounds(Enable: Boolean);
6204 var
6205 i: Integer;
6206 begin
6207 // Òðèããåðû:
6208 if gTriggers <> nil then
6209 for i := 0 to High(gTriggers) do
6210 with gTriggers[i] do
6211 if (TriggerType = TRIGGER_SOUND) and
6212 (Sound <> nil) and
6213 Sound.IsPlaying() then
6214 begin
6215 Sound.Pause(Enable);
6216 end;
6217
6218 // Çâóêè èãðîêîâ:
6219 if gPlayers <> nil then
6220 for i := 0 to High(gPlayers) do
6221 if gPlayers[i] <> nil then
6222 gPlayers[i].PauseSounds(Enable);
6223
6224 // Ìóçûêà:
6225 if gMusic <> nil then
6226 gMusic.Pause(Enable);
6227 end;
6228
6229 procedure g_Game_StopAllSounds(all: Boolean);
6230 var
6231 i: Integer;
6232 begin
6233 if gTriggers <> nil then
6234 for i := 0 to High(gTriggers) do
6235 with gTriggers[i] do
6236 if (TriggerType = TRIGGER_SOUND) and
6237 (Sound <> nil) then
6238 Sound.Stop();
6239
6240 if gMusic <> nil then
6241 gMusic.Stop();
6242
6243 if all then
6244 e_StopChannels();
6245 end;
6246
6247 procedure g_Game_UpdateTriggerSounds();
6248 var
6249 i: Integer;
6250 begin
6251 if gTriggers <> nil then
6252 for i := 0 to High(gTriggers) do
6253 with gTriggers[i] do
6254 if (TriggerType = TRIGGER_SOUND) and
6255 (Sound <> nil) and
6256 (Data.Local) and
6257 Sound.IsPlaying() then
6258 begin
6259 if ((gPlayer1 <> nil) and g_CollidePoint(gPlayer1.GameX, gPlayer1.GameY, X, Y, Width, Height)) or
6260 ((gPlayer2 <> nil) and g_CollidePoint(gPlayer2.GameX, gPlayer2.GameY, X, Y, Width, Height)) then
6261 begin
6262 Sound.SetPan(0.5 - Data.Pan/255.0);
6263 Sound.SetVolume(Data.Volume/255.0);
6264 end
6265 else
6266 Sound.SetCoords(X+(Width div 2), Y+(Height div 2), Data.Volume/255.0);
6267 end;
6268 end;
6269
6270 function g_Game_IsWatchedPlayer(UID: Word): Boolean;
6271 begin
6272 Result := False;
6273 if (gPlayer1 <> nil) and (gPlayer1.UID = UID) then
6274 begin
6275 Result := True;
6276 Exit;
6277 end;
6278 if (gPlayer2 <> nil) and (gPlayer2.UID = UID) then
6279 begin
6280 Result := True;
6281 Exit;
6282 end;
6283 if gSpectMode <> SPECT_PLAYERS then
6284 Exit;
6285 if gSpectPID1 = UID then
6286 begin
6287 Result := True;
6288 Exit;
6289 end;
6290 if gSpectViewTwo and (gSpectPID2 = UID) then
6291 begin
6292 Result := True;
6293 Exit;
6294 end;
6295 end;
6296
6297 function g_Game_IsWatchedTeam(Team: Byte): Boolean;
6298 var
6299 Pl: TPlayer;
6300 begin
6301 Result := False;
6302 if (gPlayer1 <> nil) and (gPlayer1.Team = Team) then
6303 begin
6304 Result := True;
6305 Exit;
6306 end;
6307 if (gPlayer2 <> nil) and (gPlayer2.Team = Team) then
6308 begin
6309 Result := True;
6310 Exit;
6311 end;
6312 if gSpectMode <> SPECT_PLAYERS then
6313 Exit;
6314 Pl := g_Player_Get(gSpectPID1);
6315 if (Pl <> nil) and (Pl.Team = Team) then
6316 begin
6317 Result := True;
6318 Exit;
6319 end;
6320 if gSpectViewTwo then
6321 begin
6322 Pl := g_Player_Get(gSpectPID2);
6323 if (Pl <> nil) and (Pl.Team = Team) then
6324 begin
6325 Result := True;
6326 Exit;
6327 end;
6328 end;
6329 end;
6330
6331 procedure g_Game_Message(Msg: string; Time: Word);
6332 begin
6333 MessageText := b_Text_Format(Msg);
6334 MessageTime := Time;
6335 end;
6336
6337 procedure g_Game_Announce_GoodShot(SpawnerUID: Word);
6338 var
6339 a: Integer;
6340 begin
6341 case gAnnouncer of
6342 ANNOUNCE_NONE:
6343 Exit;
6344 ANNOUNCE_ME,
6345 ANNOUNCE_MEPLUS:
6346 if not g_Game_IsWatchedPlayer(SpawnerUID) then
6347 Exit;
6348 end;
6349 for a := 0 to 3 do
6350 if goodsnd[a].IsPlaying() then
6351 Exit;
6352
6353 goodsnd[Random(4)].Play();
6354 end;
6355
6356 procedure g_Game_Announce_KillCombo(Param: Integer);
6357 var
6358 UID: Word;
6359 c, n: Byte;
6360 Pl: TPlayer;
6361 Name: String;
6362 begin
6363 UID := Param and $FFFF;
6364 c := Param shr 16;
6365 if c < 2 then
6366 Exit;
6367
6368 Pl := g_Player_Get(UID);
6369 if Pl = nil then
6370 Name := '?'
6371 else
6372 Name := Pl.Name;
6373
6374 case c of
6375 2: begin
6376 n := 0;
6377 g_Console_Add(Format(_lc[I_PLAYER_KILL_2X], [Name]), True);
6378 end;
6379 3: begin
6380 n := 1;
6381 g_Console_Add(Format(_lc[I_PLAYER_KILL_3X], [Name]), True);
6382 end;
6383 4: begin
6384 n := 2;
6385 g_Console_Add(Format(_lc[I_PLAYER_KILL_4X], [Name]), True);
6386 end;
6387 else begin
6388 n := 3;
6389 g_Console_Add(Format(_lc[I_PLAYER_KILL_MX], [Name]), True);
6390 end;
6391 end;
6392
6393 case gAnnouncer of
6394 ANNOUNCE_NONE:
6395 Exit;
6396 ANNOUNCE_ME:
6397 if not g_Game_IsWatchedPlayer(UID) then
6398 Exit;
6399 ANNOUNCE_MEPLUS:
6400 if (not g_Game_IsWatchedPlayer(UID)) and (c < 4) then
6401 Exit;
6402 end;
6403
6404 if killsnd[n].IsPlaying() then
6405 killsnd[n].Stop();
6406 killsnd[n].Play();
6407 end;
6408
6409 procedure g_Game_StartVote(Command, Initiator: string);
6410 var
6411 Need: Integer;
6412 begin
6413 if not gVotesEnabled then Exit;
6414 if gGameSettings.GameType <> GT_SERVER then Exit;
6415 if gVoteInProgress or gVotePassed then
6416 begin
6417 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_INPROGRESS], [gVoteCommand]), True);
6418 MH_SEND_VoteEvent(NET_VE_INPROGRESS, gVoteCommand);
6419 Exit;
6420 end;
6421 gVoteInProgress := True;
6422 gVotePassed := False;
6423 gVoteTimer := gTime + gVoteTimeout * 1000;
6424 gVoteCount := 0;
6425 gVoted := False;
6426 gVoteCommand := Command;
6427
6428 if (gPlayer1 <> nil) or (gPlayer2 <> nil) then
6429 Need := Floor((NetClientCount+1)/2.0)+1
6430 else
6431 Need := Floor(NetClientCount/2.0)+1;
6432 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_STARTED], [Initiator, Command, Need]), True);
6433 MH_SEND_VoteEvent(NET_VE_STARTED, Initiator, Command, Need);
6434 end;
6435
6436 procedure g_Game_CheckVote;
6437 var
6438 I, Need: Integer;
6439 begin
6440 if gGameSettings.GameType <> GT_SERVER then Exit;
6441 if not gVoteInProgress then Exit;
6442
6443 if (gTime >= gVoteTimer) then
6444 begin
6445 if (gPlayer1 <> nil) or (gPlayer2 <> nil) then
6446 Need := Floor((NetClientCount+1)/2.0) + 1
6447 else
6448 Need := Floor(NetClientCount/2.0) + 1;
6449 if gVoteCount >= Need then
6450 begin
6451 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_PASSED], [gVoteCommand]), True);
6452 MH_SEND_VoteEvent(NET_VE_PASSED, gVoteCommand);
6453 gVotePassed := True;
6454 gVoteCmdTimer := gTime + 5000;
6455 end
6456 else
6457 begin
6458 g_Console_Add(_lc[I_MESSAGE_VOTE_FAILED], True);
6459 MH_SEND_VoteEvent(NET_VE_FAILED);
6460 end;
6461 if NetClients <> nil then
6462 for I := Low(NetClients) to High(NetClients) do
6463 if NetClients[i].Used then
6464 NetClients[i].Voted := False;
6465 gVoteInProgress := False;
6466 gVoted := False;
6467 gVoteCount := 0;
6468 end
6469 else
6470 begin
6471 if (gPlayer1 <> nil) or (gPlayer2 <> nil) then
6472 Need := Floor((NetClientCount+1)/2.0) + 1
6473 else
6474 Need := Floor(NetClientCount/2.0) + 1;
6475 if gVoteCount >= Need then
6476 begin
6477 g_Console_Add(Format(_lc[I_MESSAGE_VOTE_PASSED], [gVoteCommand]), True);
6478 MH_SEND_VoteEvent(NET_VE_PASSED, gVoteCommand);
6479 gVoteInProgress := False;
6480 gVotePassed := True;
6481 gVoteCmdTimer := gTime + 5000;
6482 gVoted := False;
6483 gVoteCount := 0;
6484 if NetClients <> nil then
6485 for I := Low(NetClients) to High(NetClients) do
6486 if NetClients[i].Used then
6487 NetClients[i].Voted := False;
6488 end;
6489 end;
6490 end;
6491
6492 procedure g_Game_LoadMapList(FileName: string);
6493 var
6494 ListFile: TextFile;
6495 s: string;
6496 begin
6497 MapList := nil;
6498 MapIndex := -1;
6499
6500 if not FileExists(FileName) then Exit;
6501
6502 AssignFile(ListFile, FileName);
6503 Reset(ListFile);
6504 while not EOF(ListFile) do
6505 begin
6506 ReadLn(ListFile, s);
6507
6508 s := Trim(s);
6509 if s = '' then Continue;
6510
6511 SetLength(MapList, Length(MapList)+1);
6512 MapList[High(MapList)] := s;
6513 end;
6514 CloseFile(ListFile);
6515 end;
6516
6517 procedure g_Game_SetDebugMode();
6518 begin
6519 gDebugMode := True;
6520 // ×èòû (äàæå â ñâîåé èãðå):
6521 gCheats := True;
6522 end;
6523
6524 procedure g_Game_SetLoadingText(Text: String; Max: Integer; reWrite: Boolean);
6525 var
6526 i: Word;
6527 begin
6528 if Length(LoadingStat.Msgs) = 0 then
6529 Exit;
6530
6531 with LoadingStat do
6532 begin
6533 if not reWrite then
6534 begin // Ïåðåõîäèì íà ñëåäóþùóþ ñòðîêó èëè ñêðîëëèðóåì:
6535 if NextMsg = Length(Msgs) then
6536 begin // scroll
6537 for i := 0 to High(Msgs)-1 do
6538 Msgs[i] := Msgs[i+1];
6539 end
6540 else
6541 Inc(NextMsg);
6542 end else
6543 if NextMsg = 0 then
6544 Inc(NextMsg);
6545
6546 Msgs[NextMsg-1] := Text;
6547 CurValue := 0;
6548 MaxValue := Max;
6549 ShowCount := 0;
6550 end;
6551
6552 g_ActiveWindow := nil;
6553
6554 ProcessLoading;
6555 end;
6556
6557 procedure g_Game_StepLoading();
6558 begin
6559 with LoadingStat do
6560 begin
6561 Inc(CurValue);
6562 Inc(ShowCount);
6563 if (ShowCount > LOADING_SHOW_STEP) then
6564 begin
6565 ShowCount := 0;
6566 ProcessLoading;
6567 end;
6568 end;
6569 end;
6570
6571 procedure g_Game_ClearLoading();
6572 var
6573 len: Word;
6574 begin
6575 with LoadingStat do
6576 begin
6577 CurValue := 0;
6578 MaxValue := 0;
6579 ShowCount := 0;
6580 len := ((gScreenHeight div 3)*2 - 50) div LOADING_INTERLINE;
6581 if len < 1 then len := 1;
6582 SetLength(Msgs, len);
6583 for len := Low(Msgs) to High(Msgs) do
6584 Msgs[len] := '';
6585 NextMsg := 0;
6586 end;
6587 end;
6588
6589 procedure Parse_Params(var pars: TParamStrValues);
6590 var
6591 i: Integer;
6592 s: String;
6593 begin
6594 SetLength(pars, 0);
6595 i := 1;
6596 while i <= ParamCount do
6597 begin
6598 s := ParamStr(i);
6599 if (s[1] = '-') and (Length(s) > 1) then
6600 begin
6601 if (s[2] = '-') and (Length(s) > 2) then
6602 begin // Îäèíî÷íûé ïàðàìåòð
6603 SetLength(pars, Length(pars) + 1);
6604 with pars[High(pars)] do
6605 begin
6606 Name := LowerCase(s);
6607 Value := '+';
6608 end;
6609 end
6610 else
6611 if (i < ParamCount) then
6612 begin // Ïàðàìåòð ñî çíà÷åíèåì
6613 Inc(i);
6614 SetLength(pars, Length(pars) + 1);
6615 with pars[High(pars)] do
6616 begin
6617 Name := LowerCase(s);
6618 Value := LowerCase(ParamStr(i));
6619 end;
6620 end;
6621 end;
6622
6623 Inc(i);
6624 end;
6625 end;
6626
6627 function Find_Param_Value(var pars: TParamStrValues; aName: String): String;
6628 var
6629 i: Integer;
6630 begin
6631 Result := '';
6632 for i := 0 to High(pars) do
6633 if pars[i].Name = aName then
6634 begin
6635 Result := pars[i].Value;
6636 Break;
6637 end;
6638 end;
6639
6640 procedure g_Game_Process_Params();
6641 var
6642 pars: TParamStrValues;
6643 map: String;
6644 GMode, n: Byte;
6645 LimT, LimS: Integer;
6646 Opt: LongWord;
6647 Lives: Integer;
6648 s: String;
6649 Port: Integer;
6650 ip: String;
6651 F: TextFile;
6652 begin
6653 Parse_Params(pars);
6654
6655 // Debug mode:
6656 s := Find_Param_Value(pars, '--debug');
6657 if (s <> '') then
6658 begin
6659 g_Game_SetDebugMode();
6660 s := Find_Param_Value(pars, '--netdump');
6661 if (s <> '') then
6662 NetDump := True;
6663 end;
6664
6665 // Connect when game loads
6666 ip := Find_Param_Value(pars, '-connect');
6667
6668 if ip <> '' then
6669 begin
6670 s := Find_Param_Value(pars, '-port');
6671 if (s = '') or not TryStrToInt(s, Port) then
6672 Port := 25666;
6673
6674 s := Find_Param_Value(pars, '-pw');
6675
6676 g_Game_StartClient(ip, Port, s);
6677 Exit;
6678 end;
6679
6680 // Start map when game loads:
6681 map := LowerCase(Find_Param_Value(pars, '-map'));
6682 if isWadPath(map) then
6683 begin
6684 // Game mode:
6685 s := Find_Param_Value(pars, '-gm');
6686 GMode := g_Game_TextToMode(s);
6687 if GMode = GM_NONE then GMode := GM_DM;
6688 if GMode = GM_SINGLE then GMode := GM_COOP;
6689
6690 // Time limit:
6691 s := Find_Param_Value(pars, '-limt');
6692 if (s = '') or (not TryStrToInt(s, LimT)) then
6693 LimT := 0;
6694 if LimT < 0 then
6695 LimT := 0;
6696
6697 // Goal limit:
6698 s := Find_Param_Value(pars, '-lims');
6699 if (s = '') or (not TryStrToInt(s, LimS)) then
6700 LimS := 0;
6701 if LimS < 0 then
6702 LimS := 0;
6703
6704 // Lives limit:
6705 s := Find_Param_Value(pars, '-lives');
6706 if (s = '') or (not TryStrToInt(s, Lives)) then
6707 Lives := 0;
6708 if Lives < 0 then
6709 Lives := 0;
6710
6711 // Options:
6712 s := Find_Param_Value(pars, '-opt');
6713 if (s = '') then
6714 Opt := GAME_OPTION_ALLOWEXIT or GAME_OPTION_BOTVSPLAYER or GAME_OPTION_BOTVSMONSTER
6715 else
6716 Opt := StrToIntDef(s, 0);
6717 if Opt = 0 then
6718 Opt := GAME_OPTION_ALLOWEXIT or GAME_OPTION_BOTVSPLAYER or GAME_OPTION_BOTVSMONSTER;
6719
6720 // Close after map:
6721 s := Find_Param_Value(pars, '--close');
6722 if (s <> '') then
6723 gMapOnce := True;
6724
6725 // Delete test map after play:
6726 s := Find_Param_Value(pars, '--testdelete');
6727 if (s <> '') then
6728 begin
6729 gMapToDelete := MapsDir + map;
6730 e_WriteLog('"--testdelete" is deprecated, use --tempdelete.', MSG_FATALERROR);
6731 Halt(1);
6732 end;
6733
6734 // Delete temporary WAD after play:
6735 s := Find_Param_Value(pars, '--tempdelete');
6736 if (s <> '') then
6737 begin
6738 gMapToDelete := MapsDir + map;
6739 gTempDelete := True;
6740 end;
6741
6742 // Number of players:
6743 s := Find_Param_Value(pars, '-pl');
6744 if (s = '') then
6745 n := 1
6746 else
6747 n := StrToIntDef(s, 1);
6748
6749 // Start:
6750 s := Find_Param_Value(pars, '-port');
6751 if (s = '') or not TryStrToInt(s, Port) then
6752 g_Game_StartCustom(map, GMode, LimT, LimS, Lives, Opt, n)
6753 else
6754 g_Game_StartServer(map, GMode, LimT, LimS, Lives, Opt, n, 0, Port);
6755 end;
6756
6757 // Execute script when game loads:
6758 s := Find_Param_Value(pars, '-exec');
6759 if s <> '' then
6760 begin
6761 if Pos(':\', s) = 0 then
6762 s := GameDir + '/' + s;
6763
6764 {$I-}
6765 AssignFile(F, s);
6766 Reset(F);
6767 if IOResult <> 0 then
6768 begin
6769 e_WriteLog(Format(_lc[I_SIMPLE_ERROR], ['Failed to read file: ' + s]), MSG_WARNING);
6770 g_Console_Add(Format(_lc[I_CONSOLE_ERROR_READ], [s]));
6771 CloseFile(F);
6772 Exit;
6773 end;
6774 e_WriteLog('Executing script: ' + s, MSG_NOTIFY);
6775 g_Console_Add(Format(_lc[I_CONSOLE_EXEC], [s]));
6776
6777 while not EOF(F) do
6778 begin
6779 ReadLn(F, s);
6780 if IOResult <> 0 then
6781 begin
6782 e_WriteLog(Format(_lc[I_SIMPLE_ERROR], ['Failed to read file: ' + s]), MSG_WARNING);
6783 g_Console_Add(Format(_lc[I_CONSOLE_ERROR_READ], [s]));
6784 CloseFile(F);
6785 Exit;
6786 end;
6787 if Pos('#', s) <> 1 then // script comment
6788 g_Console_Process(s, True);
6789 end;
6790
6791 CloseFile(F);
6792 {$I+}
6793 end;
6794
6795 SetLength(pars, 0);
6796 end;
6797
6798 end.