DEADSOFTWARE

more flamer tweaks
[d2df-sdl.git] / src / game / g_weapons.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 {$MODE DELPHI}
17 unit g_weapons;
19 interface
21 uses
22 g_textures, g_basic, e_graphics, g_phys, BinEditor;
24 const
25 HIT_SOME = 0;
26 HIT_ROCKET = 1;
27 HIT_BFG = 2;
28 HIT_TRAP = 3;
29 HIT_FALL = 4;
30 HIT_WATER = 5;
31 HIT_ACID = 6;
32 HIT_ELECTRO = 7;
33 HIT_FLAME = 8;
34 HIT_SELF = 9;
35 HIT_DISCON = 10;
37 type
38 TShot = record
39 ShotType: Byte;
40 Target: Word;
41 SpawnerUID: Word;
42 Triggers: DWArray;
43 Obj: TObj;
44 Animation: TAnimation;
45 TextureID: DWORD;
46 Timeout: DWORD;
47 Stopped: Byte;
48 end;
50 var
51 Shots: array of TShot = nil;
52 LastShotID: Integer = 0;
54 procedure g_Weapon_LoadData();
55 procedure g_Weapon_FreeData();
56 procedure g_Weapon_Init();
57 procedure g_Weapon_Free();
58 function g_Weapon_Hit(obj: PObj; d: Integer; SpawnerUID: Word; t: Byte; HitCorpses: Boolean = True): Byte;
59 function g_Weapon_HitUID(UID: Word; d: Integer; SpawnerUID: Word; t: Byte): Boolean;
60 function g_Weapon_CreateShot(I: Integer; ShotType: Byte; Spawner, TargetUID: Word; X, Y, XV, YV: Integer): LongWord;
62 procedure g_Weapon_gun(x, y, xd, yd, v, dmg: Integer; SpawnerUID: Word; CheckTrigger: Boolean);
63 procedure g_Weapon_punch(x, y: Integer; d, SpawnerUID: Word);
64 function g_Weapon_chainsaw(x, y: Integer; d, SpawnerUID: Word): Integer;
65 procedure g_Weapon_rocket(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1; Silent: Boolean = False);
66 procedure g_Weapon_revf(x, y, xd, yd: Integer; SpawnerUID, TargetUID: Word; WID: Integer = -1; Silent: Boolean = False);
67 procedure g_Weapon_flame(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1; Silent: Boolean = False);
68 procedure g_Weapon_plasma(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1; Silent: Boolean = False);
69 procedure g_Weapon_ball1(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1; Silent: Boolean = False);
70 procedure g_Weapon_ball2(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1; Silent: Boolean = False);
71 procedure g_Weapon_ball7(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1; Silent: Boolean = False);
72 procedure g_Weapon_aplasma(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1; Silent: Boolean = False);
73 procedure g_Weapon_manfire(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1; Silent: Boolean = False);
74 procedure g_Weapon_bfgshot(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1; Silent: Boolean = False);
75 procedure g_Weapon_bfghit(x, y: Integer);
76 procedure g_Weapon_pistol(x, y, xd, yd: Integer; SpawnerUID: Word; Silent: Boolean = False);
77 procedure g_Weapon_mgun(x, y, xd, yd: Integer; SpawnerUID: Word; Silent: Boolean = False);
78 procedure g_Weapon_shotgun(x, y, xd, yd: Integer; SpawnerUID: Word; Silent: Boolean = False);
79 procedure g_Weapon_dshotgun(x, y, xd, yd: Integer; SpawnerUID: Word; Silent: Boolean = False);
81 function g_Weapon_Explode(X, Y: Integer; rad: Integer; SpawnerUID: Word): Boolean;
82 procedure g_Weapon_BFG9000(X, Y: Integer; SpawnerUID: Word);
83 procedure g_Weapon_Update();
84 procedure g_Weapon_Draw();
85 function g_Weapon_Danger(UID: Word; X, Y: Integer; Width, Height: Word; Time: Byte): Boolean;
86 procedure g_Weapon_DestroyShot(I: Integer; X, Y: Integer; Loud: Boolean = True);
88 procedure g_Weapon_SaveState(var Mem: TBinMemoryWriter);
89 procedure g_Weapon_LoadState(var Mem: TBinMemoryReader);
91 const
92 WEAPON_KASTET = 0;
93 WEAPON_SAW = 1;
94 WEAPON_PISTOL = 2;
95 WEAPON_SHOTGUN1 = 3;
96 WEAPON_SHOTGUN2 = 4;
97 WEAPON_CHAINGUN = 5;
98 WEAPON_ROCKETLAUNCHER = 6;
99 WEAPON_PLASMA = 7;
100 WEAPON_BFG = 8;
101 WEAPON_SUPERPULEMET = 9;
102 WEAPON_FLAMETHROWER = 10;
103 WEAPON_ZOMBY_PISTOL = 20;
104 WEAPON_IMP_FIRE = 21;
105 WEAPON_BSP_FIRE = 22;
106 WEAPON_CACO_FIRE = 23;
107 WEAPON_BARON_FIRE = 24;
108 WEAPON_MANCUB_FIRE = 25;
109 WEAPON_SKEL_FIRE = 26;
111 WP_FIRST = WEAPON_KASTET;
112 WP_LAST = WEAPON_FLAMETHROWER;
114 implementation
116 uses
117 Math, g_map, g_player, g_gfx, g_sound, g_main,
118 g_console, SysUtils, g_options, g_game,
119 g_triggers, MAPDEF, e_log, g_monsters, g_saveload,
120 g_language, g_netmsg;
122 type
123 TWaterPanel = record
124 X, Y: Integer;
125 Width, Height: Word;
126 Active: Boolean;
127 end;
129 const
130 SHOT_ROCKETLAUNCHER_WIDTH = 14;
131 SHOT_ROCKETLAUNCHER_HEIGHT = 14;
133 SHOT_SKELFIRE_WIDTH = 14;
134 SHOT_SKELFIRE_HEIGHT = 14;
136 SHOT_PLASMA_WIDTH = 16;
137 SHOT_PLASMA_HEIGHT = 16;
139 SHOT_BFG_WIDTH = 32;
140 SHOT_BFG_HEIGHT = 32;
141 SHOT_BFG_DAMAGE = 100;
142 SHOT_BFG_RADIUS = 256;
144 SHOT_FLAME_WIDTH = 4;
145 SHOT_FLAME_HEIGHT = 4;
146 SHOT_FLAME_LIFETIME = 180;
148 SHOT_SIGNATURE = $544F4853; // 'SHOT'
150 var
151 WaterMap: array of array of DWORD = nil;
153 function FindShot(): DWORD;
154 var
155 i: Integer;
156 begin
157 if Shots <> nil then
158 for i := 0 to High(Shots) do
159 if Shots[i].ShotType = 0 then
160 begin
161 Result := i;
162 LastShotID := Result;
163 Exit;
164 end;
166 if Shots = nil then
167 begin
168 SetLength(Shots, 128);
169 Result := 0;
170 end
171 else
172 begin
173 Result := High(Shots) + 1;
174 SetLength(Shots, Length(Shots) + 128);
175 end;
176 LastShotID := Result;
177 end;
179 procedure CreateWaterMap();
180 var
181 WaterArray: Array of TWaterPanel;
182 a, b, c, m: Integer;
183 ok: Boolean;
184 begin
185 if gWater = nil then
186 Exit;
188 SetLength(WaterArray, Length(gWater));
190 for a := 0 to High(gWater) do
191 begin
192 WaterArray[a].X := gWater[a].X;
193 WaterArray[a].Y := gWater[a].Y;
194 WaterArray[a].Width := gWater[a].Width;
195 WaterArray[a].Height := gWater[a].Height;
196 WaterArray[a].Active := True;
197 end;
199 g_Game_SetLoadingText(_lc[I_LOAD_WATER_MAP], High(WaterArray), False);
201 for a := 0 to High(WaterArray) do
202 if WaterArray[a].Active then
203 begin
204 WaterArray[a].Active := False;
205 m := Length(WaterMap);
206 SetLength(WaterMap, m+1);
207 SetLength(WaterMap[m], 1);
208 WaterMap[m][0] := a;
209 ok := True;
211 while ok do
212 begin
213 ok := False;
214 for b := 0 to High(WaterArray) do
215 if WaterArray[b].Active then
216 for c := 0 to High(WaterMap[m]) do
217 if g_CollideAround(WaterArray[b].X,
218 WaterArray[b].Y,
219 WaterArray[b].Width,
220 WaterArray[b].Height,
221 WaterArray[WaterMap[m][c]].X,
222 WaterArray[WaterMap[m][c]].Y,
223 WaterArray[WaterMap[m][c]].Width,
224 WaterArray[WaterMap[m][c]].Height) then
225 begin
226 WaterArray[b].Active := False;
227 SetLength(WaterMap[m],
228 Length(WaterMap[m])+1);
229 WaterMap[m][High(WaterMap[m])] := b;
230 ok := True;
231 Break;
232 end;
233 end;
235 g_Game_StepLoading();
236 end;
238 WaterArray := nil;
239 end;
241 procedure CheckTrap(ID: DWORD; dm: Integer; t: Byte);
242 var
243 a, b, c, d, i1, i2: Integer;
244 pl, mn: WArray;
245 begin
246 if (gWater = nil) or (WaterMap = nil) then Exit;
248 i1 := -1;
249 i2 := -1;
251 SetLength(pl, 1024);
252 SetLength(mn, 1024);
253 for d := 0 to 1023 do pl[d] := $FFFF;
254 for d := 0 to 1023 do mn[d] := $FFFF;
256 for a := 0 to High(WaterMap) do
257 for b := 0 to High(WaterMap[a]) do
258 begin
259 if not g_Obj_Collide(gWater[WaterMap[a][b]].X, gWater[WaterMap[a][b]].Y,
260 gWater[WaterMap[a][b]].Width, gWater[WaterMap[a][b]].Height,
261 @Shots[ID].Obj) then Continue;
263 for c := 0 to High(WaterMap[a]) do
264 begin
265 if gPlayers <> nil then
266 begin
267 for d := 0 to High(gPlayers) do
268 if (gPlayers[d] <> nil) and (gPlayers[d].Live) then
269 if gPlayers[d].Collide(gWater[WaterMap[a][c]]) then
270 if not InWArray(d, pl) then
271 if i1 < 1023 then
272 begin
273 i1 := i1+1;
274 pl[i1] := d;
275 end;
276 end;
278 if gMonsters <> nil then
279 begin
280 for d := 0 to High(gMonsters) do
281 if (gMonsters[d] <> nil) and (gMonsters[d].Live) then
282 if gMonsters[d].Collide(gWater[WaterMap[a][c]]) then
283 if not InWArray(d, mn) then
284 if i2 < 1023 then
285 begin
286 i2 := i2+1;
287 mn[i2] := d;
288 end;
289 end;
290 end;
292 if i1 <> -1 then
293 for d := 0 to i1 do
294 gPlayers[pl[d]].Damage(dm, Shots[ID].SpawnerUID, 0, 0, t);
296 if i2 <> -1 then
297 for d := 0 to i2 do
298 gMonsters[mn[d]].Damage(dm, 0, 0, Shots[ID].SpawnerUID, t);
299 end;
301 pl := nil;
302 mn := nil;
303 end;
305 function HitMonster(m: TMonster; d: Integer; vx, vy: Integer; SpawnerUID: Word; t: Byte): Boolean;
306 var
307 tt, mt: Byte;
308 mon: TMonster;
309 begin
310 Result := False;
312 tt := g_GetUIDType(SpawnerUID);
313 if tt = UID_MONSTER then
314 begin
315 mon := g_Monsters_Get(SpawnerUID);
316 if mon <> nil then
317 mt := g_Monsters_Get(SpawnerUID).MonsterType
318 else
319 mt := 0;
320 end
321 else
322 mt := 0;
324 if m = nil then Exit;
325 if m.UID = SpawnerUID then
326 begin
327 // Ñàì ñåáÿ ìîæåò ðàíèòü òîëüêî ðàêåòîé è òîêîì:
328 if (t <> HIT_ROCKET) and (t <> HIT_ELECTRO) then
329 Exit;
330 // Êèáåð äåìîí è áî÷êà âîîáùå íå ìîãóò ñåáÿ ðàíèòü:
331 if (m.MonsterType = MONSTER_CYBER) or
332 (m.MonsterType = MONSTER_BARREL) then
333 begin
334 Result := True;
335 Exit;
336 end;
337 end;
339 if tt = UID_MONSTER then
340 begin
341 // Lost_Soul íå ìîæåò ðàíèòü Pain_Elemental'à:
342 if (mt = MONSTER_SOUL) and (m.MonsterType = MONSTER_PAIN) then
343 Exit;
345 // Îáà ìîíñòðà îäíîãî âèäà:
346 if mt = m.MonsterType then
347 case mt of
348 MONSTER_IMP, MONSTER_DEMON, MONSTER_BARON, MONSTER_KNIGHT, MONSTER_CACO,
349 MONSTER_SOUL, MONSTER_MANCUB, MONSTER_SKEL, MONSTER_FISH:
350 Exit; // Ýòè íå áüþò ñâîèõ
351 end;
352 end;
354 if g_Game_IsServer then
355 begin
356 if (t <> HIT_FLAME) or (m.FFireTime = 0) or (vx <> 0) or (vy <> 0) then
357 Result := m.Damage(d, vx, vy, SpawnerUID, t)
358 else
359 Result := True;
360 if t = HIT_FLAME then
361 m.CatchFire(SpawnerUID);
362 end
363 else
364 Result := True;
365 end;
367 function HitPlayer(p: TPlayer; d: Integer; vx, vy: Integer; SpawnerUID: Word; t: Byte): Boolean;
368 begin
369 Result := False;
371 // Ñàì ñåáÿ ìîæåò ðàíèòü òîëüêî ðàêåòîé è òîêîì:
372 if (p.UID = SpawnerUID) and (t <> HIT_ROCKET) and (t <> HIT_ELECTRO) then
373 Exit;
375 if g_Game_IsServer then
376 begin
377 if (t <> HIT_FLAME) or (p.FFireTime = 0) or (vx <> 0) or (vy <> 0) then
378 p.Damage(d, SpawnerUID, vx, vy, t);
379 if (t = HIT_FLAME) then
380 p.CatchFire(SpawnerUID);
381 end;
383 Result := True;
384 end;
386 function GunHit(X, Y: Integer; vx, vy: Integer; dmg: Integer;
387 SpawnerUID: Word; AllowPush: Boolean): Byte;
388 var
389 i, h: Integer;
390 begin
391 Result := 0;
393 h := High(gPlayers);
395 if h <> -1 then
396 for i := 0 to h do
397 if (gPlayers[i] <> nil) and gPlayers[i].Live and gPlayers[i].Collide(X, Y) then
398 if HitPlayer(gPlayers[i], dmg, vx*10, vy*10-3, SpawnerUID, HIT_SOME) then
399 begin
400 if AllowPush then gPlayers[i].Push(vx, vy);
401 Result := 1;
402 end;
404 if Result <> 0 then Exit;
406 h := High(gMonsters);
408 if h <> -1 then
409 for i := 0 to h do
410 if (gMonsters[i] <> nil) and gMonsters[i].Live and gMonsters[i].Collide(X, Y) then
411 if HitMonster(gMonsters[i], dmg, vx*10, vy*10-3, SpawnerUID, HIT_SOME) then
412 begin
413 if AllowPush then gMonsters[i].Push(vx, vy);
414 Result := 2;
415 Exit;
416 end;
417 end;
419 procedure g_Weapon_BFG9000(X, Y: Integer; SpawnerUID: Word);
420 var
421 i, h: Integer;
422 st: Byte;
423 pl: TPlayer;
424 b: Boolean;
425 begin
426 //g_Sound_PlayEx('SOUND_WEAPON_EXPLODEBFG', 255);
428 h := High(gCorpses);
430 if gAdvCorpses and (h <> -1) then
431 for i := 0 to h do
432 if (gCorpses[i] <> nil) and (gCorpses[i].State <> CORPSE_STATE_REMOVEME) then
433 with gCorpses[i] do
434 if (g_PatchLength(X, Y, Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2),
435 Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)) <= SHOT_BFG_RADIUS) and
436 g_TraceVector(X, Y, Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2),
437 Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)) then
438 begin
439 Damage(50, 0, 0);
440 g_Weapon_BFGHit(Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2),
441 Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2));
442 end;
444 st := TEAM_NONE;
445 pl := g_Player_Get(SpawnerUID);
446 if pl <> nil then
447 st := pl.Team;
449 h := High(gPlayers);
451 if h <> -1 then
452 for i := 0 to h do
453 if (gPlayers[i] <> nil) and (gPlayers[i].Live) and (gPlayers[i].UID <> SpawnerUID) then
454 with gPlayers[i] do
455 if (g_PatchLength(X, Y, GameX+PLAYER_RECT.X+(PLAYER_RECT.Width div 2),
456 GameY+PLAYER_RECT.Y+(PLAYER_RECT.Height div 2)) <= SHOT_BFG_RADIUS) and
457 g_TraceVector(X, Y, GameX+PLAYER_RECT.X+(PLAYER_RECT.Width div 2),
458 GameY+PLAYER_RECT.Y+(PLAYER_RECT.Height div 2)) then
459 begin
460 if (st = TEAM_NONE) or (st <> gPlayers[i].Team) then
461 b := HitPlayer(gPlayers[i], 50, 0, 0, SpawnerUID, HIT_SOME)
462 else
463 b := HitPlayer(gPlayers[i], 25, 0, 0, SpawnerUID, HIT_SOME);
464 if b then
465 gPlayers[i].BFGHit();
466 end;
468 h := High(gMonsters);
470 if h <> -1 then
471 for i := 0 to h do
472 if (gMonsters[i] <> nil) and (gMonsters[i].Live) and (gMonsters[i].UID <> SpawnerUID) then
473 with gMonsters[i] do
474 if (g_PatchLength(X, Y, Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2),
475 Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)) <= SHOT_BFG_RADIUS) and
476 g_TraceVector(X, Y, Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2),
477 Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)) then
478 if HitMonster(gMonsters[i], 50, 0, 0, SpawnerUID, HIT_SOME) then gMonsters[i].BFGHit();
479 end;
481 function g_Weapon_CreateShot(I: Integer; ShotType: Byte; Spawner, TargetUID: Word; X, Y, XV, YV: Integer): LongWord;
482 var
483 find_id, FramesID: DWORD;
484 begin
485 if I < 0 then
486 find_id := FindShot()
487 else
488 begin
489 find_id := I;
490 if Integer(find_id) >= High(Shots) then
491 SetLength(Shots, find_id + 64)
492 end;
494 case ShotType of
495 WEAPON_ROCKETLAUNCHER:
496 begin
497 with Shots[find_id] do
498 begin
499 g_Obj_Init(@Obj);
501 Obj.Rect.Width := SHOT_ROCKETLAUNCHER_WIDTH;
502 Obj.Rect.Height := SHOT_ROCKETLAUNCHER_HEIGHT;
504 Animation := nil;
505 Triggers := nil;
506 ShotType := WEAPON_ROCKETLAUNCHER;
507 g_Texture_Get('TEXTURE_WEAPON_ROCKET', TextureID);
508 end;
509 end;
511 WEAPON_PLASMA:
512 begin
513 with Shots[find_id] do
514 begin
515 g_Obj_Init(@Obj);
517 Obj.Rect.Width := SHOT_PLASMA_WIDTH;
518 Obj.Rect.Height := SHOT_PLASMA_HEIGHT;
520 Triggers := nil;
521 ShotType := WEAPON_PLASMA;
522 g_Frames_Get(FramesID, 'FRAMES_WEAPON_PLASMA');
523 Animation := TAnimation.Create(FramesID, True, 5);
524 end;
525 end;
527 WEAPON_BFG:
528 begin
529 with Shots[find_id] do
530 begin
531 g_Obj_Init(@Obj);
533 Obj.Rect.Width := SHOT_BFG_WIDTH;
534 Obj.Rect.Height := SHOT_BFG_HEIGHT;
536 Triggers := nil;
537 ShotType := WEAPON_BFG;
538 g_Frames_Get(FramesID, 'FRAMES_WEAPON_BFG');
539 Animation := TAnimation.Create(FramesID, True, 6);
540 end;
541 end;
543 WEAPON_FLAMETHROWER:
544 begin
545 with Shots[find_id] do
546 begin
547 g_Obj_Init(@Obj);
549 Obj.Rect.Width := SHOT_FLAME_WIDTH;
550 Obj.Rect.Height := SHOT_FLAME_HEIGHT;
552 Triggers := nil;
553 ShotType := WEAPON_FLAMETHROWER;
554 Animation := nil;
555 TextureID := 0;
556 Stopped := 0;
557 end;
558 end;
560 WEAPON_IMP_FIRE:
561 begin
562 with Shots[find_id] do
563 begin
564 g_Obj_Init(@Obj);
566 Obj.Rect.Width := 16;
567 Obj.Rect.Height := 16;
569 Triggers := nil;
570 ShotType := WEAPON_IMP_FIRE;
571 g_Frames_Get(FramesID, 'FRAMES_WEAPON_IMPFIRE');
572 Animation := TAnimation.Create(FramesID, True, 4);
573 end;
574 end;
576 WEAPON_CACO_FIRE:
577 begin
578 with Shots[find_id] do
579 begin
580 g_Obj_Init(@Obj);
582 Obj.Rect.Width := 16;
583 Obj.Rect.Height := 16;
585 Triggers := nil;
586 ShotType := WEAPON_CACO_FIRE;
587 g_Frames_Get(FramesID, 'FRAMES_WEAPON_CACOFIRE');
588 Animation := TAnimation.Create(FramesID, True, 4);
589 end;
590 end;
592 WEAPON_MANCUB_FIRE:
593 begin
594 with Shots[find_id] do
595 begin
596 g_Obj_Init(@Obj);
598 Obj.Rect.Width := 32;
599 Obj.Rect.Height := 32;
601 Triggers := nil;
602 ShotType := WEAPON_MANCUB_FIRE;
603 g_Frames_Get(FramesID, 'FRAMES_WEAPON_MANCUBFIRE');
604 Animation := TAnimation.Create(FramesID, True, 4);
605 end;
606 end;
608 WEAPON_BARON_FIRE:
609 begin
610 with Shots[find_id] do
611 begin
612 g_Obj_Init(@Obj);
614 Obj.Rect.Width := 32;
615 Obj.Rect.Height := 16;
617 Triggers := nil;
618 ShotType := WEAPON_BARON_FIRE;
619 g_Frames_Get(FramesID, 'FRAMES_WEAPON_BARONFIRE');
620 Animation := TAnimation.Create(FramesID, True, 4);
621 end;
622 end;
624 WEAPON_BSP_FIRE:
625 begin
626 with Shots[find_id] do
627 begin
628 g_Obj_Init(@Obj);
630 Obj.Rect.Width := 16;
631 Obj.Rect.Height := 16;
633 Triggers := nil;
634 ShotType := WEAPON_BSP_FIRE;
635 g_Frames_Get(FramesID, 'FRAMES_WEAPON_BSPFIRE');
636 Animation := TAnimation.Create(FramesID, True, 4);
637 end;
638 end;
640 WEAPON_SKEL_FIRE:
641 begin
642 with Shots[find_id] do
643 begin
644 g_Obj_Init(@Obj);
646 Obj.Rect.Width := SHOT_SKELFIRE_WIDTH;
647 Obj.Rect.Height := SHOT_SKELFIRE_HEIGHT;
649 Triggers := nil;
650 ShotType := WEAPON_SKEL_FIRE;
651 target := TargetUID;
652 g_Frames_Get(FramesID, 'FRAMES_WEAPON_SKELFIRE');
653 Animation := TAnimation.Create(FramesID, True, 5);
654 end;
655 end;
656 end;
658 Shots[find_id].Obj.X := X;
659 Shots[find_id].Obj.Y := Y;
660 Shots[find_id].Obj.Vel.X := XV;
661 Shots[find_id].Obj.Vel.Y := YV;
662 Shots[find_id].Obj.Accel.X := 0;
663 Shots[find_id].Obj.Accel.Y := 0;
664 Shots[find_id].SpawnerUID := Spawner;
665 Result := find_id;
666 end;
668 procedure throw(i, x, y, xd, yd, s: Integer);
669 var
670 a: Integer;
671 begin
672 yd := yd - y;
673 xd := xd - x;
675 a := Max(Abs(xd), Abs(yd));
676 if a = 0 then
677 a := 1;
679 Shots[i].Obj.X := x;
680 Shots[i].Obj.Y := y;
681 Shots[i].Obj.Vel.X := (xd*s) div a;
682 Shots[i].Obj.Vel.Y := (yd*s) div a;
683 Shots[i].Obj.Accel.X := 0;
684 Shots[i].Obj.Accel.Y := 0;
685 if Shots[i].ShotType in [WEAPON_ROCKETLAUNCHER, WEAPON_BFG] then
686 Shots[i].Timeout := 900 // ~25 sec
687 else
688 begin
689 if Shots[i].ShotType = WEAPON_FLAMETHROWER then
690 Shots[i].Timeout := SHOT_FLAME_LIFETIME
691 else
692 Shots[i].Timeout := 550; // ~15 sec
693 end;
694 end;
696 function g_Weapon_Hit(obj: PObj; d: Integer; SpawnerUID: Word; t: Byte; HitCorpses: Boolean = True): Byte;
697 var
698 i, h: Integer;
700 function PlayerHit(Team: Byte = 0): Boolean;
701 var
702 i: Integer;
703 ChkTeam: Boolean;
704 p: TPlayer;
705 begin
706 Result := False;
707 h := High(gPlayers);
709 if h <> -1 then
710 for i := 0 to h do
711 if (gPlayers[i] <> nil) and gPlayers[i].Live and g_Obj_Collide(obj, @gPlayers[i].Obj) then
712 begin
713 ChkTeam := True;
714 if (Team > 0) and (g_GetUIDType(SpawnerUID) = UID_PLAYER) then
715 begin
716 p := g_Player_Get(SpawnerUID);
717 if p <> nil then
718 ChkTeam := (p.Team = gPlayers[i].Team) xor (Team = 2);
719 end;
720 if ChkTeam then
721 if HitPlayer(gPlayers[i], d, obj^.Vel.X, obj^.Vel.Y, SpawnerUID, t) then
722 begin
723 gPlayers[i].Push((obj^.Vel.X+obj^.Accel.X)*IfThen(t = HIT_BFG, 8, 1) div 4,
724 (obj^.Vel.Y+obj^.Accel.Y)*IfThen(t = HIT_BFG, 8, 1) div 4);
725 if t = HIT_BFG then
726 g_Game_DelayEvent(DE_BFGHIT, 1000, SpawnerUID);
727 Result := True;
728 break;
729 end;
730 end;
731 end;
732 function MonsterHit(): Boolean;
733 var
734 i: Integer;
735 begin
736 Result := False;
737 h := High(gMonsters);
739 if h <> -1 then
740 for i := 0 to h do
741 if (gMonsters[i] <> nil) and gMonsters[i].Live and g_Obj_Collide(obj, @gMonsters[i].Obj) then
742 if HitMonster(gMonsters[i], d, obj^.Vel.X, obj^.Vel.Y, SpawnerUID, t) then
743 begin
744 gMonsters[i].Push((obj^.Vel.X+obj^.Accel.X)*IfThen(t = HIT_BFG, 8, 1) div 4,
745 (obj^.Vel.Y+obj^.Accel.Y)*IfThen(t = HIT_BFG, 8, 1) div 4);
746 Result := True;
747 break;
748 end;
749 end;
750 begin
751 Result := 0;
753 if HitCorpses then
754 begin
755 h := High(gCorpses);
757 if gAdvCorpses and (h <> -1) then
758 for i := 0 to h do
759 if (gCorpses[i] <> nil) and (gCorpses[i].State <> CORPSE_STATE_REMOVEME) and
760 g_Obj_Collide(obj, @gCorpses[i].Obj) then
761 begin
762 // Ðàñïèëèâàåì òðóï:
763 gCorpses[i].Damage(d, (obj^.Vel.X+obj^.Accel.X) div 4,
764 (obj^.Vel.Y+obj^.Accel.Y) div 4);
765 Result := 1;
766 end;
767 end;
769 case gGameSettings.GameMode of
770 // Êàìïàíèÿ:
771 GM_COOP, GM_SINGLE:
772 begin
773 // Ñíà÷àëà áü¸ì ìîíñòðîâ, åñëè åñòü, ïîòîì ïûòàåìñÿ áèòü èãðîêîâ
774 if MonsterHit() then
775 begin
776 Result := 2;
777 Exit;
778 end;
780 if PlayerHit() then
781 begin
782 Result := 1;
783 Exit;
784 end;
785 end;
787 // Äåçìàò÷:
788 GM_DM:
789 begin
790 // Ñíà÷àëà áü¸ì èãðîêîâ, åñëè åñòü, ïîòîì ïûòàåìñÿ áèòü ìîíñòðîâ
791 if PlayerHit() then
792 begin
793 Result := 1;
794 Exit;
795 end;
797 if MonsterHit() then
798 begin
799 Result := 2;
800 Exit;
801 end;
802 end;
804 // Êîìàíäíûå:
805 GM_TDM, GM_CTF:
806 begin
807 // Ñíà÷àëà áü¸ì èãðîêîâ êîìàíäû ñîïåðíèêà
808 if PlayerHit(2) then
809 begin
810 Result := 1;
811 Exit;
812 end;
814 // Ïîòîì ìîíñòðîâ
815 if MonsterHit() then
816 begin
817 Result := 2;
818 Exit;
819 end;
821 // È â êîíöå ñâîèõ èãðîêîâ
822 if PlayerHit(1) then
823 begin
824 Result := 1;
825 Exit;
826 end;
827 end;
829 end;
830 end;
832 function g_Weapon_HitUID(UID: Word; d: Integer; SpawnerUID: Word; t: Byte): Boolean;
833 begin
834 Result := False;
836 case g_GetUIDType(UID) of
837 UID_PLAYER: Result := HitPlayer(g_Player_Get(UID), d, 0, 0, SpawnerUID, t);
838 UID_MONSTER: Result := HitMonster(g_Monsters_Get(UID), d, 0, 0, SpawnerUID, t);
839 else Exit;
840 end;
841 end;
843 function g_Weapon_Explode(X, Y: Integer; rad: Integer; SpawnerUID: Word): Boolean;
844 var
845 i, h, r, dx, dy, m, mm: Integer;
846 _angle: SmallInt;
847 begin
848 Result := False;
850 g_Triggers_PressC(X, Y, rad, SpawnerUID, ACTIVATE_SHOT);
852 r := rad*rad;
854 h := High(gPlayers);
856 if h <> -1 then
857 for i := 0 to h do
858 if (gPlayers[i] <> nil) and gPlayers[i].Live then
859 with gPlayers[i] do
860 begin
861 dx := Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2)-X;
862 dy := Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)-Y;
864 if dx > 1000 then dx := 1000;
865 if dy > 1000 then dy := 1000;
867 if dx*dx+dy*dy < r then
868 begin
869 //m := PointToRect(X, Y, GameX+PLAYER_RECT.X, GameY+PLAYER_RECT.Y,
870 // PLAYER_RECT.Width, PLAYER_RECT.Height);
872 mm := Max(abs(dx), abs(dy));
873 if mm = 0 then mm := 1;
875 HitPlayer(gPlayers[i], (100*(rad-mm)) div rad, (dx*10) div mm, (dy*10) div mm, SpawnerUID, HIT_ROCKET);
876 gPlayers[i].Push((dx*7) div mm, (dy*7) div mm);
877 end;
878 end;
880 h := High(gMonsters);
882 if h <> -1 then
883 for i := 0 to h do
884 if gMonsters[i] <> nil then
885 with gMonsters[i] do
886 begin
887 dx := Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2)-X;
888 dy := Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)-Y;
890 if dx > 1000 then dx := 1000;
891 if dy > 1000 then dy := 1000;
893 if dx*dx+dy*dy < r then
894 begin
895 //m := PointToRect(X, Y, Obj.X+Obj.Rect.X, Obj.Y+Obj.Rect.Y,
896 // Obj.Rect.Width, Obj.Rect.Height);
898 mm := Max(abs(dx), abs(dy));
899 if mm = 0 then mm := 1;
901 if gMonsters[i].Live then
902 HitMonster(gMonsters[i], ((gMonsters[i].Obj.Rect.Width div 4)*10*(rad-mm)) div rad,
903 0, 0, SpawnerUID, HIT_ROCKET);
905 gMonsters[i].Push((dx*7) div mm, (dy*7) div mm);
906 end;
907 end;
909 h := High(gCorpses);
911 if gAdvCorpses and (h <> -1) then
912 for i := 0 to h do
913 if (gCorpses[i] <> nil) and (gCorpses[i].State <> CORPSE_STATE_REMOVEME) then
914 with gCorpses[i] do
915 begin
916 dx := Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2)-X;
917 dy := Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)-Y;
919 if dx > 1000 then dx := 1000;
920 if dy > 1000 then dy := 1000;
922 if dx*dx+dy*dy < r then
923 begin
924 m := PointToRect(X, Y, Obj.X+Obj.Rect.X, Obj.Y+Obj.Rect.Y,
925 Obj.Rect.Width, Obj.Rect.Height);
927 mm := Max(abs(dx), abs(dy));
928 if mm = 0 then mm := 1;
930 Damage(Round(100*(rad-m)/rad), (dx*10) div mm, (dy*10) div mm);
931 end;
932 end;
934 h := High(gGibs);
936 if gAdvGibs and (h <> -1) then
937 for i := 0 to h do
938 if gGibs[i].Live then
939 with gGibs[i] do
940 begin
941 dx := Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2)-X;
942 dy := Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)-Y;
944 if dx > 1000 then dx := 1000;
945 if dy > 1000 then dy := 1000;
947 if dx*dx+dy*dy < r then
948 begin
949 m := PointToRect(X, Y, Obj.X+Obj.Rect.X, Obj.Y+Obj.Rect.Y,
950 Obj.Rect.Width, Obj.Rect.Height);
951 _angle := GetAngle(Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2),
952 Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2), X, Y);
954 g_Obj_PushA(@Obj, Round(15*(rad-m)/rad), _angle);
955 end;
956 end;
957 end;
959 procedure g_Weapon_Init();
960 begin
961 CreateWaterMap();
962 end;
964 procedure g_Weapon_Free();
965 var
966 i: Integer;
967 begin
968 if Shots <> nil then
969 begin
970 for i := 0 to High(Shots) do
971 if Shots[i].ShotType <> 0 then
972 Shots[i].Animation.Free();
974 Shots := nil;
975 end;
977 WaterMap := nil;
978 end;
980 procedure g_Weapon_LoadData();
981 begin
982 e_WriteLog('Loading weapons data...', MSG_NOTIFY);
984 g_Sound_CreateWADEx('SOUND_WEAPON_HITPUNCH', GameWAD+':SOUNDS\HITPUNCH');
985 g_Sound_CreateWADEx('SOUND_WEAPON_MISSPUNCH', GameWAD+':SOUNDS\MISSPUNCH');
986 g_Sound_CreateWADEx('SOUND_WEAPON_HITBERSERK', GameWAD+':SOUNDS\HITBERSERK');
987 g_Sound_CreateWADEx('SOUND_WEAPON_MISSBERSERK', GameWAD+':SOUNDS\MISSBERSERK');
988 g_Sound_CreateWADEx('SOUND_WEAPON_SELECTSAW', GameWAD+':SOUNDS\SELECTSAW');
989 g_Sound_CreateWADEx('SOUND_WEAPON_IDLESAW', GameWAD+':SOUNDS\IDLESAW');
990 g_Sound_CreateWADEx('SOUND_WEAPON_HITSAW', GameWAD+':SOUNDS\HITSAW');
991 g_Sound_CreateWADEx('SOUND_WEAPON_FIRESHOTGUN2', GameWAD+':SOUNDS\FIRESHOTGUN2');
992 g_Sound_CreateWADEx('SOUND_WEAPON_FIRESHOTGUN', GameWAD+':SOUNDS\FIRESHOTGUN');
993 g_Sound_CreateWADEx('SOUND_WEAPON_FIRESAW', GameWAD+':SOUNDS\FIRESAW');
994 g_Sound_CreateWADEx('SOUND_WEAPON_FIREROCKET', GameWAD+':SOUNDS\FIREROCKET');
995 g_Sound_CreateWADEx('SOUND_WEAPON_FIREPLASMA', GameWAD+':SOUNDS\FIREPLASMA');
996 g_Sound_CreateWADEx('SOUND_WEAPON_FIREPISTOL', GameWAD+':SOUNDS\FIREPISTOL');
997 g_Sound_CreateWADEx('SOUND_WEAPON_FIRECGUN', GameWAD+':SOUNDS\FIRECGUN');
998 g_Sound_CreateWADEx('SOUND_WEAPON_FIREBFG', GameWAD+':SOUNDS\FIREBFG');
999 g_Sound_CreateWADEx('SOUND_FIRE', GameWAD+':SOUNDS\FIRE');
1000 g_Sound_CreateWADEx('SOUND_WEAPON_STARTFIREBFG', GameWAD+':SOUNDS\STARTFIREBFG');
1001 g_Sound_CreateWADEx('SOUND_WEAPON_EXPLODEROCKET', GameWAD+':SOUNDS\EXPLODEROCKET');
1002 g_Sound_CreateWADEx('SOUND_WEAPON_EXPLODEBFG', GameWAD+':SOUNDS\EXPLODEBFG');
1003 g_Sound_CreateWADEx('SOUND_WEAPON_BFGWATER', GameWAD+':SOUNDS\BFGWATER');
1004 g_Sound_CreateWADEx('SOUND_WEAPON_EXPLODEPLASMA', GameWAD+':SOUNDS\EXPLODEPLASMA');
1005 g_Sound_CreateWADEx('SOUND_WEAPON_PLASMAWATER', GameWAD+':SOUNDS\PLASMAWATER');
1006 g_Sound_CreateWADEx('SOUND_WEAPON_FIREBALL', GameWAD+':SOUNDS\FIREBALL');
1007 g_Sound_CreateWADEx('SOUND_WEAPON_EXPLODEBALL', GameWAD+':SOUNDS\EXPLODEBALL');
1008 g_Sound_CreateWADEx('SOUND_WEAPON_FIREREV', GameWAD+':SOUNDS\FIREREV');
1009 g_Sound_CreateWADEx('SOUND_PLAYER_JETFLY', GameWAD+':SOUNDS\WORKJETPACK');
1010 g_Sound_CreateWADEx('SOUND_PLAYER_JETON', GameWAD+':SOUNDS\STARTJETPACK');
1011 g_Sound_CreateWADEx('SOUND_PLAYER_JETOFF', GameWAD+':SOUNDS\STOPJETPACK');
1012 g_Sound_CreateWADEx('SOUND_PLAYER_CASING1', GameWAD+':SOUNDS\CASING1');
1013 g_Sound_CreateWADEx('SOUND_PLAYER_CASING2', GameWAD+':SOUNDS\CASING2');
1014 g_Sound_CreateWADEx('SOUND_PLAYER_SHELL1', GameWAD+':SOUNDS\SHELL1');
1015 g_Sound_CreateWADEx('SOUND_PLAYER_SHELL2', GameWAD+':SOUNDS\SHELL2');
1017 g_Texture_CreateWADEx('TEXTURE_WEAPON_ROCKET', GameWAD+':TEXTURES\BROCKET');
1018 g_Frames_CreateWAD(nil, 'FRAMES_WEAPON_SKELFIRE', GameWAD+':TEXTURES\BSKELFIRE', 64, 16, 2);
1019 g_Frames_CreateWAD(nil, 'FRAMES_WEAPON_BFG', GameWAD+':TEXTURES\BBFG', 64, 64, 2);
1020 g_Frames_CreateWAD(nil, 'FRAMES_WEAPON_PLASMA', GameWAD+':TEXTURES\BPLASMA', 16, 16, 2);
1021 g_Frames_CreateWAD(nil, 'FRAMES_WEAPON_IMPFIRE', GameWAD+':TEXTURES\BIMPFIRE', 16, 16, 2);
1022 g_Frames_CreateWAD(nil, 'FRAMES_WEAPON_BSPFIRE', GameWAD+':TEXTURES\BBSPFIRE', 16, 16, 2);
1023 g_Frames_CreateWAD(nil, 'FRAMES_WEAPON_CACOFIRE', GameWAD+':TEXTURES\BCACOFIRE', 16, 16, 2);
1024 g_Frames_CreateWAD(nil, 'FRAMES_WEAPON_BARONFIRE', GameWAD+':TEXTURES\BBARONFIRE', 64, 16, 2);
1025 g_Frames_CreateWAD(nil, 'FRAMES_WEAPON_MANCUBFIRE', GameWAD+':TEXTURES\BMANCUBFIRE', 64, 32, 2);
1026 g_Frames_CreateWAD(nil, 'FRAMES_EXPLODE_ROCKET', GameWAD+':TEXTURES\EROCKET', 128, 128, 6);
1027 g_Frames_CreateWAD(nil, 'FRAMES_EXPLODE_SKELFIRE', GameWAD+':TEXTURES\ESKELFIRE', 64, 64, 3);
1028 g_Frames_CreateWAD(nil, 'FRAMES_EXPLODE_BFG', GameWAD+':TEXTURES\EBFG', 128, 128, 6);
1029 g_Frames_CreateWAD(nil, 'FRAMES_EXPLODE_IMPFIRE', GameWAD+':TEXTURES\EIMPFIRE', 64, 64, 3);
1030 g_Frames_CreateWAD(nil, 'FRAMES_BFGHIT', GameWAD+':TEXTURES\BFGHIT', 64, 64, 4);
1031 g_Frames_CreateWAD(nil, 'FRAMES_FIRE', GameWAD+':TEXTURES\FIRE', 64, 128, 8);
1032 g_Frames_CreateWAD(nil, 'FRAMES_FLAME', GameWAD+':TEXTURES\FLAME', 32, 32, 11);
1033 g_Frames_CreateWAD(nil, 'FRAMES_EXPLODE_PLASMA', GameWAD+':TEXTURES\EPLASMA', 32, 32, 4, True);
1034 g_Frames_CreateWAD(nil, 'FRAMES_EXPLODE_BSPFIRE', GameWAD+':TEXTURES\EBSPFIRE', 32, 32, 5);
1035 g_Frames_CreateWAD(nil, 'FRAMES_EXPLODE_CACOFIRE', GameWAD+':TEXTURES\ECACOFIRE', 64, 64, 3);
1036 g_Frames_CreateWAD(nil, 'FRAMES_EXPLODE_BARONFIRE', GameWAD+':TEXTURES\EBARONFIRE', 64, 64, 3);
1037 g_Frames_CreateWAD(nil, 'FRAMES_SMOKE', GameWAD+':TEXTURES\SMOKE', 32, 32, 10, False);
1039 g_Texture_CreateWADEx('TEXTURE_SHELL_BULLET', GameWAD+':TEXTURES\EBULLET');
1040 g_Texture_CreateWADEx('TEXTURE_SHELL_SHELL', GameWAD+':TEXTURES\ESHELL');
1041 end;
1043 procedure g_Weapon_FreeData();
1044 begin
1045 e_WriteLog('Releasing weapons data...', MSG_NOTIFY);
1047 g_Sound_Delete('SOUND_WEAPON_HITPUNCH');
1048 g_Sound_Delete('SOUND_WEAPON_MISSPUNCH');
1049 g_Sound_Delete('SOUND_WEAPON_HITBERSERK');
1050 g_Sound_Delete('SOUND_WEAPON_MISSBERSERK');
1051 g_Sound_Delete('SOUND_WEAPON_SELECTSAW');
1052 g_Sound_Delete('SOUND_WEAPON_IDLESAW');
1053 g_Sound_Delete('SOUND_WEAPON_HITSAW');
1054 g_Sound_Delete('SOUND_WEAPON_FIRESHOTGUN2');
1055 g_Sound_Delete('SOUND_WEAPON_FIRESHOTGUN');
1056 g_Sound_Delete('SOUND_WEAPON_FIRESAW');
1057 g_Sound_Delete('SOUND_WEAPON_FIREROCKET');
1058 g_Sound_Delete('SOUND_WEAPON_FIREPLASMA');
1059 g_Sound_Delete('SOUND_WEAPON_FIREPISTOL');
1060 g_Sound_Delete('SOUND_WEAPON_FIRECGUN');
1061 g_Sound_Delete('SOUND_WEAPON_FIREBFG');
1062 g_Sound_Delete('SOUND_FIRE');
1063 g_Sound_Delete('SOUND_WEAPON_STARTFIREBFG');
1064 g_Sound_Delete('SOUND_WEAPON_EXPLODEROCKET');
1065 g_Sound_Delete('SOUND_WEAPON_EXPLODEBFG');
1066 g_Sound_Delete('SOUND_WEAPON_BFGWATER');
1067 g_Sound_Delete('SOUND_WEAPON_EXPLODEPLASMA');
1068 g_Sound_Delete('SOUND_WEAPON_PLASMAWATER');
1069 g_Sound_Delete('SOUND_WEAPON_FIREBALL');
1070 g_Sound_Delete('SOUND_WEAPON_EXPLODEBALL');
1071 g_Sound_Delete('SOUND_WEAPON_FIREREV');
1072 g_Sound_Delete('SOUND_PLAYER_JETFLY');
1073 g_Sound_Delete('SOUND_PLAYER_JETON');
1074 g_Sound_Delete('SOUND_PLAYER_JETOFF');
1075 g_Sound_Delete('SOUND_PLAYER_CASING1');
1076 g_Sound_Delete('SOUND_PLAYER_CASING2');
1077 g_Sound_Delete('SOUND_PLAYER_SHELL1');
1078 g_Sound_Delete('SOUND_PLAYER_SHELL2');
1080 g_Texture_Delete('TEXTURE_WEAPON_ROCKET');
1081 g_Frames_DeleteByName('FRAMES_WEAPON_BFG');
1082 g_Frames_DeleteByName('FRAMES_WEAPON_PLASMA');
1083 g_Frames_DeleteByName('FRAMES_WEAPON_IMPFIRE');
1084 g_Frames_DeleteByName('FRAMES_WEAPON_BSPFIRE');
1085 g_Frames_DeleteByName('FRAMES_WEAPON_CACOFIRE');
1086 g_Frames_DeleteByName('FRAMES_WEAPON_MANCUBFIRE');
1087 g_Frames_DeleteByName('FRAMES_EXPLODE_ROCKET');
1088 g_Frames_DeleteByName('FRAMES_EXPLODE_BFG');
1089 g_Frames_DeleteByName('FRAMES_EXPLODE_IMPFIRE');
1090 g_Frames_DeleteByName('FRAMES_BFGHIT');
1091 g_Frames_DeleteByName('FRAMES_FIRE');
1092 g_Frames_DeleteByName('FRAMES_EXPLODE_PLASMA');
1093 g_Frames_DeleteByName('FRAMES_EXPLODE_BSPFIRE');
1094 g_Frames_DeleteByName('FRAMES_EXPLODE_CACOFIRE');
1095 g_Frames_DeleteByName('FRAMES_SMOKE');
1096 g_Frames_DeleteByName('FRAMES_WEAPON_BARONFIRE');
1097 g_Frames_DeleteByName('FRAMES_EXPLODE_BARONFIRE');
1098 end;
1100 procedure g_Weapon_gun(x, y, xd, yd, v, dmg: Integer; SpawnerUID: Word; CheckTrigger: Boolean);
1101 var
1102 a: Integer;
1103 x2, y2: Integer;
1104 dx, dy: Integer;
1105 xe, ye: Integer;
1106 xi, yi: Integer;
1107 s, c: Extended;
1108 //vx, vy: Integer;
1109 xx, yy, d: Integer;
1111 i: Integer;
1112 t1, _collide: Boolean;
1113 w, h: Word;
1114 begin
1115 a := GetAngle(x, y, xd, yd)+180;
1117 SinCos(DegToRad(-a), s, c);
1119 if Abs(s) < 0.01 then s := 0;
1120 if Abs(c) < 0.01 then c := 0;
1122 x2 := x+Round(c*gMapInfo.Width);
1123 y2 := y+Round(s*gMapInfo.Width);
1125 t1 := gWalls <> nil;
1126 _collide := False;
1127 w := gMapInfo.Width;
1128 h := gMapInfo.Height;
1130 xe := 0;
1131 ye := 0;
1132 dx := x2-x;
1133 dy := y2-y;
1135 if (xd = 0) and (yd = 0) then Exit;
1137 if dx > 0 then xi := 1 else if dx < 0 then xi := -1 else xi := 0;
1138 if dy > 0 then yi := 1 else if dy < 0 then yi := -1 else yi := 0;
1140 dx := Abs(dx);
1141 dy := Abs(dy);
1143 if dx > dy then d := dx else d := dy;
1145 //blood vel, for Monster.Damage()
1146 //vx := (dx*10 div d)*xi;
1147 //vy := (dy*10 div d)*yi;
1149 xx := x;
1150 yy := y;
1152 for i := 1 to d do
1153 begin
1154 xe := xe+dx;
1155 ye := ye+dy;
1157 if xe > d then
1158 begin
1159 xe := xe-d;
1160 xx := xx+xi;
1161 end;
1163 if ye > d then
1164 begin
1165 ye := ye-d;
1166 yy := yy+yi;
1167 end;
1169 if (yy > h) or (yy < 0) then Break;
1170 if (xx > w) or (xx < 0) then Break;
1172 if t1 then
1173 if ByteBool(gCollideMap[yy, xx] and MARK_BLOCKED) then
1174 begin
1175 _collide := True;
1176 g_GFX_Spark(xx-xi, yy-yi, 2+Random(2), 180+a, 0, 0);
1177 if g_Game_IsServer and g_Game_IsNet then
1178 MH_SEND_Effect(xx-xi, yy-yi, 180+a, NET_GFX_SPARK);
1179 end;
1181 if not _collide then
1182 _collide := GunHit(xx, yy, xi*v, yi*v, dmg, SpawnerUID, v <> 0) <> 0;
1184 if _collide then
1185 Break;
1186 end;
1188 if CheckTrigger and g_Game_IsServer then
1189 g_Triggers_PressL(X, Y, xx-xi, yy-yi, SpawnerUID, ACTIVATE_SHOT);
1190 end;
1192 procedure g_Weapon_punch(x, y: Integer; d, SpawnerUID: Word);
1193 var
1194 obj: TObj;
1195 begin
1196 obj.X := X;
1197 obj.Y := Y;
1198 obj.rect.X := 0;
1199 obj.rect.Y := 0;
1200 obj.rect.Width := 39;
1201 obj.rect.Height := 52;
1202 obj.Vel.X := 0;
1203 obj.Vel.Y := 0;
1204 obj.Accel.X := 0;
1205 obj.Accel.Y := 0;
1207 if g_Weapon_Hit(@obj, d, SpawnerUID, HIT_SOME) <> 0 then
1208 g_Sound_PlayExAt('SOUND_WEAPON_HITPUNCH', x, y)
1209 else
1210 g_Sound_PlayExAt('SOUND_WEAPON_MISSPUNCH', x, y);
1211 end;
1213 function g_Weapon_chainsaw(x, y: Integer; d, SpawnerUID: Word): Integer;
1214 var
1215 obj: TObj;
1216 begin
1217 obj.X := X;
1218 obj.Y := Y;
1219 obj.rect.X := 0;
1220 obj.rect.Y := 0;
1221 obj.rect.Width := 32;
1222 obj.rect.Height := 52;
1223 obj.Vel.X := 0;
1224 obj.Vel.Y := 0;
1225 obj.Accel.X := 0;
1226 obj.Accel.Y := 0;
1228 Result := g_Weapon_Hit(@obj, d, SpawnerUID, HIT_SOME);
1229 end;
1231 procedure g_Weapon_rocket(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1;
1232 Silent: Boolean = False);
1233 var
1234 find_id: DWORD;
1235 dx, dy: Integer;
1236 begin
1237 if WID < 0 then
1238 find_id := FindShot()
1239 else
1240 begin
1241 find_id := WID;
1242 if Integer(find_id) >= High(Shots) then
1243 SetLength(Shots, find_id + 64)
1244 end;
1246 with Shots[find_id] do
1247 begin
1248 g_Obj_Init(@Obj);
1250 Obj.Rect.Width := SHOT_ROCKETLAUNCHER_WIDTH;
1251 Obj.Rect.Height := SHOT_ROCKETLAUNCHER_HEIGHT;
1253 dx := IfThen(xd > x, -Obj.Rect.Width, 0);
1254 dy := -(Obj.Rect.Height div 2);
1256 ShotType := WEAPON_ROCKETLAUNCHER;
1257 throw(find_id, x+dx, y+dy, xd+dx, yd+dy, 12);
1259 Animation := nil;
1260 triggers := nil;
1261 g_Texture_Get('TEXTURE_WEAPON_ROCKET', TextureID);
1262 end;
1264 Shots[find_id].SpawnerUID := SpawnerUID;
1266 if not Silent then
1267 g_Sound_PlayExAt('SOUND_WEAPON_FIREROCKET', x, y);
1268 end;
1270 procedure g_Weapon_revf(x, y, xd, yd: Integer; SpawnerUID, TargetUID: Word;
1271 WID: Integer = -1; Silent: Boolean = False);
1272 var
1273 find_id, FramesID: DWORD;
1274 dx, dy: Integer;
1275 begin
1276 if WID < 0 then
1277 find_id := FindShot()
1278 else
1279 begin
1280 find_id := WID;
1281 if Integer(find_id) >= High(Shots) then
1282 SetLength(Shots, find_id + 64)
1283 end;
1285 with Shots[find_id] do
1286 begin
1287 g_Obj_Init(@Obj);
1289 Obj.Rect.Width := SHOT_SKELFIRE_WIDTH;
1290 Obj.Rect.Height := SHOT_SKELFIRE_HEIGHT;
1292 dx := -(Obj.Rect.Width div 2);
1293 dy := -(Obj.Rect.Height div 2);
1295 ShotType := WEAPON_SKEL_FIRE;
1296 throw(find_id, x+dx, y+dy, xd+dx, yd+dy, 12);
1298 triggers := nil;
1299 target := TargetUID;
1300 g_Frames_Get(FramesID, 'FRAMES_WEAPON_SKELFIRE');
1301 Animation := TAnimation.Create(FramesID, True, 5);
1302 end;
1304 Shots[find_id].SpawnerUID := SpawnerUID;
1306 if not Silent then
1307 g_Sound_PlayExAt('SOUND_WEAPON_FIREREV', x, y);
1308 end;
1310 procedure g_Weapon_plasma(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1;
1311 Silent: Boolean = False);
1312 var
1313 find_id, FramesID: DWORD;
1314 dx, dy: Integer;
1315 begin
1316 if WID < 0 then
1317 find_id := FindShot()
1318 else
1319 begin
1320 find_id := WID;
1321 if Integer(find_id) >= High(Shots) then
1322 SetLength(Shots, find_id + 64);
1323 end;
1325 with Shots[find_id] do
1326 begin
1327 g_Obj_Init(@Obj);
1329 Obj.Rect.Width := SHOT_PLASMA_WIDTH;
1330 Obj.Rect.Height := SHOT_PLASMA_HEIGHT;
1332 dx := IfThen(xd>x, -Obj.Rect.Width, 0);
1333 dy := -(Obj.Rect.Height div 2);
1335 ShotType := WEAPON_PLASMA;
1336 throw(find_id, x+dx, y+dy, xd+dx, yd+dy, 16);
1338 triggers := nil;
1339 g_Frames_Get(FramesID, 'FRAMES_WEAPON_PLASMA');
1340 Animation := TAnimation.Create(FramesID, True, 5);
1341 end;
1343 Shots[find_id].SpawnerUID := SpawnerUID;
1345 if not Silent then
1346 g_Sound_PlayExAt('SOUND_WEAPON_FIREPLASMA', x, y);
1347 end;
1349 procedure g_Weapon_flame(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1;
1350 Silent: Boolean = False);
1351 var
1352 find_id, FramesID: DWORD;
1353 dx, dy: Integer;
1354 begin
1355 if WID < 0 then
1356 find_id := FindShot()
1357 else
1358 begin
1359 find_id := WID;
1360 if Integer(find_id) >= High(Shots) then
1361 SetLength(Shots, find_id + 64);
1362 end;
1364 with Shots[find_id] do
1365 begin
1366 g_Obj_Init(@Obj);
1368 Obj.Rect.Width := SHOT_FLAME_WIDTH;
1369 Obj.Rect.Height := SHOT_FLAME_HEIGHT;
1371 dx := IfThen(xd>x, -Obj.Rect.Width, 0);
1372 dy := -(Obj.Rect.Height div 2);
1374 ShotType := WEAPON_FLAMETHROWER;
1375 throw(find_id, x+dx, y+dy, xd+dx, yd+dy, 16);
1377 triggers := nil;
1378 Animation := nil;
1379 TextureID := 0;
1380 Stopped := 0;
1381 end;
1383 Shots[find_id].SpawnerUID := SpawnerUID;
1385 // if not Silent then
1386 // g_Sound_PlayExAt('SOUND_WEAPON_FIREPLASMA', x, y);
1387 end;
1389 procedure g_Weapon_ball1(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1;
1390 Silent: Boolean = False);
1391 var
1392 find_id, FramesID: DWORD;
1393 dx, dy: Integer;
1394 begin
1395 if WID < 0 then
1396 find_id := FindShot()
1397 else
1398 begin
1399 find_id := WID;
1400 if Integer(find_id) >= High(Shots) then
1401 SetLength(Shots, find_id + 64)
1402 end;
1404 with Shots[find_id] do
1405 begin
1406 g_Obj_Init(@Obj);
1408 Obj.Rect.Width := 16;
1409 Obj.Rect.Height := 16;
1411 dx := IfThen(xd>x, -Obj.Rect.Width, 0);
1412 dy := -(Obj.Rect.Height div 2);
1414 ShotType := WEAPON_IMP_FIRE;
1415 throw(find_id, x+dx, y+dy, xd+dx, yd+dy, 16);
1417 triggers := nil;
1418 g_Frames_Get(FramesID, 'FRAMES_WEAPON_IMPFIRE');
1419 Animation := TAnimation.Create(FramesID, True, 4);
1420 end;
1422 Shots[find_id].SpawnerUID := SpawnerUID;
1424 if not Silent then
1425 g_Sound_PlayExAt('SOUND_WEAPON_FIREBALL', x, y);
1426 end;
1428 procedure g_Weapon_ball2(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1;
1429 Silent: Boolean = False);
1430 var
1431 find_id, FramesID: DWORD;
1432 dx, dy: Integer;
1433 begin
1434 if WID < 0 then
1435 find_id := FindShot()
1436 else
1437 begin
1438 find_id := WID;
1439 if Integer(find_id) >= High(Shots) then
1440 SetLength(Shots, find_id + 64)
1441 end;
1443 with Shots[find_id] do
1444 begin
1445 g_Obj_Init(@Obj);
1447 Obj.Rect.Width := 16;
1448 Obj.Rect.Height := 16;
1450 dx := IfThen(xd>x, -Obj.Rect.Width, 0);
1451 dy := -(Obj.Rect.Height div 2);
1453 ShotType := WEAPON_CACO_FIRE;
1454 throw(find_id, x+dx, y+dy, xd+dx, yd+dy, 16);
1456 triggers := nil;
1457 g_Frames_Get(FramesID, 'FRAMES_WEAPON_CACOFIRE');
1458 Animation := TAnimation.Create(FramesID, True, 4);
1459 end;
1461 Shots[find_id].SpawnerUID := SpawnerUID;
1463 if not Silent then
1464 g_Sound_PlayExAt('SOUND_WEAPON_FIREBALL', x, y);
1465 end;
1467 procedure g_Weapon_ball7(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1;
1468 Silent: Boolean = False);
1469 var
1470 find_id, FramesID: DWORD;
1471 dx, dy: Integer;
1472 begin
1473 if WID < 0 then
1474 find_id := FindShot()
1475 else
1476 begin
1477 find_id := WID;
1478 if Integer(find_id) >= High(Shots) then
1479 SetLength(Shots, find_id + 64)
1480 end;
1482 with Shots[find_id] do
1483 begin
1484 g_Obj_Init(@Obj);
1486 Obj.Rect.Width := 32;
1487 Obj.Rect.Height := 16;
1489 dx := IfThen(xd>x, -Obj.Rect.Width, 0);
1490 dy := -(Obj.Rect.Height div 2);
1492 ShotType := WEAPON_BARON_FIRE;
1493 throw(find_id, x+dx, y+dy, xd+dx, yd+dy, 16);
1495 triggers := nil;
1496 g_Frames_Get(FramesID, 'FRAMES_WEAPON_BARONFIRE');
1497 Animation := TAnimation.Create(FramesID, True, 4);
1498 end;
1500 Shots[find_id].SpawnerUID := SpawnerUID;
1502 if not Silent then
1503 g_Sound_PlayExAt('SOUND_WEAPON_FIREBALL', x, y);
1504 end;
1506 procedure g_Weapon_aplasma(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1;
1507 Silent: Boolean = False);
1508 var
1509 find_id, FramesID: DWORD;
1510 dx, dy: Integer;
1511 begin
1512 if WID < 0 then
1513 find_id := FindShot()
1514 else
1515 begin
1516 find_id := WID;
1517 if Integer(find_id) >= High(Shots) then
1518 SetLength(Shots, find_id + 64)
1519 end;
1521 with Shots[find_id] do
1522 begin
1523 g_Obj_Init(@Obj);
1525 Obj.Rect.Width := 16;
1526 Obj.Rect.Height := 16;
1528 dx := IfThen(xd>x, -Obj.Rect.Width, 0);
1529 dy := -(Obj.Rect.Height div 2);
1531 ShotType := WEAPON_BSP_FIRE;
1532 throw(find_id, x+dx, y+dy, xd+dx, yd+dy, 16);
1534 triggers := nil;
1536 g_Frames_Get(FramesID, 'FRAMES_WEAPON_BSPFIRE');
1537 Animation := TAnimation.Create(FramesID, True, 4);
1538 end;
1540 Shots[find_id].SpawnerUID := SpawnerUID;
1542 if not Silent then
1543 g_Sound_PlayExAt('SOUND_WEAPON_FIREPLASMA', x, y);
1544 end;
1546 procedure g_Weapon_manfire(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1;
1547 Silent: Boolean = False);
1548 var
1549 find_id, FramesID: DWORD;
1550 dx, dy: Integer;
1551 begin
1552 if WID < 0 then
1553 find_id := FindShot()
1554 else
1555 begin
1556 find_id := WID;
1557 if Integer(find_id) >= High(Shots) then
1558 SetLength(Shots, find_id + 64)
1559 end;
1561 with Shots[find_id] do
1562 begin
1563 g_Obj_Init(@Obj);
1565 Obj.Rect.Width := 32;
1566 Obj.Rect.Height := 32;
1568 dx := IfThen(xd>x, -Obj.Rect.Width, 0);
1569 dy := -(Obj.Rect.Height div 2);
1571 ShotType := WEAPON_MANCUB_FIRE;
1572 throw(find_id, x+dx, y+dy, xd+dx, yd+dy, 16);
1574 triggers := nil;
1576 g_Frames_Get(FramesID, 'FRAMES_WEAPON_MANCUBFIRE');
1577 Animation := TAnimation.Create(FramesID, True, 4);
1578 end;
1580 Shots[find_id].SpawnerUID := SpawnerUID;
1582 if not Silent then
1583 g_Sound_PlayExAt('SOUND_WEAPON_FIREBALL', x, y);
1584 end;
1586 procedure g_Weapon_bfgshot(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1;
1587 Silent: Boolean = False);
1588 var
1589 find_id, FramesID: DWORD;
1590 dx, dy: Integer;
1591 begin
1592 if WID < 0 then
1593 find_id := FindShot()
1594 else
1595 begin
1596 find_id := WID;
1597 if Integer(find_id) >= High(Shots) then
1598 SetLength(Shots, find_id + 64)
1599 end;
1601 with Shots[find_id] do
1602 begin
1603 g_Obj_Init(@Obj);
1605 Obj.Rect.Width := SHOT_BFG_WIDTH;
1606 Obj.Rect.Height := SHOT_BFG_HEIGHT;
1608 dx := IfThen(xd>x, -Obj.Rect.Width, 0);
1609 dy := -(Obj.Rect.Height div 2);
1611 ShotType := WEAPON_BFG;
1612 throw(find_id, x+dx, y+dy, xd+dx, yd+dy, 16);
1614 triggers := nil;
1615 g_Frames_Get(FramesID, 'FRAMES_WEAPON_BFG');
1616 Animation := TAnimation.Create(FramesID, True, 6);
1617 end;
1619 Shots[find_id].SpawnerUID := SpawnerUID;
1621 if not Silent then
1622 g_Sound_PlayExAt('SOUND_WEAPON_FIREBFG', x, y);
1623 end;
1625 procedure g_Weapon_bfghit(x, y: Integer);
1626 var
1627 ID: DWORD;
1628 Anim: TAnimation;
1629 begin
1630 if g_Frames_Get(ID, 'FRAMES_BFGHIT') then
1631 begin
1632 Anim := TAnimation.Create(ID, False, 4);
1633 g_GFX_OnceAnim(x-32, y-32, Anim);
1634 Anim.Free();
1635 end;
1636 end;
1638 procedure g_Weapon_pistol(x, y, xd, yd: Integer; SpawnerUID: Word;
1639 Silent: Boolean = False);
1640 begin
1641 if not Silent then
1642 g_Sound_PlayExAt('SOUND_WEAPON_FIREPISTOL', x, y);
1644 g_Weapon_gun(x, y, xd, yd, 1, 3, SpawnerUID, True);
1645 if gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF] then
1646 begin
1647 g_Weapon_gun(x, y+1, xd, yd+1, 1, 3, SpawnerUID, False);
1648 g_Weapon_gun(x, y-1, xd, yd-1, 1, 2, SpawnerUID, False);
1649 end;
1650 end;
1652 procedure g_Weapon_mgun(x, y, xd, yd: Integer; SpawnerUID: Word;
1653 Silent: Boolean = False);
1654 begin
1655 if not Silent then
1656 if gSoundEffectsDF then g_Sound_PlayExAt('SOUND_WEAPON_FIRECGUN', x, y);
1658 g_Weapon_gun(x, y, xd, yd, 1, 3, SpawnerUID, True);
1659 if (gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF]) and
1660 (g_GetUIDType(SpawnerUID) = UID_PLAYER) then
1661 begin
1662 g_Weapon_gun(x, y+1, xd, yd+1, 1, 2, SpawnerUID, False);
1663 g_Weapon_gun(x, y-1, xd, yd-1, 1, 2, SpawnerUID, False);
1664 end;
1665 end;
1667 procedure g_Weapon_shotgun(x, y, xd, yd: Integer; SpawnerUID: Word;
1668 Silent: Boolean = False);
1669 var
1670 i, j: Integer;
1671 begin
1672 if not Silent then
1673 if gSoundEffectsDF then g_Sound_PlayExAt('SOUND_WEAPON_FIRESHOTGUN', x, y);
1675 for i := 0 to 9 do
1676 begin
1677 j := Random(17)-8; // -8 .. 8
1678 g_Weapon_gun(x, y+j, xd, yd+j, IfThen(i mod 2 <> 0, 1, 0), 3, SpawnerUID, i=0);
1679 end;
1680 end;
1682 procedure g_Weapon_dshotgun(x, y, xd, yd: Integer; SpawnerUID: Word;
1683 Silent: Boolean = False);
1684 var
1685 a, i, j: Integer;
1686 begin
1687 if not Silent then
1688 g_Sound_PlayExAt('SOUND_WEAPON_FIRESHOTGUN2', x, y);
1690 if gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF] then a := 25 else a := 20;
1691 for i := 0 to a do
1692 begin
1693 j := Random(41)-20; // -20 .. 20
1694 g_Weapon_gun(x, y+j, xd, yd+j, IfThen(i mod 3 <> 0, 0, 1), 3, SpawnerUID, i=0);
1695 end;
1696 end;
1698 procedure g_Weapon_Update();
1699 var
1700 i, a, h, cx, cy, oldvx, oldvy: Integer;
1701 _id: DWORD;
1702 Anim: TAnimation;
1703 t: DWArray;
1704 st: Word;
1705 s: String;
1706 o: TObj;
1707 spl: Boolean;
1708 Loud: Boolean;
1709 begin
1710 if Shots = nil then
1711 Exit;
1713 for i := 0 to High(Shots) do
1714 begin
1715 if Shots[i].ShotType = 0 then
1716 Continue;
1718 Loud := True;
1720 with Shots[i] do
1721 begin
1722 Timeout := Timeout - 1;
1723 oldvx := Obj.Vel.X;
1724 oldvy := Obj.Vel.Y;
1725 // Àêòèâèðîâàòü òðèããåðû ïî ïóòè (êðîìå óæå àêòèâèðîâàííûõ):
1726 if g_Game_IsServer then
1727 t := g_Triggers_PressR(Obj.X, Obj.Y, Obj.Rect.Width, Obj.Rect.Height,
1728 SpawnerUID, ACTIVATE_SHOT, triggers)
1729 else
1730 t := nil;
1732 if t <> nil then
1733 begin
1734 // Ïîïîëíÿåì ñïèñîê àêòèâèðîâàííûõ òðèããåðîâ:
1735 if triggers = nil then
1736 triggers := t
1737 else
1738 begin
1739 h := High(t);
1741 for a := 0 to h do
1742 if not InDWArray(t[a], triggers) then
1743 begin
1744 SetLength(triggers, Length(triggers)+1);
1745 triggers[High(triggers)] := t[a];
1746 end;
1747 end;
1748 end;
1750 // Àíèìàöèÿ ñíàðÿäà:
1751 if Animation <> nil then
1752 Animation.Update();
1754 // Äâèæåíèå:
1755 spl := (ShotType <> WEAPON_PLASMA) and
1756 (ShotType <> WEAPON_BFG) and
1757 (ShotType <> WEAPON_BSP_FIRE) and
1758 (ShotType <> WEAPON_FLAMETHROWER);
1760 st := g_Obj_Move(@Obj, False, spl);
1762 if WordBool(st and MOVE_FALLOUT) or (Obj.X < -1000) or
1763 (Obj.X > gMapInfo.Width+1000) or (Obj.Y < -1000) then
1764 begin
1765 // Íà êëèåíòå ñêîðåå âñåãî è òàê óæå âûïàë.
1766 ShotType := 0;
1767 Animation.Free();
1768 Continue;
1769 end;
1771 cx := Obj.X + (Obj.Rect.Width div 2);
1772 cy := Obj.Y + (Obj.Rect.Height div 2);
1774 case ShotType of
1775 WEAPON_ROCKETLAUNCHER, WEAPON_SKEL_FIRE: // Ðàêåòû è ñíàðÿäû Ñêåëåòà
1776 begin
1777 // Âûëåòåëà èç âîäû:
1778 if WordBool(st and MOVE_HITAIR) then
1779 g_Obj_SetSpeed(@Obj, 12);
1781 // Â âîäå øëåéô - ïóçûðè, â âîçäóõå øëåéô - äûì:
1782 if WordBool(st and MOVE_INWATER) then
1783 g_GFX_Bubbles(Obj.X+(Obj.Rect.Width div 2),
1784 Obj.Y+(Obj.Rect.Height div 2),
1785 1+Random(3), 16, 16)
1786 else
1787 if g_Frames_Get(_id, 'FRAMES_SMOKE') then
1788 begin
1789 Anim := TAnimation.Create(_id, False, 3);
1790 Anim.Alpha := 150;
1791 g_GFX_OnceAnim(Obj.X-14+Random(9),
1792 Obj.Y+(Obj.Rect.Height div 2)-20+Random(9),
1793 Anim, ONCEANIM_SMOKE);
1794 Anim.Free();
1795 end;
1797 // Ïîïàëè â êîãî-òî èëè â ñòåíó:
1798 if WordBool(st and (MOVE_HITWALL or MOVE_HITLAND or MOVE_HITCEIL)) or
1799 (g_Weapon_Hit(@Obj, 10, SpawnerUID, HIT_SOME, False) <> 0) or
1800 (Timeout < 1) then
1801 begin
1802 Obj.Vel.X := 0;
1803 Obj.Vel.Y := 0;
1805 g_Weapon_Explode(cx, cy, 60, SpawnerUID);
1807 if ShotType = WEAPON_SKEL_FIRE then
1808 begin // Âçðûâ ñíàðÿäà Ñêåëåòà
1809 if g_Frames_Get(TextureID, 'FRAMES_EXPLODE_SKELFIRE') then
1810 begin
1811 Anim := TAnimation.Create(TextureID, False, 8);
1812 Anim.Blending := False;
1813 g_GFX_OnceAnim((Obj.X+32)-58, (Obj.Y+8)-36, Anim);
1814 Anim.Free();
1815 end;
1816 end
1817 else
1818 begin // Âçðûâ Ðàêåòû
1819 if g_Frames_Get(TextureID, 'FRAMES_EXPLODE_ROCKET') then
1820 begin
1821 Anim := TAnimation.Create(TextureID, False, 6);
1822 Anim.Blending := False;
1823 g_GFX_OnceAnim(cx-64, cy-64, Anim);
1824 Anim.Free();
1825 end;
1826 end;
1828 g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEROCKET', Obj.X, Obj.Y);
1830 ShotType := 0;
1831 end;
1833 if ShotType = WEAPON_SKEL_FIRE then
1834 begin // Ñàìîíàâîäêà ñíàðÿäà Ñêåëåòà:
1835 if GetPos(target, @o) then
1836 throw(i, Obj.X, Obj.Y,
1837 o.X+o.Rect.X+(o.Rect.Width div 2)+o.Vel.X+o.Accel.X,
1838 o.Y+o.Rect.Y+(o.Rect.Height div 2)+o.Vel.Y+o.Accel.Y,
1839 12);
1840 end;
1841 end;
1843 WEAPON_PLASMA, WEAPON_BSP_FIRE: // Ïëàçìà, ïëàçìà Àðàõíàòðîíà
1844 begin
1845 // Ïîïàëà â âîäó - ýëåêòðîøîê ïî âîäå:
1846 if WordBool(st and (MOVE_INWATER or MOVE_HITWATER)) then
1847 begin
1848 g_Sound_PlayExAt('SOUND_WEAPON_PLASMAWATER', Obj.X, Obj.Y);
1849 if g_Game_IsServer then CheckTrap(i, 10, HIT_ELECTRO);
1850 ShotType := 0;
1851 Continue;
1852 end;
1854 // Âåëè÷èíà óðîíà:
1855 if (ShotType = WEAPON_PLASMA) and
1856 (gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF]) then
1857 a := 10
1858 else
1859 a := 5;
1861 if ShotType = WEAPON_BSP_FIRE then
1862 a := 10;
1864 // Ïîïàëè â êîãî-òî èëè â ñòåíó:
1865 if WordBool(st and (MOVE_HITWALL or MOVE_HITLAND or MOVE_HITCEIL)) or
1866 (g_Weapon_Hit(@Obj, a, SpawnerUID, HIT_SOME, False) <> 0) or
1867 (Timeout < 1) then
1868 begin
1869 if ShotType = WEAPON_PLASMA then
1870 s := 'FRAMES_EXPLODE_PLASMA'
1871 else
1872 s := 'FRAMES_EXPLODE_BSPFIRE';
1874 // Âçðûâ Ïëàçìû:
1875 if g_Frames_Get(TextureID, s) then
1876 begin
1877 Anim := TAnimation.Create(TextureID, False, 3);
1878 Anim.Blending := False;
1879 g_GFX_OnceAnim(cx-16, cy-16, Anim);
1880 Anim.Free();
1881 end;
1883 g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEPLASMA', Obj.X, Obj.Y);
1885 ShotType := 0;
1886 end;
1887 end;
1889 WEAPON_FLAMETHROWER: // Îãíåìåò
1890 begin
1891 // Ñî âðåìåíåì óìèðàåò
1892 if (Timeout < 1) then
1893 begin
1894 ShotType := 0;
1895 Continue;
1896 end;
1897 // Ïîä âîäîé òîæå
1898 if WordBool(st and (MOVE_HITWATER or MOVE_INWATER)) then
1899 begin
1900 if WordBool(st and MOVE_HITWATER) then
1901 begin
1902 if g_Frames_Get(_id, 'FRAMES_SMOKE') then
1903 begin
1904 Anim := TAnimation.Create(_id, False, 3);
1905 Anim.Alpha := 0;
1906 g_GFX_OnceAnim(cx-4+Random(8)-(Anim.Width div 2),
1907 cy-4+Random(8)-(Anim.Height div 2),
1908 Anim, ONCEANIM_SMOKE);
1909 Anim.Free();
1910 end;
1911 end
1912 else
1913 g_GFX_Bubbles(cx, cy, 1+Random(3), 16, 16);
1914 ShotType := 0;
1915 Continue;
1916 end;
1918 // Ãðàâèòàöèÿ
1919 if Stopped = 0 then
1920 Obj.Accel.Y := Obj.Accel.Y + 1;
1921 // Ïîïàëè â ñòåíó èëè â âîäó:
1922 if WordBool(st and (MOVE_HITWALL or MOVE_HITLAND or MOVE_HITCEIL or MOVE_HITWATER)) then
1923 begin
1924 // Ïðèëèïàåì:
1925 Obj.Vel.X := 0;
1926 Obj.Vel.Y := 0;
1927 Obj.Accel.Y := 0;
1928 if WordBool(st and MOVE_HITWALL) then
1929 Stopped := MOVE_HITWALL
1930 else if WordBool(st and MOVE_HITLAND) then
1931 Stopped := MOVE_HITLAND
1932 else if WordBool(st and MOVE_HITCEIL) then
1933 Stopped := MOVE_HITCEIL;
1934 end;
1936 a := IfThen(Stopped = 0, 5, 1);
1937 // Åñëè â êîãî-òî ïîïàëè
1938 if g_Weapon_Hit(@Obj, a, SpawnerUID, HIT_FLAME, False) <> 0 then
1939 begin
1940 // HIT_FLAME ñàì ïîäîææåò
1941 // Åñëè â ïîëåòå ïîïàëè, èñ÷åçàåì
1942 if Stopped = 0 then
1943 ShotType := 0;
1944 end;
1946 if g_Frames_Get(_id, 'FRAMES_FLAME') and (gTime mod 2 = 0) then
1947 begin
1948 Anim := TAnimation.Create(_id, False, 2 + Random(2));
1949 Anim.Alpha := 0;
1950 case Stopped of
1951 0: g_GFX_OnceAnim(cx-4+Random(8)-(Anim.Width div 2),
1952 cy-4+Random(8)-(Anim.Height div 2),
1953 Anim, ONCEANIM_SMOKE);
1954 MOVE_HITWALL: g_GFX_OnceAnim(cx-4+Random(8)-(Anim.Width div 2),
1955 cy-12+Random(24)-(Anim.Height div 2),
1956 Anim, ONCEANIM_SMOKE);
1957 MOVE_HITLAND: g_GFX_OnceAnim(cx-12+Random(24)-(Anim.Width div 2),
1958 cy-10+Random(8)-(Anim.Height div 2),
1959 Anim, ONCEANIM_SMOKE);
1960 MOVE_HITCEIL: g_GFX_OnceAnim(cx-12+Random(24)-(Anim.Width div 2),
1961 cy+6+Random(8)-(Anim.Height div 2),
1962 Anim, ONCEANIM_SMOKE);
1963 end;
1964 Anim.Free();
1965 end;
1966 end;
1968 WEAPON_BFG: // BFG
1969 begin
1970 // Ïîïàëà â âîäó - ýëåêòðîøîê ïî âîäå:
1971 if WordBool(st and (MOVE_INWATER or MOVE_HITWATER)) then
1972 begin
1973 g_Sound_PlayExAt('SOUND_WEAPON_BFGWATER', Obj.X, Obj.Y);
1974 if g_Game_IsServer then CheckTrap(i, 1000, HIT_ELECTRO);
1975 ShotType := 0;
1976 Continue;
1977 end;
1979 // Ïîïàëè â êîãî-òî èëè â ñòåíó:
1980 if WordBool(st and (MOVE_HITWALL or MOVE_HITLAND or MOVE_HITCEIL)) or
1981 (g_Weapon_Hit(@Obj, SHOT_BFG_DAMAGE, SpawnerUID, HIT_BFG, False) <> 0) or
1982 (Timeout < 1) then
1983 begin
1984 // Ëó÷è BFG:
1985 if g_Game_IsServer then g_Weapon_BFG9000(cx, cy, SpawnerUID);
1987 // Âçðûâ BFG:
1988 if g_Frames_Get(TextureID, 'FRAMES_EXPLODE_BFG') then
1989 begin
1990 Anim := TAnimation.Create(TextureID, False, 6);
1991 Anim.Blending := False;
1992 g_GFX_OnceAnim(cx-64, cy-64, Anim);
1993 Anim.Free();
1994 end;
1996 g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEBFG', Obj.X, Obj.Y);
1998 ShotType := 0;
1999 end;
2000 end;
2002 WEAPON_IMP_FIRE, WEAPON_CACO_FIRE, WEAPON_BARON_FIRE: // Âûñòðåëû Áåñà, Êàêîäåìîíà Ðûöàðÿ/Áàðîíà àäà
2003 begin
2004 // Âûëåòåë èç âîäû:
2005 if WordBool(st and MOVE_HITAIR) then
2006 g_Obj_SetSpeed(@Obj, 16);
2008 // Âåëè÷èíà óðîíà:
2009 if ShotType = WEAPON_IMP_FIRE then
2010 a := 5
2011 else
2012 if ShotType = WEAPON_CACO_FIRE then
2013 a := 20
2014 else
2015 a := 40;
2017 // Ïîïàëè â êîãî-òî èëè â ñòåíó:
2018 if WordBool(st and (MOVE_HITWALL or MOVE_HITLAND or MOVE_HITCEIL)) or
2019 (g_Weapon_Hit(@Obj, a, SpawnerUID, HIT_SOME) <> 0) or
2020 (Timeout < 1) then
2021 begin
2022 if ShotType = WEAPON_IMP_FIRE then
2023 s := 'FRAMES_EXPLODE_IMPFIRE'
2024 else
2025 if ShotType = WEAPON_CACO_FIRE then
2026 s := 'FRAMES_EXPLODE_CACOFIRE'
2027 else
2028 s := 'FRAMES_EXPLODE_BARONFIRE';
2030 // Âçðûâ:
2031 if g_Frames_Get(TextureID, s) then
2032 begin
2033 Anim := TAnimation.Create(TextureID, False, 6);
2034 Anim.Blending := False;
2035 g_GFX_OnceAnim(cx-32, cy-32, Anim);
2036 Anim.Free();
2037 end;
2039 g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEBALL', Obj.X, Obj.Y);
2041 ShotType := 0;
2042 end;
2043 end;
2045 WEAPON_MANCUB_FIRE: // Âûñòðåë Ìàíêóáóñà
2046 begin
2047 // Âûëåòåë èç âîäû:
2048 if WordBool(st and MOVE_HITAIR) then
2049 g_Obj_SetSpeed(@Obj, 16);
2051 // Ïîïàëè â êîãî-òî èëè â ñòåíó:
2052 if WordBool(st and (MOVE_HITWALL or MOVE_HITLAND or MOVE_HITCEIL)) or
2053 (g_Weapon_Hit(@Obj, 40, SpawnerUID, HIT_SOME, False) <> 0) or
2054 (Timeout < 1) then
2055 begin
2056 // Âçðûâ:
2057 if g_Frames_Get(TextureID, 'FRAMES_EXPLODE_ROCKET') then
2058 begin
2059 Anim := TAnimation.Create(TextureID, False, 6);
2060 Anim.Blending := False;
2061 g_GFX_OnceAnim(cx-64, cy-64, Anim);
2062 Anim.Free();
2063 end;
2065 g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEBALL', Obj.X, Obj.Y);
2067 ShotType := 0;
2068 end;
2069 end;
2070 end; // case ShotType of...
2072 // Åñëè ñíàðÿäà óæå íåò, óäàëÿåì àíèìàöèþ:
2073 if (ShotType = 0) then
2074 begin
2075 if gGameSettings.GameType = GT_SERVER then
2076 MH_SEND_DeleteShot(i, Obj.X, Obj.Y, Loud);
2077 if Animation <> nil then
2078 begin
2079 Animation.Free();
2080 Animation := nil;
2081 end;
2082 end
2083 else if (ShotType <> WEAPON_FLAMETHROWER) and ((oldvx <> Obj.Vel.X) or (oldvy <> Obj.Vel.Y)) then
2084 if gGameSettings.GameType = GT_SERVER then
2085 MH_SEND_UpdateShot(i);
2086 end;
2087 end;
2088 end;
2090 procedure g_Weapon_Draw();
2091 var
2092 i: Integer;
2093 a: SmallInt;
2094 p: TPoint;
2095 begin
2096 if Shots = nil then
2097 Exit;
2099 for i := 0 to High(Shots) do
2100 if Shots[i].ShotType <> 0 then
2101 with Shots[i] do
2102 begin
2103 if (Shots[i].ShotType = WEAPON_ROCKETLAUNCHER) or
2104 (Shots[i].ShotType = WEAPON_BARON_FIRE) or
2105 (Shots[i].ShotType = WEAPON_MANCUB_FIRE) or
2106 (Shots[i].ShotType = WEAPON_SKEL_FIRE) then
2107 a := -GetAngle2(Obj.Vel.X, Obj.Vel.Y)
2108 else
2109 a := 0;
2111 p.X := Obj.Rect.Width div 2;
2112 p.Y := Obj.Rect.Height div 2;
2114 if Animation <> nil then
2115 begin
2116 if (Shots[i].ShotType = WEAPON_BARON_FIRE) or
2117 (Shots[i].ShotType = WEAPON_MANCUB_FIRE) or
2118 (Shots[i].ShotType = WEAPON_SKEL_FIRE) then
2119 Animation.DrawEx(Obj.X, Obj.Y, M_NONE, p, a)
2120 else
2121 Animation.Draw(Obj.X, Obj.Y, M_NONE);
2122 end
2123 else if TextureID <> 0 then
2124 begin
2125 if (Shots[i].ShotType = WEAPON_ROCKETLAUNCHER) then
2126 e_DrawAdv(TextureID, Obj.X, Obj.Y, 0, True, False, a, @p, M_NONE)
2127 else
2128 e_Draw(TextureID, Obj.X, Obj.Y, 0, True, False);
2129 end;
2131 if g_debug_Frames then
2132 begin
2133 e_DrawQuad(Obj.X+Obj.Rect.X,
2134 Obj.Y+Obj.Rect.Y,
2135 Obj.X+Obj.Rect.X+Obj.Rect.Width-1,
2136 Obj.Y+Obj.Rect.Y+Obj.Rect.Height-1,
2137 0, 255, 0);
2138 end;
2139 end;
2140 end;
2142 function g_Weapon_Danger(UID: Word; X, Y: Integer; Width, Height: Word; Time: Byte): Boolean;
2143 var
2144 a: Integer;
2145 begin
2146 Result := False;
2148 if Shots = nil then
2149 Exit;
2151 for a := 0 to High(Shots) do
2152 if (Shots[a].ShotType <> 0) and (Shots[a].SpawnerUID <> UID) then
2153 if ((Shots[a].Obj.Vel.Y = 0) and (Shots[a].Obj.Vel.X > 0) and (Shots[a].Obj.X < X)) or
2154 (Shots[a].Obj.Vel.Y = 0) and (Shots[a].Obj.Vel.X < 0) and (Shots[a].Obj.X > X) then
2155 if (Abs(X-Shots[a].Obj.X) < Abs(Shots[a].Obj.Vel.X*Time)) and
2156 g_Collide(X, Y, Width, Height, X, Shots[a].Obj.Y,
2157 Shots[a].Obj.Rect.Width, Shots[a].Obj.Rect.Height) and
2158 g_TraceVector(X, Y, Shots[a].Obj.X, Shots[a].Obj.Y) then
2159 begin
2160 Result := True;
2161 Exit;
2162 end;
2163 end;
2165 procedure g_Weapon_SaveState(var Mem: TBinMemoryWriter);
2166 var
2167 count, i, j: Integer;
2168 dw: DWORD;
2169 begin
2170 // Ñ÷èòàåì êîëè÷åñòâî ñóùåñòâóþùèõ ñíàðÿäîâ:
2171 count := 0;
2172 if Shots <> nil then
2173 for i := 0 to High(Shots) do
2174 if Shots[i].ShotType <> 0 then
2175 count := count + 1;
2177 Mem := TBinMemoryWriter.Create((count+1) * 80);
2179 // Êîëè÷åñòâî ñíàðÿäîâ:
2180 Mem.WriteInt(count);
2182 if count = 0 then
2183 Exit;
2185 for i := 0 to High(Shots) do
2186 if Shots[i].ShotType <> 0 then
2187 begin
2188 // Ñèãíàòóðà ñíàðÿäà:
2189 dw := SHOT_SIGNATURE; // 'SHOT'
2190 Mem.WriteDWORD(dw);
2191 // Òèï ñíàðÿäà:
2192 Mem.WriteByte(Shots[i].ShotType);
2193 // Öåëü:
2194 Mem.WriteWord(Shots[i].Target);
2195 // UID ñòðåëÿâøåãî:
2196 Mem.WriteWord(Shots[i].SpawnerUID);
2197 // Ðàçìåð ïîëÿ Triggers:
2198 dw := Length(Shots[i].Triggers);
2199 Mem.WriteDWORD(dw);
2200 // Òðèããåðû, àêòèâèðîâàííûå âûñòðåëîì:
2201 for j := 0 to Integer(dw)-1 do
2202 Mem.WriteDWORD(Shots[i].Triggers[j]);
2203 // Îáúåêò ñíàðÿäà:
2204 Obj_SaveState(@Shots[i].Obj, Mem);
2205 // Êîñòûëèíà åáàíàÿ:
2206 Mem.WriteByte(Shots[i].Stopped);
2207 end;
2208 end;
2210 procedure g_Weapon_LoadState(var Mem: TBinMemoryReader);
2211 var
2212 count, i, j: Integer;
2213 dw: DWORD;
2214 begin
2215 if Mem = nil then
2216 Exit;
2218 // Êîëè÷åñòâî ñíàðÿäîâ:
2219 Mem.ReadInt(count);
2221 SetLength(Shots, count);
2223 if count = 0 then
2224 Exit;
2226 for i := 0 to count-1 do
2227 begin
2228 // Ñèãíàòóðà ñíàðÿäà:
2229 Mem.ReadDWORD(dw);
2230 if dw <> SHOT_SIGNATURE then // 'SHOT'
2231 begin
2232 raise EBinSizeError.Create('g_Weapons_LoadState: Wrong Shot Signature');
2233 end;
2234 // Òèï ñíàðÿäà:
2235 Mem.ReadByte(Shots[i].ShotType);
2236 // Öåëü:
2237 Mem.ReadWord(Shots[i].Target);
2238 // UID ñòðåëÿâøåãî:
2239 Mem.ReadWord(Shots[i].SpawnerUID);
2240 // Ðàçìåð ïîëÿ Triggers:
2241 Mem.ReadDWORD(dw);
2242 SetLength(Shots[i].Triggers, dw);
2243 // Òðèããåðû, àêòèâèðîâàííûå âûñòðåëîì:
2244 for j := 0 to Integer(dw)-1 do
2245 Mem.ReadDWORD(Shots[i].Triggers[j]);
2246 // Îáúåêò ïðåäìåòà:
2247 Obj_LoadState(@Shots[i].Obj, Mem);
2248 // Êîñòûëèíà åáàíàÿ:
2249 Mem.ReadByte(Shots[i].Stopped);
2251 // Óñòàíîâêà òåêñòóðû èëè àíèìàöèè:
2252 Shots[i].TextureID := DWORD(-1);
2253 Shots[i].Animation := nil;
2255 case Shots[i].ShotType of
2256 WEAPON_ROCKETLAUNCHER, WEAPON_SKEL_FIRE:
2257 begin
2258 g_Texture_Get('TEXTURE_WEAPON_ROCKET', Shots[i].TextureID);
2259 end;
2260 WEAPON_PLASMA:
2261 begin
2262 g_Frames_Get(dw, 'FRAMES_WEAPON_PLASMA');
2263 Shots[i].Animation := TAnimation.Create(dw, True, 5);
2264 end;
2265 WEAPON_BFG:
2266 begin
2267 g_Frames_Get(dw, 'FRAMES_WEAPON_BFG');
2268 Shots[i].Animation := TAnimation.Create(dw, True, 6);
2269 end;
2270 WEAPON_IMP_FIRE:
2271 begin
2272 g_Frames_Get(dw, 'FRAMES_WEAPON_IMPFIRE');
2273 Shots[i].Animation := TAnimation.Create(dw, True, 4);
2274 end;
2275 WEAPON_BSP_FIRE:
2276 begin
2277 g_Frames_Get(dw, 'FRAMES_WEAPON_BSPFIRE');
2278 Shots[i].Animation := TAnimation.Create(dw, True, 4);
2279 end;
2280 WEAPON_CACO_FIRE:
2281 begin
2282 g_Frames_Get(dw, 'FRAMES_WEAPON_CACOFIRE');
2283 Shots[i].Animation := TAnimation.Create(dw, True, 4);
2284 end;
2285 WEAPON_BARON_FIRE:
2286 begin
2287 g_Frames_Get(dw, 'FRAMES_WEAPON_BARONFIRE');
2288 Shots[i].Animation := TAnimation.Create(dw, True, 4);
2289 end;
2290 WEAPON_MANCUB_FIRE:
2291 begin
2292 g_Frames_Get(dw, 'FRAMES_WEAPON_MANCUBFIRE');
2293 Shots[i].Animation := TAnimation.Create(dw, True, 4);
2294 end;
2295 end;
2296 end;
2297 end;
2299 procedure g_Weapon_DestroyShot(I: Integer; X, Y: Integer; Loud: Boolean = True);
2300 var
2301 cx, cy: Integer;
2302 Anim: TAnimation;
2303 s: string;
2304 begin
2305 if Shots = nil then
2306 Exit;
2307 if (I > High(Shots)) or (I < 0) then Exit;
2309 with Shots[I] do
2310 begin
2311 if ShotType = 0 then Exit;
2312 Obj.X := X;
2313 Obj.Y := Y;
2314 cx := Obj.X + (Obj.Rect.Width div 2);
2315 cy := Obj.Y + (Obj.Rect.Height div 2);
2317 case ShotType of
2318 WEAPON_ROCKETLAUNCHER, WEAPON_SKEL_FIRE: // Ðàêåòû è ñíàðÿäû Ñêåëåòà
2319 begin
2320 if Loud then
2321 begin
2322 if ShotType = WEAPON_SKEL_FIRE then
2323 begin // Âçðûâ ñíàðÿäà Ñêåëåòà
2324 if g_Frames_Get(TextureID, 'FRAMES_EXPLODE_SKELFIRE') then
2325 begin
2326 Anim := TAnimation.Create(TextureID, False, 8);
2327 Anim.Blending := False;
2328 g_GFX_OnceAnim((Obj.X+32)-32, (Obj.Y+8)-32, Anim);
2329 Anim.Free();
2330 end;
2331 end
2332 else
2333 begin // Âçðûâ Ðàêåòû
2334 if g_Frames_Get(TextureID, 'FRAMES_EXPLODE_ROCKET') then
2335 begin
2336 Anim := TAnimation.Create(TextureID, False, 6);
2337 Anim.Blending := False;
2338 g_GFX_OnceAnim(cx-64, cy-64, Anim);
2339 Anim.Free();
2340 end;
2341 end;
2342 g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEROCKET', Obj.X, Obj.Y);
2343 end;
2344 end;
2346 WEAPON_PLASMA, WEAPON_BSP_FIRE: // Ïëàçìà, ïëàçìà Àðàõíàòðîíà
2347 begin
2348 if ShotType = WEAPON_PLASMA then
2349 s := 'FRAMES_EXPLODE_PLASMA'
2350 else
2351 s := 'FRAMES_EXPLODE_BSPFIRE';
2353 if g_Frames_Get(TextureID, s) and loud then
2354 begin
2355 Anim := TAnimation.Create(TextureID, False, 3);
2356 Anim.Blending := False;
2357 g_GFX_OnceAnim(cx-16, cy-16, Anim);
2358 Anim.Free();
2360 g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEPLASMA', Obj.X, Obj.Y);
2361 end;
2362 end;
2364 WEAPON_BFG: // BFG
2365 begin
2366 // Âçðûâ BFG:
2367 if g_Frames_Get(TextureID, 'FRAMES_EXPLODE_BFG') and Loud then
2368 begin
2369 Anim := TAnimation.Create(TextureID, False, 6);
2370 Anim.Blending := False;
2371 g_GFX_OnceAnim(cx-64, cy-64, Anim);
2372 Anim.Free();
2374 g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEBFG', Obj.X, Obj.Y);
2375 end;
2376 end;
2378 WEAPON_IMP_FIRE, WEAPON_CACO_FIRE, WEAPON_BARON_FIRE: // Âûñòðåëû Áåñà, Êàêîäåìîíà Ðûöàðÿ/Áàðîíà àäà
2379 begin
2380 if ShotType = WEAPON_IMP_FIRE then
2381 s := 'FRAMES_EXPLODE_IMPFIRE'
2382 else
2383 if ShotType = WEAPON_CACO_FIRE then
2384 s := 'FRAMES_EXPLODE_CACOFIRE'
2385 else
2386 s := 'FRAMES_EXPLODE_BARONFIRE';
2388 if g_Frames_Get(TextureID, s) and Loud then
2389 begin
2390 Anim := TAnimation.Create(TextureID, False, 6);
2391 Anim.Blending := False;
2392 g_GFX_OnceAnim(cx-32, cy-32, Anim);
2393 Anim.Free();
2395 g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEBALL', Obj.X, Obj.Y);
2396 end;
2397 end;
2399 WEAPON_MANCUB_FIRE: // Âûñòðåë Ìàíêóáóñà
2400 begin
2401 if g_Frames_Get(TextureID, 'FRAMES_EXPLODE_ROCKET') and Loud then
2402 begin
2403 Anim := TAnimation.Create(TextureID, False, 6);
2404 Anim.Blending := False;
2405 g_GFX_OnceAnim(cx-64, cy-64, Anim);
2406 Anim.Free();
2408 g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEBALL', Obj.X, Obj.Y);
2409 end;
2410 end;
2411 end; // case ShotType of...
2413 ShotType := 0;
2414 Animation.Free();
2415 end;
2416 end;
2418 end.