DEADSOFTWARE

added `.positionChanged()` to (almost) all entities; don't forget to call it after...
[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 {$INCLUDE ../shared/a_modes.inc}
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;
49 procedure positionChanged (); //WARNING! call this after monster position was changed, or coldet will not work right!
50 end;
53 var
54 Shots: array of TShot = nil;
55 LastShotID: Integer = 0;
57 procedure g_Weapon_LoadData();
58 procedure g_Weapon_FreeData();
59 procedure g_Weapon_Init();
60 procedure g_Weapon_Free();
61 function g_Weapon_Hit(obj: PObj; d: Integer; SpawnerUID: Word; t: Byte; HitCorpses: Boolean = True): Byte;
62 function g_Weapon_HitUID(UID: Word; d: Integer; SpawnerUID: Word; t: Byte): Boolean;
63 function g_Weapon_CreateShot(I: Integer; ShotType: Byte; Spawner, TargetUID: Word; X, Y, XV, YV: Integer): LongWord;
65 procedure g_Weapon_gun(x, y, xd, yd, v, dmg: Integer; SpawnerUID: Word; CheckTrigger: Boolean);
66 procedure g_Weapon_punch(x, y: Integer; d, SpawnerUID: Word);
67 function g_Weapon_chainsaw(x, y: Integer; d, SpawnerUID: Word): Integer;
68 procedure g_Weapon_rocket(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1; Silent: Boolean = False);
69 procedure g_Weapon_revf(x, y, xd, yd: Integer; SpawnerUID, TargetUID: Word; WID: Integer = -1; Silent: Boolean = False);
70 procedure g_Weapon_flame(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1; Silent: Boolean = False);
71 procedure g_Weapon_plasma(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1; Silent: Boolean = False);
72 procedure g_Weapon_ball1(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1; Silent: Boolean = False);
73 procedure g_Weapon_ball2(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1; Silent: Boolean = False);
74 procedure g_Weapon_ball7(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1; Silent: Boolean = False);
75 procedure g_Weapon_aplasma(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1; Silent: Boolean = False);
76 procedure g_Weapon_manfire(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1; Silent: Boolean = False);
77 procedure g_Weapon_bfgshot(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1; Silent: Boolean = False);
78 procedure g_Weapon_bfghit(x, y: Integer);
79 procedure g_Weapon_pistol(x, y, xd, yd: Integer; SpawnerUID: Word; Silent: Boolean = False);
80 procedure g_Weapon_mgun(x, y, xd, yd: Integer; SpawnerUID: Word; Silent: Boolean = False);
81 procedure g_Weapon_shotgun(x, y, xd, yd: Integer; SpawnerUID: Word; Silent: Boolean = False);
82 procedure g_Weapon_dshotgun(x, y, xd, yd: Integer; SpawnerUID: Word; Silent: Boolean = False);
84 function g_Weapon_Explode(X, Y: Integer; rad: Integer; SpawnerUID: Word): Boolean;
85 procedure g_Weapon_BFG9000(X, Y: Integer; SpawnerUID: Word);
86 procedure g_Weapon_Update();
87 procedure g_Weapon_Draw();
88 function g_Weapon_Danger(UID: Word; X, Y: Integer; Width, Height: Word; Time: Byte): Boolean;
89 procedure g_Weapon_DestroyShot(I: Integer; X, Y: Integer; Loud: Boolean = True);
91 procedure g_Weapon_SaveState(var Mem: TBinMemoryWriter);
92 procedure g_Weapon_LoadState(var Mem: TBinMemoryReader);
94 procedure g_Weapon_AddDynLights();
96 const
97 WEAPON_KASTET = 0;
98 WEAPON_SAW = 1;
99 WEAPON_PISTOL = 2;
100 WEAPON_SHOTGUN1 = 3;
101 WEAPON_SHOTGUN2 = 4;
102 WEAPON_CHAINGUN = 5;
103 WEAPON_ROCKETLAUNCHER = 6;
104 WEAPON_PLASMA = 7;
105 WEAPON_BFG = 8;
106 WEAPON_SUPERPULEMET = 9;
107 WEAPON_FLAMETHROWER = 10;
108 WEAPON_ZOMBY_PISTOL = 20;
109 WEAPON_IMP_FIRE = 21;
110 WEAPON_BSP_FIRE = 22;
111 WEAPON_CACO_FIRE = 23;
112 WEAPON_BARON_FIRE = 24;
113 WEAPON_MANCUB_FIRE = 25;
114 WEAPON_SKEL_FIRE = 26;
116 WP_FIRST = WEAPON_KASTET;
117 WP_LAST = WEAPON_FLAMETHROWER;
119 implementation
121 uses
122 Math, g_map, g_player, g_gfx, g_sound, g_main,
123 g_console, SysUtils, g_options, g_game,
124 g_triggers, MAPDEF, e_log, g_monsters, g_saveload,
125 g_language, g_netmsg;
127 type
128 TWaterPanel = record
129 X, Y: Integer;
130 Width, Height: Word;
131 Active: Boolean;
132 end;
134 const
135 SHOT_ROCKETLAUNCHER_WIDTH = 14;
136 SHOT_ROCKETLAUNCHER_HEIGHT = 14;
138 SHOT_SKELFIRE_WIDTH = 14;
139 SHOT_SKELFIRE_HEIGHT = 14;
141 SHOT_PLASMA_WIDTH = 16;
142 SHOT_PLASMA_HEIGHT = 16;
144 SHOT_BFG_WIDTH = 32;
145 SHOT_BFG_HEIGHT = 32;
146 SHOT_BFG_DAMAGE = 100;
147 SHOT_BFG_RADIUS = 256;
149 SHOT_FLAME_WIDTH = 4;
150 SHOT_FLAME_HEIGHT = 4;
151 SHOT_FLAME_LIFETIME = 180;
153 SHOT_SIGNATURE = $544F4853; // 'SHOT'
155 var
156 WaterMap: array of array of DWORD = nil;
158 function FindShot(): DWORD;
159 var
160 i: Integer;
161 begin
162 if Shots <> nil then
163 for i := 0 to High(Shots) do
164 if Shots[i].ShotType = 0 then
165 begin
166 Result := i;
167 LastShotID := Result;
168 Exit;
169 end;
171 if Shots = nil then
172 begin
173 SetLength(Shots, 128);
174 Result := 0;
175 end
176 else
177 begin
178 Result := High(Shots) + 1;
179 SetLength(Shots, Length(Shots) + 128);
180 end;
181 LastShotID := Result;
182 end;
184 procedure CreateWaterMap();
185 var
186 WaterArray: Array of TWaterPanel;
187 a, b, c, m: Integer;
188 ok: Boolean;
189 begin
190 if gWater = nil then
191 Exit;
193 SetLength(WaterArray, Length(gWater));
195 for a := 0 to High(gWater) do
196 begin
197 WaterArray[a].X := gWater[a].X;
198 WaterArray[a].Y := gWater[a].Y;
199 WaterArray[a].Width := gWater[a].Width;
200 WaterArray[a].Height := gWater[a].Height;
201 WaterArray[a].Active := True;
202 end;
204 g_Game_SetLoadingText(_lc[I_LOAD_WATER_MAP], High(WaterArray), False);
206 for a := 0 to High(WaterArray) do
207 if WaterArray[a].Active then
208 begin
209 WaterArray[a].Active := False;
210 m := Length(WaterMap);
211 SetLength(WaterMap, m+1);
212 SetLength(WaterMap[m], 1);
213 WaterMap[m][0] := a;
214 ok := True;
216 while ok do
217 begin
218 ok := False;
219 for b := 0 to High(WaterArray) do
220 if WaterArray[b].Active then
221 for c := 0 to High(WaterMap[m]) do
222 if g_CollideAround(WaterArray[b].X,
223 WaterArray[b].Y,
224 WaterArray[b].Width,
225 WaterArray[b].Height,
226 WaterArray[WaterMap[m][c]].X,
227 WaterArray[WaterMap[m][c]].Y,
228 WaterArray[WaterMap[m][c]].Width,
229 WaterArray[WaterMap[m][c]].Height) then
230 begin
231 WaterArray[b].Active := False;
232 SetLength(WaterMap[m],
233 Length(WaterMap[m])+1);
234 WaterMap[m][High(WaterMap[m])] := b;
235 ok := True;
236 Break;
237 end;
238 end;
240 g_Game_StepLoading();
241 end;
243 WaterArray := nil;
244 end;
246 procedure CheckTrap(ID: DWORD; dm: Integer; t: Byte);
247 var
248 a, b, c, d, i1, i2: Integer;
249 pl, mn: WArray;
250 begin
251 if (gWater = nil) or (WaterMap = nil) then Exit;
253 i1 := -1;
254 i2 := -1;
256 SetLength(pl, 1024);
257 SetLength(mn, 1024);
258 for d := 0 to 1023 do pl[d] := $FFFF;
259 for d := 0 to 1023 do mn[d] := $FFFF;
261 for a := 0 to High(WaterMap) do
262 for b := 0 to High(WaterMap[a]) do
263 begin
264 if not g_Obj_Collide(gWater[WaterMap[a][b]].X, gWater[WaterMap[a][b]].Y,
265 gWater[WaterMap[a][b]].Width, gWater[WaterMap[a][b]].Height,
266 @Shots[ID].Obj) then Continue;
268 for c := 0 to High(WaterMap[a]) do
269 begin
270 if gPlayers <> nil then
271 begin
272 for d := 0 to High(gPlayers) do
273 if (gPlayers[d] <> nil) and (gPlayers[d].Live) then
274 if gPlayers[d].Collide(gWater[WaterMap[a][c]]) then
275 if not InWArray(d, pl) then
276 if i1 < 1023 then
277 begin
278 i1 := i1+1;
279 pl[i1] := d;
280 end;
281 end;
283 if gMonsters <> nil then
284 begin
285 for d := 0 to High(gMonsters) do
286 if (gMonsters[d] <> nil) and (gMonsters[d].Live) then
287 if gMonsters[d].Collide(gWater[WaterMap[a][c]]) then
288 if not InWArray(d, mn) then
289 if i2 < 1023 then
290 begin
291 i2 := i2+1;
292 mn[i2] := d;
293 end;
294 end;
295 end;
297 if i1 <> -1 then
298 for d := 0 to i1 do
299 gPlayers[pl[d]].Damage(dm, Shots[ID].SpawnerUID, 0, 0, t);
301 if i2 <> -1 then
302 for d := 0 to i2 do
303 gMonsters[mn[d]].Damage(dm, 0, 0, Shots[ID].SpawnerUID, t);
304 end;
306 pl := nil;
307 mn := nil;
308 end;
310 function HitMonster(m: TMonster; d: Integer; vx, vy: Integer; SpawnerUID: Word; t: Byte): Boolean;
311 var
312 tt, mt: Byte;
313 mon: TMonster;
314 begin
315 Result := False;
317 tt := g_GetUIDType(SpawnerUID);
318 if tt = UID_MONSTER then
319 begin
320 mon := g_Monsters_Get(SpawnerUID);
321 if mon <> nil then
322 mt := g_Monsters_Get(SpawnerUID).MonsterType
323 else
324 mt := 0;
325 end
326 else
327 mt := 0;
329 if m = nil then Exit;
330 if m.UID = SpawnerUID then
331 begin
332 // Ñàì ñåáÿ ìîæåò ðàíèòü òîëüêî ðàêåòîé è òîêîì:
333 if (t <> HIT_ROCKET) and (t <> HIT_ELECTRO) then
334 Exit;
335 // Êèáåð äåìîí è áî÷êà âîîáùå íå ìîãóò ñåáÿ ðàíèòü:
336 if (m.MonsterType = MONSTER_CYBER) or
337 (m.MonsterType = MONSTER_BARREL) then
338 begin
339 Result := True;
340 Exit;
341 end;
342 end;
344 if tt = UID_MONSTER then
345 begin
346 // Lost_Soul íå ìîæåò ðàíèòü Pain_Elemental'à:
347 if (mt = MONSTER_SOUL) and (m.MonsterType = MONSTER_PAIN) then
348 Exit;
350 // Îáà ìîíñòðà îäíîãî âèäà:
351 if mt = m.MonsterType then
352 case mt of
353 MONSTER_IMP, MONSTER_DEMON, MONSTER_BARON, MONSTER_KNIGHT, MONSTER_CACO,
354 MONSTER_SOUL, MONSTER_MANCUB, MONSTER_SKEL, MONSTER_FISH:
355 Exit; // Ýòè íå áüþò ñâîèõ
356 end;
357 end;
359 if g_Game_IsServer then
360 begin
361 if (t <> HIT_FLAME) or (m.FFireTime = 0) or (vx <> 0) or (vy <> 0) then
362 Result := m.Damage(d, vx, vy, SpawnerUID, t)
363 else
364 Result := True;
365 if t = HIT_FLAME then
366 m.CatchFire(SpawnerUID);
367 end
368 else
369 Result := True;
370 end;
372 function HitPlayer(p: TPlayer; d: Integer; vx, vy: Integer; SpawnerUID: Word; t: Byte): Boolean;
373 begin
374 Result := False;
376 // Ñàì ñåáÿ ìîæåò ðàíèòü òîëüêî ðàêåòîé è òîêîì:
377 if (p.UID = SpawnerUID) and (t <> HIT_ROCKET) and (t <> HIT_ELECTRO) then
378 Exit;
380 if g_Game_IsServer then
381 begin
382 if (t <> HIT_FLAME) or (p.FFireTime = 0) or (vx <> 0) or (vy <> 0) then
383 p.Damage(d, SpawnerUID, vx, vy, t);
384 if (t = HIT_FLAME) then
385 p.CatchFire(SpawnerUID);
386 end;
388 Result := True;
389 end;
391 function GunHit(X, Y: Integer; vx, vy: Integer; dmg: Integer;
392 SpawnerUID: Word; AllowPush: Boolean): Byte;
393 var
394 i, h: Integer;
395 begin
396 Result := 0;
398 h := High(gPlayers);
400 if h <> -1 then
401 for i := 0 to h do
402 if (gPlayers[i] <> nil) and gPlayers[i].Live and gPlayers[i].Collide(X, Y) then
403 if HitPlayer(gPlayers[i], dmg, vx*10, vy*10-3, SpawnerUID, HIT_SOME) then
404 begin
405 if AllowPush then gPlayers[i].Push(vx, vy);
406 Result := 1;
407 end;
409 if Result <> 0 then Exit;
411 h := High(gMonsters);
413 if h <> -1 then
414 for i := 0 to h do
415 if (gMonsters[i] <> nil) and gMonsters[i].Live and gMonsters[i].Collide(X, Y) then
416 if HitMonster(gMonsters[i], dmg, vx*10, vy*10-3, SpawnerUID, HIT_SOME) then
417 begin
418 if AllowPush then gMonsters[i].Push(vx, vy);
419 Result := 2;
420 Exit;
421 end;
422 end;
424 procedure g_Weapon_BFG9000(X, Y: Integer; SpawnerUID: Word);
425 var
426 i, h: Integer;
427 st: Byte;
428 pl: TPlayer;
429 b: Boolean;
430 begin
431 //g_Sound_PlayEx('SOUND_WEAPON_EXPLODEBFG', 255);
433 h := High(gCorpses);
435 if gAdvCorpses and (h <> -1) then
436 for i := 0 to h do
437 if (gCorpses[i] <> nil) and (gCorpses[i].State <> CORPSE_STATE_REMOVEME) then
438 with gCorpses[i] do
439 if (g_PatchLength(X, Y, Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2),
440 Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)) <= SHOT_BFG_RADIUS) and
441 g_TraceVector(X, Y, Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2),
442 Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)) then
443 begin
444 Damage(50, 0, 0);
445 g_Weapon_BFGHit(Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2),
446 Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2));
447 end;
449 st := TEAM_NONE;
450 pl := g_Player_Get(SpawnerUID);
451 if pl <> nil then
452 st := pl.Team;
454 h := High(gPlayers);
456 if h <> -1 then
457 for i := 0 to h do
458 if (gPlayers[i] <> nil) and (gPlayers[i].Live) and (gPlayers[i].UID <> SpawnerUID) then
459 with gPlayers[i] do
460 if (g_PatchLength(X, Y, GameX+PLAYER_RECT.X+(PLAYER_RECT.Width div 2),
461 GameY+PLAYER_RECT.Y+(PLAYER_RECT.Height div 2)) <= SHOT_BFG_RADIUS) and
462 g_TraceVector(X, Y, GameX+PLAYER_RECT.X+(PLAYER_RECT.Width div 2),
463 GameY+PLAYER_RECT.Y+(PLAYER_RECT.Height div 2)) then
464 begin
465 if (st = TEAM_NONE) or (st <> gPlayers[i].Team) then
466 b := HitPlayer(gPlayers[i], 50, 0, 0, SpawnerUID, HIT_SOME)
467 else
468 b := HitPlayer(gPlayers[i], 25, 0, 0, SpawnerUID, HIT_SOME);
469 if b then
470 gPlayers[i].BFGHit();
471 end;
473 h := High(gMonsters);
475 if h <> -1 then
476 for i := 0 to h do
477 if (gMonsters[i] <> nil) and (gMonsters[i].Live) and (gMonsters[i].UID <> SpawnerUID) then
478 with gMonsters[i] do
479 if (g_PatchLength(X, Y, Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2),
480 Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)) <= SHOT_BFG_RADIUS) and
481 g_TraceVector(X, Y, Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2),
482 Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)) then
483 if HitMonster(gMonsters[i], 50, 0, 0, SpawnerUID, HIT_SOME) then gMonsters[i].BFGHit();
484 end;
486 function g_Weapon_CreateShot(I: Integer; ShotType: Byte; Spawner, TargetUID: Word; X, Y, XV, YV: Integer): LongWord;
487 var
488 find_id, FramesID: DWORD;
489 begin
490 if I < 0 then
491 find_id := FindShot()
492 else
493 begin
494 find_id := I;
495 if Integer(find_id) >= High(Shots) then
496 SetLength(Shots, find_id + 64)
497 end;
499 case ShotType of
500 WEAPON_ROCKETLAUNCHER:
501 begin
502 with Shots[find_id] do
503 begin
504 g_Obj_Init(@Obj);
506 Obj.Rect.Width := SHOT_ROCKETLAUNCHER_WIDTH;
507 Obj.Rect.Height := SHOT_ROCKETLAUNCHER_HEIGHT;
509 Animation := nil;
510 Triggers := nil;
511 ShotType := WEAPON_ROCKETLAUNCHER;
512 g_Texture_Get('TEXTURE_WEAPON_ROCKET', TextureID);
513 end;
514 end;
516 WEAPON_PLASMA:
517 begin
518 with Shots[find_id] do
519 begin
520 g_Obj_Init(@Obj);
522 Obj.Rect.Width := SHOT_PLASMA_WIDTH;
523 Obj.Rect.Height := SHOT_PLASMA_HEIGHT;
525 Triggers := nil;
526 ShotType := WEAPON_PLASMA;
527 g_Frames_Get(FramesID, 'FRAMES_WEAPON_PLASMA');
528 Animation := TAnimation.Create(FramesID, True, 5);
529 end;
530 end;
532 WEAPON_BFG:
533 begin
534 with Shots[find_id] do
535 begin
536 g_Obj_Init(@Obj);
538 Obj.Rect.Width := SHOT_BFG_WIDTH;
539 Obj.Rect.Height := SHOT_BFG_HEIGHT;
541 Triggers := nil;
542 ShotType := WEAPON_BFG;
543 g_Frames_Get(FramesID, 'FRAMES_WEAPON_BFG');
544 Animation := TAnimation.Create(FramesID, True, 6);
545 end;
546 end;
548 WEAPON_FLAMETHROWER:
549 begin
550 with Shots[find_id] do
551 begin
552 g_Obj_Init(@Obj);
554 Obj.Rect.Width := SHOT_FLAME_WIDTH;
555 Obj.Rect.Height := SHOT_FLAME_HEIGHT;
557 Triggers := nil;
558 ShotType := WEAPON_FLAMETHROWER;
559 Animation := nil;
560 TextureID := 0;
561 g_Frames_Get(TextureID, 'FRAMES_FLAME');
562 end;
563 end;
565 WEAPON_IMP_FIRE:
566 begin
567 with Shots[find_id] do
568 begin
569 g_Obj_Init(@Obj);
571 Obj.Rect.Width := 16;
572 Obj.Rect.Height := 16;
574 Triggers := nil;
575 ShotType := WEAPON_IMP_FIRE;
576 g_Frames_Get(FramesID, 'FRAMES_WEAPON_IMPFIRE');
577 Animation := TAnimation.Create(FramesID, True, 4);
578 end;
579 end;
581 WEAPON_CACO_FIRE:
582 begin
583 with Shots[find_id] do
584 begin
585 g_Obj_Init(@Obj);
587 Obj.Rect.Width := 16;
588 Obj.Rect.Height := 16;
590 Triggers := nil;
591 ShotType := WEAPON_CACO_FIRE;
592 g_Frames_Get(FramesID, 'FRAMES_WEAPON_CACOFIRE');
593 Animation := TAnimation.Create(FramesID, True, 4);
594 end;
595 end;
597 WEAPON_MANCUB_FIRE:
598 begin
599 with Shots[find_id] do
600 begin
601 g_Obj_Init(@Obj);
603 Obj.Rect.Width := 32;
604 Obj.Rect.Height := 32;
606 Triggers := nil;
607 ShotType := WEAPON_MANCUB_FIRE;
608 g_Frames_Get(FramesID, 'FRAMES_WEAPON_MANCUBFIRE');
609 Animation := TAnimation.Create(FramesID, True, 4);
610 end;
611 end;
613 WEAPON_BARON_FIRE:
614 begin
615 with Shots[find_id] do
616 begin
617 g_Obj_Init(@Obj);
619 Obj.Rect.Width := 32;
620 Obj.Rect.Height := 16;
622 Triggers := nil;
623 ShotType := WEAPON_BARON_FIRE;
624 g_Frames_Get(FramesID, 'FRAMES_WEAPON_BARONFIRE');
625 Animation := TAnimation.Create(FramesID, True, 4);
626 end;
627 end;
629 WEAPON_BSP_FIRE:
630 begin
631 with Shots[find_id] do
632 begin
633 g_Obj_Init(@Obj);
635 Obj.Rect.Width := 16;
636 Obj.Rect.Height := 16;
638 Triggers := nil;
639 ShotType := WEAPON_BSP_FIRE;
640 g_Frames_Get(FramesID, 'FRAMES_WEAPON_BSPFIRE');
641 Animation := TAnimation.Create(FramesID, True, 4);
642 end;
643 end;
645 WEAPON_SKEL_FIRE:
646 begin
647 with Shots[find_id] do
648 begin
649 g_Obj_Init(@Obj);
651 Obj.Rect.Width := SHOT_SKELFIRE_WIDTH;
652 Obj.Rect.Height := SHOT_SKELFIRE_HEIGHT;
654 Triggers := nil;
655 ShotType := WEAPON_SKEL_FIRE;
656 target := TargetUID;
657 g_Frames_Get(FramesID, 'FRAMES_WEAPON_SKELFIRE');
658 Animation := TAnimation.Create(FramesID, True, 5);
659 end;
660 end;
661 end;
663 Shots[find_id].Obj.X := X;
664 Shots[find_id].Obj.Y := Y;
665 Shots[find_id].Obj.Vel.X := XV;
666 Shots[find_id].Obj.Vel.Y := YV;
667 Shots[find_id].Obj.Accel.X := 0;
668 Shots[find_id].Obj.Accel.Y := 0;
669 Shots[find_id].SpawnerUID := Spawner;
670 if (ShotType = WEAPON_FLAMETHROWER) and (XV = 0) and (YV = 0) then
671 Shots[find_id].Stopped := 255
672 else
673 Shots[find_id].Stopped := 0;
674 Result := find_id;
675 end;
677 procedure throw(i, x, y, xd, yd, s: Integer);
678 var
679 a: Integer;
680 begin
681 yd := yd - y;
682 xd := xd - x;
684 a := Max(Abs(xd), Abs(yd));
685 if a = 0 then
686 a := 1;
688 Shots[i].Obj.X := x;
689 Shots[i].Obj.Y := y;
690 Shots[i].Obj.Vel.X := (xd*s) div a;
691 Shots[i].Obj.Vel.Y := (yd*s) div a;
692 Shots[i].Obj.Accel.X := 0;
693 Shots[i].Obj.Accel.Y := 0;
694 Shots[i].Stopped := 0;
695 if Shots[i].ShotType in [WEAPON_ROCKETLAUNCHER, WEAPON_BFG] then
696 Shots[i].Timeout := 900 // ~25 sec
697 else
698 begin
699 if Shots[i].ShotType = WEAPON_FLAMETHROWER then
700 Shots[i].Timeout := SHOT_FLAME_LIFETIME
701 else
702 Shots[i].Timeout := 550; // ~15 sec
703 end;
704 end;
706 function g_Weapon_Hit(obj: PObj; d: Integer; SpawnerUID: Word; t: Byte; HitCorpses: Boolean = True): Byte;
707 var
708 i, h: Integer;
710 function PlayerHit(Team: Byte = 0): Boolean;
711 var
712 i: Integer;
713 ChkTeam: Boolean;
714 p: TPlayer;
715 begin
716 Result := False;
717 h := High(gPlayers);
719 if h <> -1 then
720 for i := 0 to h do
721 if (gPlayers[i] <> nil) and gPlayers[i].Live and g_Obj_Collide(obj, @gPlayers[i].Obj) then
722 begin
723 ChkTeam := True;
724 if (Team > 0) and (g_GetUIDType(SpawnerUID) = UID_PLAYER) then
725 begin
726 p := g_Player_Get(SpawnerUID);
727 if p <> nil then
728 ChkTeam := (p.Team = gPlayers[i].Team) xor (Team = 2);
729 end;
730 if ChkTeam then
731 if HitPlayer(gPlayers[i], d, obj^.Vel.X, obj^.Vel.Y, SpawnerUID, t) then
732 begin
733 if t <> HIT_FLAME then
734 gPlayers[i].Push((obj^.Vel.X+obj^.Accel.X)*IfThen(t = HIT_BFG, 8, 1) div 4,
735 (obj^.Vel.Y+obj^.Accel.Y)*IfThen(t = HIT_BFG, 8, 1) div 4);
736 if t = HIT_BFG then
737 g_Game_DelayEvent(DE_BFGHIT, 1000, SpawnerUID);
738 Result := True;
739 break;
740 end;
741 end;
742 end;
743 function MonsterHit(): Boolean;
744 var
745 i: Integer;
746 begin
747 Result := False;
748 h := High(gMonsters);
750 if h <> -1 then
751 for i := 0 to h do
752 if (gMonsters[i] <> nil) and gMonsters[i].Live and g_Obj_Collide(obj, @gMonsters[i].Obj) then
753 if HitMonster(gMonsters[i], d, obj^.Vel.X, obj^.Vel.Y, SpawnerUID, t) then
754 begin
755 if t <> HIT_FLAME then
756 gMonsters[i].Push((obj^.Vel.X+obj^.Accel.X)*IfThen(t = HIT_BFG, 8, 1) div 4,
757 (obj^.Vel.Y+obj^.Accel.Y)*IfThen(t = HIT_BFG, 8, 1) div 4);
758 Result := True;
759 break;
760 end;
761 end;
762 begin
763 Result := 0;
765 if HitCorpses then
766 begin
767 h := High(gCorpses);
769 if gAdvCorpses and (h <> -1) then
770 for i := 0 to h do
771 if (gCorpses[i] <> nil) and (gCorpses[i].State <> CORPSE_STATE_REMOVEME) and
772 g_Obj_Collide(obj, @gCorpses[i].Obj) then
773 begin
774 // Ðàñïèëèâàåì òðóï:
775 gCorpses[i].Damage(d, (obj^.Vel.X+obj^.Accel.X) div 4,
776 (obj^.Vel.Y+obj^.Accel.Y) div 4);
777 Result := 1;
778 end;
779 end;
781 case gGameSettings.GameMode of
782 // Êàìïàíèÿ:
783 GM_COOP, GM_SINGLE:
784 begin
785 // Ñíà÷àëà áü¸ì ìîíñòðîâ, åñëè åñòü, ïîòîì ïûòàåìñÿ áèòü èãðîêîâ
786 if MonsterHit() then
787 begin
788 Result := 2;
789 Exit;
790 end;
792 if PlayerHit() then
793 begin
794 Result := 1;
795 Exit;
796 end;
797 end;
799 // Äåçìàò÷:
800 GM_DM:
801 begin
802 // Ñíà÷àëà áü¸ì èãðîêîâ, åñëè åñòü, ïîòîì ïûòàåìñÿ áèòü ìîíñòðîâ
803 if PlayerHit() then
804 begin
805 Result := 1;
806 Exit;
807 end;
809 if MonsterHit() then
810 begin
811 Result := 2;
812 Exit;
813 end;
814 end;
816 // Êîìàíäíûå:
817 GM_TDM, GM_CTF:
818 begin
819 // Ñíà÷àëà áü¸ì èãðîêîâ êîìàíäû ñîïåðíèêà
820 if PlayerHit(2) then
821 begin
822 Result := 1;
823 Exit;
824 end;
826 // Ïîòîì ìîíñòðîâ
827 if MonsterHit() then
828 begin
829 Result := 2;
830 Exit;
831 end;
833 // È â êîíöå ñâîèõ èãðîêîâ
834 if PlayerHit(1) then
835 begin
836 Result := 1;
837 Exit;
838 end;
839 end;
841 end;
842 end;
844 function g_Weapon_HitUID(UID: Word; d: Integer; SpawnerUID: Word; t: Byte): Boolean;
845 begin
846 Result := False;
848 case g_GetUIDType(UID) of
849 UID_PLAYER: Result := HitPlayer(g_Player_Get(UID), d, 0, 0, SpawnerUID, t);
850 UID_MONSTER: Result := HitMonster(g_Monsters_Get(UID), d, 0, 0, SpawnerUID, t);
851 else Exit;
852 end;
853 end;
855 function g_Weapon_Explode(X, Y: Integer; rad: Integer; SpawnerUID: Word): Boolean;
856 var
857 i, h, r, dx, dy, m, mm: Integer;
858 _angle: SmallInt;
859 begin
860 Result := False;
862 g_Triggers_PressC(X, Y, rad, SpawnerUID, ACTIVATE_SHOT);
864 r := rad*rad;
866 h := High(gPlayers);
868 if h <> -1 then
869 for i := 0 to h do
870 if (gPlayers[i] <> nil) and gPlayers[i].Live then
871 with gPlayers[i] do
872 begin
873 dx := Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2)-X;
874 dy := Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)-Y;
876 if dx > 1000 then dx := 1000;
877 if dy > 1000 then dy := 1000;
879 if dx*dx+dy*dy < r then
880 begin
881 //m := PointToRect(X, Y, GameX+PLAYER_RECT.X, GameY+PLAYER_RECT.Y,
882 // PLAYER_RECT.Width, PLAYER_RECT.Height);
884 mm := Max(abs(dx), abs(dy));
885 if mm = 0 then mm := 1;
887 HitPlayer(gPlayers[i], (100*(rad-mm)) div rad, (dx*10) div mm, (dy*10) div mm, SpawnerUID, HIT_ROCKET);
888 gPlayers[i].Push((dx*7) div mm, (dy*7) div mm);
889 end;
890 end;
892 h := High(gMonsters);
894 if h <> -1 then
895 for i := 0 to h do
896 if gMonsters[i] <> nil then
897 with gMonsters[i] do
898 begin
899 dx := Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2)-X;
900 dy := Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)-Y;
902 if dx > 1000 then dx := 1000;
903 if dy > 1000 then dy := 1000;
905 if dx*dx+dy*dy < r then
906 begin
907 //m := PointToRect(X, Y, Obj.X+Obj.Rect.X, Obj.Y+Obj.Rect.Y,
908 // Obj.Rect.Width, Obj.Rect.Height);
910 mm := Max(abs(dx), abs(dy));
911 if mm = 0 then mm := 1;
913 if gMonsters[i].Live then
914 HitMonster(gMonsters[i], ((gMonsters[i].Obj.Rect.Width div 4)*10*(rad-mm)) div rad,
915 0, 0, SpawnerUID, HIT_ROCKET);
917 gMonsters[i].Push((dx*7) div mm, (dy*7) div mm);
918 end;
919 end;
921 h := High(gCorpses);
923 if gAdvCorpses and (h <> -1) then
924 for i := 0 to h do
925 if (gCorpses[i] <> nil) and (gCorpses[i].State <> CORPSE_STATE_REMOVEME) then
926 with gCorpses[i] do
927 begin
928 dx := Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2)-X;
929 dy := Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)-Y;
931 if dx > 1000 then dx := 1000;
932 if dy > 1000 then dy := 1000;
934 if dx*dx+dy*dy < r then
935 begin
936 m := PointToRect(X, Y, Obj.X+Obj.Rect.X, Obj.Y+Obj.Rect.Y,
937 Obj.Rect.Width, Obj.Rect.Height);
939 mm := Max(abs(dx), abs(dy));
940 if mm = 0 then mm := 1;
942 Damage(Round(100*(rad-m)/rad), (dx*10) div mm, (dy*10) div mm);
943 end;
944 end;
946 h := High(gGibs);
948 if gAdvGibs and (h <> -1) then
949 for i := 0 to h do
950 if gGibs[i].Live then
951 with gGibs[i] do
952 begin
953 dx := Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2)-X;
954 dy := Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2)-Y;
956 if dx > 1000 then dx := 1000;
957 if dy > 1000 then dy := 1000;
959 if dx*dx+dy*dy < r then
960 begin
961 m := PointToRect(X, Y, Obj.X+Obj.Rect.X, Obj.Y+Obj.Rect.Y,
962 Obj.Rect.Width, Obj.Rect.Height);
963 _angle := GetAngle(Obj.X+Obj.Rect.X+(Obj.Rect.Width div 2),
964 Obj.Y+Obj.Rect.Y+(Obj.Rect.Height div 2), X, Y);
966 g_Obj_PushA(@Obj, Round(15*(rad-m)/rad), _angle);
967 positionChanged(); // this updates spatial accelerators
968 end;
969 end;
970 end;
972 procedure g_Weapon_Init();
973 begin
974 CreateWaterMap();
975 end;
977 procedure g_Weapon_Free();
978 var
979 i: Integer;
980 begin
981 if Shots <> nil then
982 begin
983 for i := 0 to High(Shots) do
984 if Shots[i].ShotType <> 0 then
985 Shots[i].Animation.Free();
987 Shots := nil;
988 end;
990 WaterMap := nil;
991 end;
993 procedure g_Weapon_LoadData();
994 begin
995 e_WriteLog('Loading weapons data...', MSG_NOTIFY);
997 g_Sound_CreateWADEx('SOUND_WEAPON_HITPUNCH', GameWAD+':SOUNDS\HITPUNCH');
998 g_Sound_CreateWADEx('SOUND_WEAPON_MISSPUNCH', GameWAD+':SOUNDS\MISSPUNCH');
999 g_Sound_CreateWADEx('SOUND_WEAPON_HITBERSERK', GameWAD+':SOUNDS\HITBERSERK');
1000 g_Sound_CreateWADEx('SOUND_WEAPON_MISSBERSERK', GameWAD+':SOUNDS\MISSBERSERK');
1001 g_Sound_CreateWADEx('SOUND_WEAPON_SELECTSAW', GameWAD+':SOUNDS\SELECTSAW');
1002 g_Sound_CreateWADEx('SOUND_WEAPON_IDLESAW', GameWAD+':SOUNDS\IDLESAW');
1003 g_Sound_CreateWADEx('SOUND_WEAPON_HITSAW', GameWAD+':SOUNDS\HITSAW');
1004 g_Sound_CreateWADEx('SOUND_WEAPON_FIRESHOTGUN2', GameWAD+':SOUNDS\FIRESHOTGUN2');
1005 g_Sound_CreateWADEx('SOUND_WEAPON_FIRESHOTGUN', GameWAD+':SOUNDS\FIRESHOTGUN');
1006 g_Sound_CreateWADEx('SOUND_WEAPON_FIRESAW', GameWAD+':SOUNDS\FIRESAW');
1007 g_Sound_CreateWADEx('SOUND_WEAPON_FIREROCKET', GameWAD+':SOUNDS\FIREROCKET');
1008 g_Sound_CreateWADEx('SOUND_WEAPON_FIREPLASMA', GameWAD+':SOUNDS\FIREPLASMA');
1009 g_Sound_CreateWADEx('SOUND_WEAPON_FIREPISTOL', GameWAD+':SOUNDS\FIREPISTOL');
1010 g_Sound_CreateWADEx('SOUND_WEAPON_FIRECGUN', GameWAD+':SOUNDS\FIRECGUN');
1011 g_Sound_CreateWADEx('SOUND_WEAPON_FIREBFG', GameWAD+':SOUNDS\FIREBFG');
1012 g_Sound_CreateWADEx('SOUND_FIRE', GameWAD+':SOUNDS\FIRE');
1013 g_Sound_CreateWADEx('SOUND_WEAPON_STARTFIREBFG', GameWAD+':SOUNDS\STARTFIREBFG');
1014 g_Sound_CreateWADEx('SOUND_WEAPON_EXPLODEROCKET', GameWAD+':SOUNDS\EXPLODEROCKET');
1015 g_Sound_CreateWADEx('SOUND_WEAPON_EXPLODEBFG', GameWAD+':SOUNDS\EXPLODEBFG');
1016 g_Sound_CreateWADEx('SOUND_WEAPON_BFGWATER', GameWAD+':SOUNDS\BFGWATER');
1017 g_Sound_CreateWADEx('SOUND_WEAPON_EXPLODEPLASMA', GameWAD+':SOUNDS\EXPLODEPLASMA');
1018 g_Sound_CreateWADEx('SOUND_WEAPON_PLASMAWATER', GameWAD+':SOUNDS\PLASMAWATER');
1019 g_Sound_CreateWADEx('SOUND_WEAPON_FIREBALL', GameWAD+':SOUNDS\FIREBALL');
1020 g_Sound_CreateWADEx('SOUND_WEAPON_EXPLODEBALL', GameWAD+':SOUNDS\EXPLODEBALL');
1021 g_Sound_CreateWADEx('SOUND_WEAPON_FIREREV', GameWAD+':SOUNDS\FIREREV');
1022 g_Sound_CreateWADEx('SOUND_PLAYER_JETFLY', GameWAD+':SOUNDS\WORKJETPACK');
1023 g_Sound_CreateWADEx('SOUND_PLAYER_JETON', GameWAD+':SOUNDS\STARTJETPACK');
1024 g_Sound_CreateWADEx('SOUND_PLAYER_JETOFF', GameWAD+':SOUNDS\STOPJETPACK');
1025 g_Sound_CreateWADEx('SOUND_PLAYER_CASING1', GameWAD+':SOUNDS\CASING1');
1026 g_Sound_CreateWADEx('SOUND_PLAYER_CASING2', GameWAD+':SOUNDS\CASING2');
1027 g_Sound_CreateWADEx('SOUND_PLAYER_SHELL1', GameWAD+':SOUNDS\SHELL1');
1028 g_Sound_CreateWADEx('SOUND_PLAYER_SHELL2', GameWAD+':SOUNDS\SHELL2');
1030 g_Texture_CreateWADEx('TEXTURE_WEAPON_ROCKET', GameWAD+':TEXTURES\BROCKET');
1031 g_Frames_CreateWAD(nil, 'FRAMES_WEAPON_SKELFIRE', GameWAD+':TEXTURES\BSKELFIRE', 64, 16, 2);
1032 g_Frames_CreateWAD(nil, 'FRAMES_WEAPON_BFG', GameWAD+':TEXTURES\BBFG', 64, 64, 2);
1033 g_Frames_CreateWAD(nil, 'FRAMES_WEAPON_PLASMA', GameWAD+':TEXTURES\BPLASMA', 16, 16, 2);
1034 g_Frames_CreateWAD(nil, 'FRAMES_WEAPON_IMPFIRE', GameWAD+':TEXTURES\BIMPFIRE', 16, 16, 2);
1035 g_Frames_CreateWAD(nil, 'FRAMES_WEAPON_BSPFIRE', GameWAD+':TEXTURES\BBSPFIRE', 16, 16, 2);
1036 g_Frames_CreateWAD(nil, 'FRAMES_WEAPON_CACOFIRE', GameWAD+':TEXTURES\BCACOFIRE', 16, 16, 2);
1037 g_Frames_CreateWAD(nil, 'FRAMES_WEAPON_BARONFIRE', GameWAD+':TEXTURES\BBARONFIRE', 64, 16, 2);
1038 g_Frames_CreateWAD(nil, 'FRAMES_WEAPON_MANCUBFIRE', GameWAD+':TEXTURES\BMANCUBFIRE', 64, 32, 2);
1039 g_Frames_CreateWAD(nil, 'FRAMES_EXPLODE_ROCKET', GameWAD+':TEXTURES\EROCKET', 128, 128, 6);
1040 g_Frames_CreateWAD(nil, 'FRAMES_EXPLODE_SKELFIRE', GameWAD+':TEXTURES\ESKELFIRE', 64, 64, 3);
1041 g_Frames_CreateWAD(nil, 'FRAMES_EXPLODE_BFG', GameWAD+':TEXTURES\EBFG', 128, 128, 6);
1042 g_Frames_CreateWAD(nil, 'FRAMES_EXPLODE_IMPFIRE', GameWAD+':TEXTURES\EIMPFIRE', 64, 64, 3);
1043 g_Frames_CreateWAD(nil, 'FRAMES_BFGHIT', GameWAD+':TEXTURES\BFGHIT', 64, 64, 4);
1044 g_Frames_CreateWAD(nil, 'FRAMES_FIRE', GameWAD+':TEXTURES\FIRE', 64, 128, 8);
1045 g_Frames_CreateWAD(nil, 'FRAMES_FLAME', GameWAD+':TEXTURES\FLAME', 32, 32, 11);
1046 g_Frames_CreateWAD(nil, 'FRAMES_EXPLODE_PLASMA', GameWAD+':TEXTURES\EPLASMA', 32, 32, 4, True);
1047 g_Frames_CreateWAD(nil, 'FRAMES_EXPLODE_BSPFIRE', GameWAD+':TEXTURES\EBSPFIRE', 32, 32, 5);
1048 g_Frames_CreateWAD(nil, 'FRAMES_EXPLODE_CACOFIRE', GameWAD+':TEXTURES\ECACOFIRE', 64, 64, 3);
1049 g_Frames_CreateWAD(nil, 'FRAMES_EXPLODE_BARONFIRE', GameWAD+':TEXTURES\EBARONFIRE', 64, 64, 3);
1050 g_Frames_CreateWAD(nil, 'FRAMES_SMOKE', GameWAD+':TEXTURES\SMOKE', 32, 32, 10, False);
1052 g_Texture_CreateWADEx('TEXTURE_SHELL_BULLET', GameWAD+':TEXTURES\EBULLET');
1053 g_Texture_CreateWADEx('TEXTURE_SHELL_SHELL', GameWAD+':TEXTURES\ESHELL');
1054 end;
1056 procedure g_Weapon_FreeData();
1057 begin
1058 e_WriteLog('Releasing weapons data...', MSG_NOTIFY);
1060 g_Sound_Delete('SOUND_WEAPON_HITPUNCH');
1061 g_Sound_Delete('SOUND_WEAPON_MISSPUNCH');
1062 g_Sound_Delete('SOUND_WEAPON_HITBERSERK');
1063 g_Sound_Delete('SOUND_WEAPON_MISSBERSERK');
1064 g_Sound_Delete('SOUND_WEAPON_SELECTSAW');
1065 g_Sound_Delete('SOUND_WEAPON_IDLESAW');
1066 g_Sound_Delete('SOUND_WEAPON_HITSAW');
1067 g_Sound_Delete('SOUND_WEAPON_FIRESHOTGUN2');
1068 g_Sound_Delete('SOUND_WEAPON_FIRESHOTGUN');
1069 g_Sound_Delete('SOUND_WEAPON_FIRESAW');
1070 g_Sound_Delete('SOUND_WEAPON_FIREROCKET');
1071 g_Sound_Delete('SOUND_WEAPON_FIREPLASMA');
1072 g_Sound_Delete('SOUND_WEAPON_FIREPISTOL');
1073 g_Sound_Delete('SOUND_WEAPON_FIRECGUN');
1074 g_Sound_Delete('SOUND_WEAPON_FIREBFG');
1075 g_Sound_Delete('SOUND_FIRE');
1076 g_Sound_Delete('SOUND_WEAPON_STARTFIREBFG');
1077 g_Sound_Delete('SOUND_WEAPON_EXPLODEROCKET');
1078 g_Sound_Delete('SOUND_WEAPON_EXPLODEBFG');
1079 g_Sound_Delete('SOUND_WEAPON_BFGWATER');
1080 g_Sound_Delete('SOUND_WEAPON_EXPLODEPLASMA');
1081 g_Sound_Delete('SOUND_WEAPON_PLASMAWATER');
1082 g_Sound_Delete('SOUND_WEAPON_FIREBALL');
1083 g_Sound_Delete('SOUND_WEAPON_EXPLODEBALL');
1084 g_Sound_Delete('SOUND_WEAPON_FIREREV');
1085 g_Sound_Delete('SOUND_PLAYER_JETFLY');
1086 g_Sound_Delete('SOUND_PLAYER_JETON');
1087 g_Sound_Delete('SOUND_PLAYER_JETOFF');
1088 g_Sound_Delete('SOUND_PLAYER_CASING1');
1089 g_Sound_Delete('SOUND_PLAYER_CASING2');
1090 g_Sound_Delete('SOUND_PLAYER_SHELL1');
1091 g_Sound_Delete('SOUND_PLAYER_SHELL2');
1093 g_Texture_Delete('TEXTURE_WEAPON_ROCKET');
1094 g_Frames_DeleteByName('FRAMES_WEAPON_BFG');
1095 g_Frames_DeleteByName('FRAMES_WEAPON_PLASMA');
1096 g_Frames_DeleteByName('FRAMES_WEAPON_IMPFIRE');
1097 g_Frames_DeleteByName('FRAMES_WEAPON_BSPFIRE');
1098 g_Frames_DeleteByName('FRAMES_WEAPON_CACOFIRE');
1099 g_Frames_DeleteByName('FRAMES_WEAPON_MANCUBFIRE');
1100 g_Frames_DeleteByName('FRAMES_EXPLODE_ROCKET');
1101 g_Frames_DeleteByName('FRAMES_EXPLODE_BFG');
1102 g_Frames_DeleteByName('FRAMES_EXPLODE_IMPFIRE');
1103 g_Frames_DeleteByName('FRAMES_BFGHIT');
1104 g_Frames_DeleteByName('FRAMES_FIRE');
1105 g_Frames_DeleteByName('FRAMES_EXPLODE_PLASMA');
1106 g_Frames_DeleteByName('FRAMES_EXPLODE_BSPFIRE');
1107 g_Frames_DeleteByName('FRAMES_EXPLODE_CACOFIRE');
1108 g_Frames_DeleteByName('FRAMES_SMOKE');
1109 g_Frames_DeleteByName('FRAMES_WEAPON_BARONFIRE');
1110 g_Frames_DeleteByName('FRAMES_EXPLODE_BARONFIRE');
1111 end;
1113 procedure g_Weapon_gun(x, y, xd, yd, v, dmg: Integer; SpawnerUID: Word; CheckTrigger: Boolean);
1114 var
1115 a: Integer;
1116 x2, y2: Integer;
1117 dx, dy: Integer;
1118 xe, ye: Integer;
1119 xi, yi: Integer;
1120 s, c: Extended;
1121 //vx, vy: Integer;
1122 xx, yy, d: Integer;
1124 i: Integer;
1125 t1, _collide: Boolean;
1126 w, h: Word;
1127 begin
1128 a := GetAngle(x, y, xd, yd)+180;
1130 SinCos(DegToRad(-a), s, c);
1132 if Abs(s) < 0.01 then s := 0;
1133 if Abs(c) < 0.01 then c := 0;
1135 x2 := x+Round(c*gMapInfo.Width);
1136 y2 := y+Round(s*gMapInfo.Width);
1138 t1 := gWalls <> nil;
1139 _collide := False;
1140 w := gMapInfo.Width;
1141 h := gMapInfo.Height;
1143 xe := 0;
1144 ye := 0;
1145 dx := x2-x;
1146 dy := y2-y;
1148 if (xd = 0) and (yd = 0) then Exit;
1150 if dx > 0 then xi := 1 else if dx < 0 then xi := -1 else xi := 0;
1151 if dy > 0 then yi := 1 else if dy < 0 then yi := -1 else yi := 0;
1153 dx := Abs(dx);
1154 dy := Abs(dy);
1156 if dx > dy then d := dx else d := dy;
1158 //blood vel, for Monster.Damage()
1159 //vx := (dx*10 div d)*xi;
1160 //vy := (dy*10 div d)*yi;
1162 xx := x;
1163 yy := y;
1165 for i := 1 to d do
1166 begin
1167 xe := xe+dx;
1168 ye := ye+dy;
1170 if xe > d then
1171 begin
1172 xe := xe-d;
1173 xx := xx+xi;
1174 end;
1176 if ye > d then
1177 begin
1178 ye := ye-d;
1179 yy := yy+yi;
1180 end;
1182 if (yy > h) or (yy < 0) then Break;
1183 if (xx > w) or (xx < 0) then Break;
1185 if t1 then
1186 if ByteBool(gCollideMap[yy, xx] and MARK_BLOCKED) then
1187 begin
1188 _collide := True;
1189 g_GFX_Spark(xx-xi, yy-yi, 2+Random(2), 180+a, 0, 0);
1190 if g_Game_IsServer and g_Game_IsNet then
1191 MH_SEND_Effect(xx-xi, yy-yi, 180+a, NET_GFX_SPARK);
1192 end;
1194 if not _collide then
1195 _collide := GunHit(xx, yy, xi*v, yi*v, dmg, SpawnerUID, v <> 0) <> 0;
1197 if _collide then
1198 Break;
1199 end;
1201 if CheckTrigger and g_Game_IsServer then
1202 g_Triggers_PressL(X, Y, xx-xi, yy-yi, SpawnerUID, ACTIVATE_SHOT);
1203 end;
1205 procedure g_Weapon_punch(x, y: Integer; d, SpawnerUID: Word);
1206 var
1207 obj: TObj;
1208 begin
1209 obj.X := X;
1210 obj.Y := Y;
1211 obj.rect.X := 0;
1212 obj.rect.Y := 0;
1213 obj.rect.Width := 39;
1214 obj.rect.Height := 52;
1215 obj.Vel.X := 0;
1216 obj.Vel.Y := 0;
1217 obj.Accel.X := 0;
1218 obj.Accel.Y := 0;
1220 if g_Weapon_Hit(@obj, d, SpawnerUID, HIT_SOME) <> 0 then
1221 g_Sound_PlayExAt('SOUND_WEAPON_HITPUNCH', x, y)
1222 else
1223 g_Sound_PlayExAt('SOUND_WEAPON_MISSPUNCH', x, y);
1224 end;
1226 function g_Weapon_chainsaw(x, y: Integer; d, SpawnerUID: Word): Integer;
1227 var
1228 obj: TObj;
1229 begin
1230 obj.X := X;
1231 obj.Y := Y;
1232 obj.rect.X := 0;
1233 obj.rect.Y := 0;
1234 obj.rect.Width := 32;
1235 obj.rect.Height := 52;
1236 obj.Vel.X := 0;
1237 obj.Vel.Y := 0;
1238 obj.Accel.X := 0;
1239 obj.Accel.Y := 0;
1241 Result := g_Weapon_Hit(@obj, d, SpawnerUID, HIT_SOME);
1242 end;
1244 procedure g_Weapon_rocket(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1;
1245 Silent: Boolean = False);
1246 var
1247 find_id: DWORD;
1248 dx, dy: Integer;
1249 begin
1250 if WID < 0 then
1251 find_id := FindShot()
1252 else
1253 begin
1254 find_id := WID;
1255 if Integer(find_id) >= High(Shots) then
1256 SetLength(Shots, find_id + 64)
1257 end;
1259 with Shots[find_id] do
1260 begin
1261 g_Obj_Init(@Obj);
1263 Obj.Rect.Width := SHOT_ROCKETLAUNCHER_WIDTH;
1264 Obj.Rect.Height := SHOT_ROCKETLAUNCHER_HEIGHT;
1266 dx := IfThen(xd > x, -Obj.Rect.Width, 0);
1267 dy := -(Obj.Rect.Height div 2);
1269 ShotType := WEAPON_ROCKETLAUNCHER;
1270 throw(find_id, x+dx, y+dy, xd+dx, yd+dy, 12);
1272 Animation := nil;
1273 triggers := nil;
1274 g_Texture_Get('TEXTURE_WEAPON_ROCKET', TextureID);
1275 end;
1277 Shots[find_id].SpawnerUID := SpawnerUID;
1279 if not Silent then
1280 g_Sound_PlayExAt('SOUND_WEAPON_FIREROCKET', x, y);
1281 end;
1283 procedure g_Weapon_revf(x, y, xd, yd: Integer; SpawnerUID, TargetUID: Word;
1284 WID: Integer = -1; Silent: Boolean = False);
1285 var
1286 find_id, FramesID: DWORD;
1287 dx, dy: Integer;
1288 begin
1289 if WID < 0 then
1290 find_id := FindShot()
1291 else
1292 begin
1293 find_id := WID;
1294 if Integer(find_id) >= High(Shots) then
1295 SetLength(Shots, find_id + 64)
1296 end;
1298 with Shots[find_id] do
1299 begin
1300 g_Obj_Init(@Obj);
1302 Obj.Rect.Width := SHOT_SKELFIRE_WIDTH;
1303 Obj.Rect.Height := SHOT_SKELFIRE_HEIGHT;
1305 dx := -(Obj.Rect.Width div 2);
1306 dy := -(Obj.Rect.Height div 2);
1308 ShotType := WEAPON_SKEL_FIRE;
1309 throw(find_id, x+dx, y+dy, xd+dx, yd+dy, 12);
1311 triggers := nil;
1312 target := TargetUID;
1313 g_Frames_Get(FramesID, 'FRAMES_WEAPON_SKELFIRE');
1314 Animation := TAnimation.Create(FramesID, True, 5);
1315 end;
1317 Shots[find_id].SpawnerUID := SpawnerUID;
1319 if not Silent then
1320 g_Sound_PlayExAt('SOUND_WEAPON_FIREREV', x, y);
1321 end;
1323 procedure g_Weapon_plasma(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1;
1324 Silent: Boolean = False);
1325 var
1326 find_id, FramesID: DWORD;
1327 dx, dy: Integer;
1328 begin
1329 if WID < 0 then
1330 find_id := FindShot()
1331 else
1332 begin
1333 find_id := WID;
1334 if Integer(find_id) >= High(Shots) then
1335 SetLength(Shots, find_id + 64);
1336 end;
1338 with Shots[find_id] do
1339 begin
1340 g_Obj_Init(@Obj);
1342 Obj.Rect.Width := SHOT_PLASMA_WIDTH;
1343 Obj.Rect.Height := SHOT_PLASMA_HEIGHT;
1345 dx := IfThen(xd>x, -Obj.Rect.Width, 0);
1346 dy := -(Obj.Rect.Height div 2);
1348 ShotType := WEAPON_PLASMA;
1349 throw(find_id, x+dx, y+dy, xd+dx, yd+dy, 16);
1351 triggers := nil;
1352 g_Frames_Get(FramesID, 'FRAMES_WEAPON_PLASMA');
1353 Animation := TAnimation.Create(FramesID, True, 5);
1354 end;
1356 Shots[find_id].SpawnerUID := SpawnerUID;
1358 if not Silent then
1359 g_Sound_PlayExAt('SOUND_WEAPON_FIREPLASMA', x, y);
1360 end;
1362 procedure g_Weapon_flame(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1;
1363 Silent: Boolean = False);
1364 var
1365 find_id: DWORD;
1366 dx, dy: Integer;
1367 begin
1368 if WID < 0 then
1369 find_id := FindShot()
1370 else
1371 begin
1372 find_id := WID;
1373 if Integer(find_id) >= High(Shots) then
1374 SetLength(Shots, find_id + 64);
1375 end;
1377 with Shots[find_id] do
1378 begin
1379 g_Obj_Init(@Obj);
1381 Obj.Rect.Width := SHOT_FLAME_WIDTH;
1382 Obj.Rect.Height := SHOT_FLAME_HEIGHT;
1384 dx := IfThen(xd>x, -Obj.Rect.Width, 0);
1385 dy := -(Obj.Rect.Height div 2);
1387 ShotType := WEAPON_FLAMETHROWER;
1388 throw(find_id, x+dx, y+dy, xd+dx, yd+dy, 16);
1390 triggers := nil;
1391 Animation := nil;
1392 TextureID := 0;
1393 g_Frames_Get(TextureID, 'FRAMES_FLAME');
1394 end;
1396 Shots[find_id].SpawnerUID := SpawnerUID;
1398 // if not Silent then
1399 // g_Sound_PlayExAt('SOUND_WEAPON_FIREPLASMA', x, y);
1400 end;
1402 procedure g_Weapon_ball1(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1;
1403 Silent: Boolean = False);
1404 var
1405 find_id, FramesID: DWORD;
1406 dx, dy: Integer;
1407 begin
1408 if WID < 0 then
1409 find_id := FindShot()
1410 else
1411 begin
1412 find_id := WID;
1413 if Integer(find_id) >= High(Shots) then
1414 SetLength(Shots, find_id + 64)
1415 end;
1417 with Shots[find_id] do
1418 begin
1419 g_Obj_Init(@Obj);
1421 Obj.Rect.Width := 16;
1422 Obj.Rect.Height := 16;
1424 dx := IfThen(xd>x, -Obj.Rect.Width, 0);
1425 dy := -(Obj.Rect.Height div 2);
1427 ShotType := WEAPON_IMP_FIRE;
1428 throw(find_id, x+dx, y+dy, xd+dx, yd+dy, 16);
1430 triggers := nil;
1431 g_Frames_Get(FramesID, 'FRAMES_WEAPON_IMPFIRE');
1432 Animation := TAnimation.Create(FramesID, True, 4);
1433 end;
1435 Shots[find_id].SpawnerUID := SpawnerUID;
1437 if not Silent then
1438 g_Sound_PlayExAt('SOUND_WEAPON_FIREBALL', x, y);
1439 end;
1441 procedure g_Weapon_ball2(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1;
1442 Silent: Boolean = False);
1443 var
1444 find_id, FramesID: DWORD;
1445 dx, dy: Integer;
1446 begin
1447 if WID < 0 then
1448 find_id := FindShot()
1449 else
1450 begin
1451 find_id := WID;
1452 if Integer(find_id) >= High(Shots) then
1453 SetLength(Shots, find_id + 64)
1454 end;
1456 with Shots[find_id] do
1457 begin
1458 g_Obj_Init(@Obj);
1460 Obj.Rect.Width := 16;
1461 Obj.Rect.Height := 16;
1463 dx := IfThen(xd>x, -Obj.Rect.Width, 0);
1464 dy := -(Obj.Rect.Height div 2);
1466 ShotType := WEAPON_CACO_FIRE;
1467 throw(find_id, x+dx, y+dy, xd+dx, yd+dy, 16);
1469 triggers := nil;
1470 g_Frames_Get(FramesID, 'FRAMES_WEAPON_CACOFIRE');
1471 Animation := TAnimation.Create(FramesID, True, 4);
1472 end;
1474 Shots[find_id].SpawnerUID := SpawnerUID;
1476 if not Silent then
1477 g_Sound_PlayExAt('SOUND_WEAPON_FIREBALL', x, y);
1478 end;
1480 procedure g_Weapon_ball7(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1;
1481 Silent: Boolean = False);
1482 var
1483 find_id, FramesID: DWORD;
1484 dx, dy: Integer;
1485 begin
1486 if WID < 0 then
1487 find_id := FindShot()
1488 else
1489 begin
1490 find_id := WID;
1491 if Integer(find_id) >= High(Shots) then
1492 SetLength(Shots, find_id + 64)
1493 end;
1495 with Shots[find_id] do
1496 begin
1497 g_Obj_Init(@Obj);
1499 Obj.Rect.Width := 32;
1500 Obj.Rect.Height := 16;
1502 dx := IfThen(xd>x, -Obj.Rect.Width, 0);
1503 dy := -(Obj.Rect.Height div 2);
1505 ShotType := WEAPON_BARON_FIRE;
1506 throw(find_id, x+dx, y+dy, xd+dx, yd+dy, 16);
1508 triggers := nil;
1509 g_Frames_Get(FramesID, 'FRAMES_WEAPON_BARONFIRE');
1510 Animation := TAnimation.Create(FramesID, True, 4);
1511 end;
1513 Shots[find_id].SpawnerUID := SpawnerUID;
1515 if not Silent then
1516 g_Sound_PlayExAt('SOUND_WEAPON_FIREBALL', x, y);
1517 end;
1519 procedure g_Weapon_aplasma(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1;
1520 Silent: Boolean = False);
1521 var
1522 find_id, FramesID: DWORD;
1523 dx, dy: Integer;
1524 begin
1525 if WID < 0 then
1526 find_id := FindShot()
1527 else
1528 begin
1529 find_id := WID;
1530 if Integer(find_id) >= High(Shots) then
1531 SetLength(Shots, find_id + 64)
1532 end;
1534 with Shots[find_id] do
1535 begin
1536 g_Obj_Init(@Obj);
1538 Obj.Rect.Width := 16;
1539 Obj.Rect.Height := 16;
1541 dx := IfThen(xd>x, -Obj.Rect.Width, 0);
1542 dy := -(Obj.Rect.Height div 2);
1544 ShotType := WEAPON_BSP_FIRE;
1545 throw(find_id, x+dx, y+dy, xd+dx, yd+dy, 16);
1547 triggers := nil;
1549 g_Frames_Get(FramesID, 'FRAMES_WEAPON_BSPFIRE');
1550 Animation := TAnimation.Create(FramesID, True, 4);
1551 end;
1553 Shots[find_id].SpawnerUID := SpawnerUID;
1555 if not Silent then
1556 g_Sound_PlayExAt('SOUND_WEAPON_FIREPLASMA', x, y);
1557 end;
1559 procedure g_Weapon_manfire(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1;
1560 Silent: Boolean = False);
1561 var
1562 find_id, FramesID: DWORD;
1563 dx, dy: Integer;
1564 begin
1565 if WID < 0 then
1566 find_id := FindShot()
1567 else
1568 begin
1569 find_id := WID;
1570 if Integer(find_id) >= High(Shots) then
1571 SetLength(Shots, find_id + 64)
1572 end;
1574 with Shots[find_id] do
1575 begin
1576 g_Obj_Init(@Obj);
1578 Obj.Rect.Width := 32;
1579 Obj.Rect.Height := 32;
1581 dx := IfThen(xd>x, -Obj.Rect.Width, 0);
1582 dy := -(Obj.Rect.Height div 2);
1584 ShotType := WEAPON_MANCUB_FIRE;
1585 throw(find_id, x+dx, y+dy, xd+dx, yd+dy, 16);
1587 triggers := nil;
1589 g_Frames_Get(FramesID, 'FRAMES_WEAPON_MANCUBFIRE');
1590 Animation := TAnimation.Create(FramesID, True, 4);
1591 end;
1593 Shots[find_id].SpawnerUID := SpawnerUID;
1595 if not Silent then
1596 g_Sound_PlayExAt('SOUND_WEAPON_FIREBALL', x, y);
1597 end;
1599 procedure g_Weapon_bfgshot(x, y, xd, yd: Integer; SpawnerUID: Word; WID: Integer = -1;
1600 Silent: Boolean = False);
1601 var
1602 find_id, FramesID: DWORD;
1603 dx, dy: Integer;
1604 begin
1605 if WID < 0 then
1606 find_id := FindShot()
1607 else
1608 begin
1609 find_id := WID;
1610 if Integer(find_id) >= High(Shots) then
1611 SetLength(Shots, find_id + 64)
1612 end;
1614 with Shots[find_id] do
1615 begin
1616 g_Obj_Init(@Obj);
1618 Obj.Rect.Width := SHOT_BFG_WIDTH;
1619 Obj.Rect.Height := SHOT_BFG_HEIGHT;
1621 dx := IfThen(xd>x, -Obj.Rect.Width, 0);
1622 dy := -(Obj.Rect.Height div 2);
1624 ShotType := WEAPON_BFG;
1625 throw(find_id, x+dx, y+dy, xd+dx, yd+dy, 16);
1627 triggers := nil;
1628 g_Frames_Get(FramesID, 'FRAMES_WEAPON_BFG');
1629 Animation := TAnimation.Create(FramesID, True, 6);
1630 end;
1632 Shots[find_id].SpawnerUID := SpawnerUID;
1634 if not Silent then
1635 g_Sound_PlayExAt('SOUND_WEAPON_FIREBFG', x, y);
1636 end;
1638 procedure g_Weapon_bfghit(x, y: Integer);
1639 var
1640 ID: DWORD;
1641 Anim: TAnimation;
1642 begin
1643 if g_Frames_Get(ID, 'FRAMES_BFGHIT') then
1644 begin
1645 Anim := TAnimation.Create(ID, False, 4);
1646 g_GFX_OnceAnim(x-32, y-32, Anim);
1647 Anim.Free();
1648 end;
1649 end;
1651 procedure g_Weapon_pistol(x, y, xd, yd: Integer; SpawnerUID: Word;
1652 Silent: Boolean = False);
1653 begin
1654 if not Silent then
1655 g_Sound_PlayExAt('SOUND_WEAPON_FIREPISTOL', x, y);
1657 g_Weapon_gun(x, y, xd, yd, 1, 3, SpawnerUID, True);
1658 if gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF] then
1659 begin
1660 g_Weapon_gun(x, y+1, xd, yd+1, 1, 3, SpawnerUID, False);
1661 g_Weapon_gun(x, y-1, xd, yd-1, 1, 2, SpawnerUID, False);
1662 end;
1663 end;
1665 procedure g_Weapon_mgun(x, y, xd, yd: Integer; SpawnerUID: Word;
1666 Silent: Boolean = False);
1667 begin
1668 if not Silent then
1669 if gSoundEffectsDF then g_Sound_PlayExAt('SOUND_WEAPON_FIRECGUN', x, y);
1671 g_Weapon_gun(x, y, xd, yd, 1, 3, SpawnerUID, True);
1672 if (gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF]) and
1673 (g_GetUIDType(SpawnerUID) = UID_PLAYER) then
1674 begin
1675 g_Weapon_gun(x, y+1, xd, yd+1, 1, 2, SpawnerUID, False);
1676 g_Weapon_gun(x, y-1, xd, yd-1, 1, 2, SpawnerUID, False);
1677 end;
1678 end;
1680 procedure g_Weapon_shotgun(x, y, xd, yd: Integer; SpawnerUID: Word;
1681 Silent: Boolean = False);
1682 var
1683 i, j: Integer;
1684 begin
1685 if not Silent then
1686 if gSoundEffectsDF then g_Sound_PlayExAt('SOUND_WEAPON_FIRESHOTGUN', x, y);
1688 for i := 0 to 9 do
1689 begin
1690 j := Random(17)-8; // -8 .. 8
1691 g_Weapon_gun(x, y+j, xd, yd+j, IfThen(i mod 2 <> 0, 1, 0), 3, SpawnerUID, i=0);
1692 end;
1693 end;
1695 procedure g_Weapon_dshotgun(x, y, xd, yd: Integer; SpawnerUID: Word;
1696 Silent: Boolean = False);
1697 var
1698 a, i, j: Integer;
1699 begin
1700 if not Silent then
1701 g_Sound_PlayExAt('SOUND_WEAPON_FIRESHOTGUN2', x, y);
1703 if gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF] then a := 25 else a := 20;
1704 for i := 0 to a do
1705 begin
1706 j := Random(41)-20; // -20 .. 20
1707 g_Weapon_gun(x, y+j, xd, yd+j, IfThen(i mod 3 <> 0, 0, 1), 3, SpawnerUID, i=0);
1708 end;
1709 end;
1711 procedure g_Weapon_Update();
1712 var
1713 i, a, h, cx, cy, oldvx, oldvy, tf: Integer;
1714 _id: DWORD;
1715 Anim: TAnimation;
1716 t: DWArray;
1717 st: Word;
1718 s: String;
1719 o: TObj;
1720 spl: Boolean;
1721 Loud: Boolean;
1722 tcx, tcy: Integer;
1723 begin
1724 if Shots = nil then
1725 Exit;
1727 for i := 0 to High(Shots) do
1728 begin
1729 if Shots[i].ShotType = 0 then
1730 Continue;
1732 Loud := True;
1734 with Shots[i] do
1735 begin
1736 Timeout := Timeout - 1;
1737 oldvx := Obj.Vel.X;
1738 oldvy := Obj.Vel.Y;
1739 // Àêòèâèðîâàòü òðèããåðû ïî ïóòè (êðîìå óæå àêòèâèðîâàííûõ):
1740 if (Stopped = 0) and g_Game_IsServer then
1741 t := g_Triggers_PressR(Obj.X, Obj.Y, Obj.Rect.Width, Obj.Rect.Height,
1742 SpawnerUID, ACTIVATE_SHOT, triggers)
1743 else
1744 t := nil;
1746 if t <> nil then
1747 begin
1748 // Ïîïîëíÿåì ñïèñîê àêòèâèðîâàííûõ òðèããåðîâ:
1749 if triggers = nil then
1750 triggers := t
1751 else
1752 begin
1753 h := High(t);
1755 for a := 0 to h do
1756 if not InDWArray(t[a], triggers) then
1757 begin
1758 SetLength(triggers, Length(triggers)+1);
1759 triggers[High(triggers)] := t[a];
1760 end;
1761 end;
1762 end;
1764 // Àíèìàöèÿ ñíàðÿäà:
1765 if Animation <> nil then
1766 Animation.Update();
1768 // Äâèæåíèå:
1769 spl := (ShotType <> WEAPON_PLASMA) and
1770 (ShotType <> WEAPON_BFG) and
1771 (ShotType <> WEAPON_BSP_FIRE) and
1772 (ShotType <> WEAPON_FLAMETHROWER);
1774 if Stopped = 0 then
1775 begin
1776 st := g_Obj_Move(@Obj, False, spl);
1777 end
1778 else
1779 begin
1780 st := 0;
1781 end;
1782 positionChanged(); // this updates spatial accelerators
1784 if WordBool(st and MOVE_FALLOUT) or (Obj.X < -1000) or
1785 (Obj.X > gMapInfo.Width+1000) or (Obj.Y < -1000) then
1786 begin
1787 // Íà êëèåíòå ñêîðåå âñåãî è òàê óæå âûïàë.
1788 ShotType := 0;
1789 Animation.Free();
1790 Continue;
1791 end;
1793 cx := Obj.X + (Obj.Rect.Width div 2);
1794 cy := Obj.Y + (Obj.Rect.Height div 2);
1796 case ShotType of
1797 WEAPON_ROCKETLAUNCHER, WEAPON_SKEL_FIRE: // Ðàêåòû è ñíàðÿäû Ñêåëåòà
1798 begin
1799 // Âûëåòåëà èç âîäû:
1800 if WordBool(st and MOVE_HITAIR) then
1801 g_Obj_SetSpeed(@Obj, 12);
1803 // Â âîäå øëåéô - ïóçûðè, â âîçäóõå øëåéô - äûì:
1804 if WordBool(st and MOVE_INWATER) then
1805 g_GFX_Bubbles(Obj.X+(Obj.Rect.Width div 2),
1806 Obj.Y+(Obj.Rect.Height div 2),
1807 1+Random(3), 16, 16)
1808 else
1809 if g_Frames_Get(_id, 'FRAMES_SMOKE') then
1810 begin
1811 Anim := TAnimation.Create(_id, False, 3);
1812 Anim.Alpha := 150;
1813 g_GFX_OnceAnim(Obj.X-14+Random(9),
1814 Obj.Y+(Obj.Rect.Height div 2)-20+Random(9),
1815 Anim, ONCEANIM_SMOKE);
1816 Anim.Free();
1817 end;
1819 // Ïîïàëè â êîãî-òî èëè â ñòåíó:
1820 if WordBool(st and (MOVE_HITWALL or MOVE_HITLAND or MOVE_HITCEIL)) or
1821 (g_Weapon_Hit(@Obj, 10, SpawnerUID, HIT_SOME, False) <> 0) or
1822 (Timeout < 1) then
1823 begin
1824 Obj.Vel.X := 0;
1825 Obj.Vel.Y := 0;
1827 g_Weapon_Explode(cx, cy, 60, SpawnerUID);
1829 if ShotType = WEAPON_SKEL_FIRE then
1830 begin // Âçðûâ ñíàðÿäà Ñêåëåòà
1831 if g_Frames_Get(TextureID, 'FRAMES_EXPLODE_SKELFIRE') then
1832 begin
1833 Anim := TAnimation.Create(TextureID, False, 8);
1834 Anim.Blending := False;
1835 g_GFX_OnceAnim((Obj.X+32)-58, (Obj.Y+8)-36, Anim);
1836 g_DynLightExplosion((Obj.X+32), (Obj.Y+8), 64, 1, 0, 0);
1837 Anim.Free();
1838 end;
1839 end
1840 else
1841 begin // Âçðûâ Ðàêåòû
1842 if g_Frames_Get(TextureID, 'FRAMES_EXPLODE_ROCKET') then
1843 begin
1844 Anim := TAnimation.Create(TextureID, False, 6);
1845 Anim.Blending := False;
1846 g_GFX_OnceAnim(cx-64, cy-64, Anim);
1847 g_DynLightExplosion(cx, cy, 64, 1, 0, 0);
1848 Anim.Free();
1849 end;
1850 end;
1852 g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEROCKET', Obj.X, Obj.Y);
1854 ShotType := 0;
1855 end;
1857 if ShotType = WEAPON_SKEL_FIRE then
1858 begin // Ñàìîíàâîäêà ñíàðÿäà Ñêåëåòà:
1859 if GetPos(target, @o) then
1860 throw(i, Obj.X, Obj.Y,
1861 o.X+o.Rect.X+(o.Rect.Width div 2)+o.Vel.X+o.Accel.X,
1862 o.Y+o.Rect.Y+(o.Rect.Height div 2)+o.Vel.Y+o.Accel.Y,
1863 12);
1864 end;
1865 end;
1867 WEAPON_PLASMA, WEAPON_BSP_FIRE: // Ïëàçìà, ïëàçìà Àðàõíàòðîíà
1868 begin
1869 // Ïîïàëà â âîäó - ýëåêòðîøîê ïî âîäå:
1870 if WordBool(st and (MOVE_INWATER or MOVE_HITWATER)) then
1871 begin
1872 g_Sound_PlayExAt('SOUND_WEAPON_PLASMAWATER', Obj.X, Obj.Y);
1873 if g_Game_IsServer then CheckTrap(i, 10, HIT_ELECTRO);
1874 ShotType := 0;
1875 Continue;
1876 end;
1878 // Âåëè÷èíà óðîíà:
1879 if (ShotType = WEAPON_PLASMA) and
1880 (gGameSettings.GameMode in [GM_DM, GM_TDM, GM_CTF]) then
1881 a := 10
1882 else
1883 a := 5;
1885 if ShotType = WEAPON_BSP_FIRE then
1886 a := 10;
1888 // Ïîïàëè â êîãî-òî èëè â ñòåíó:
1889 if WordBool(st and (MOVE_HITWALL or MOVE_HITLAND or MOVE_HITCEIL)) or
1890 (g_Weapon_Hit(@Obj, a, SpawnerUID, HIT_SOME, False) <> 0) or
1891 (Timeout < 1) then
1892 begin
1893 if ShotType = WEAPON_PLASMA then
1894 s := 'FRAMES_EXPLODE_PLASMA'
1895 else
1896 s := 'FRAMES_EXPLODE_BSPFIRE';
1898 // Âçðûâ Ïëàçìû:
1899 if g_Frames_Get(TextureID, s) then
1900 begin
1901 Anim := TAnimation.Create(TextureID, False, 3);
1902 Anim.Blending := False;
1903 g_GFX_OnceAnim(cx-16, cy-16, Anim);
1904 Anim.Free();
1905 g_DynLightExplosion(cx, cy, 32, 0, 0.5, 0.5);
1906 end;
1908 g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEPLASMA', Obj.X, Obj.Y);
1910 ShotType := 0;
1911 end;
1912 end;
1914 WEAPON_FLAMETHROWER: // Îãíåìåò
1915 begin
1916 // Ñî âðåìåíåì óìèðàåò
1917 if (Timeout < 1) then
1918 begin
1919 ShotType := 0;
1920 Continue;
1921 end;
1922 // Ïîä âîäîé òîæå
1923 if WordBool(st and (MOVE_HITWATER or MOVE_INWATER)) then
1924 begin
1925 if WordBool(st and MOVE_HITWATER) then
1926 begin
1927 if g_Frames_Get(_id, 'FRAMES_SMOKE') then
1928 begin
1929 Anim := TAnimation.Create(_id, False, 3);
1930 Anim.Alpha := 0;
1931 tcx := Random(8);
1932 tcy := Random(8);
1933 g_GFX_OnceAnim(cx-4+tcx-(Anim.Width div 2),
1934 cy-4+tcy-(Anim.Height div 2),
1935 Anim, ONCEANIM_SMOKE);
1936 Anim.Free();
1937 end;
1938 end
1939 else
1940 g_GFX_Bubbles(cx, cy, 1+Random(3), 16, 16);
1941 ShotType := 0;
1942 Continue;
1943 end;
1945 // Ãðàâèòàöèÿ
1946 if Stopped = 0 then
1947 Obj.Accel.Y := Obj.Accel.Y + 1;
1948 // Ïîïàëè â ñòåíó èëè â âîäó:
1949 if WordBool(st and (MOVE_HITWALL or MOVE_HITLAND or MOVE_HITCEIL or MOVE_HITWATER)) then
1950 begin
1951 // Ïðèëèïàåì:
1952 Obj.Vel.X := 0;
1953 Obj.Vel.Y := 0;
1954 Obj.Accel.Y := 0;
1955 if WordBool(st and MOVE_HITWALL) then
1956 Stopped := MOVE_HITWALL
1957 else if WordBool(st and MOVE_HITLAND) then
1958 Stopped := MOVE_HITLAND
1959 else if WordBool(st and MOVE_HITCEIL) then
1960 Stopped := MOVE_HITCEIL;
1961 end;
1963 a := IfThen(Stopped = 0, 3, 1);
1964 // Åñëè â êîãî-òî ïîïàëè
1965 if g_Weapon_Hit(@Obj, a, SpawnerUID, HIT_FLAME, False) <> 0 then
1966 begin
1967 // HIT_FLAME ñàì ïîäîææåò
1968 // Åñëè â ïîëåòå ïîïàëè, èñ÷åçàåì
1969 if Stopped = 0 then
1970 ShotType := 0;
1971 end;
1973 if Stopped = 0 then
1974 tf := 2
1975 else
1976 tf := 3;
1978 if (gTime mod tf = 0) then
1979 begin
1980 Anim := TAnimation.Create(TextureID, False, 2 + Random(2));
1981 Anim.Alpha := 0;
1982 case Stopped of
1983 MOVE_HITWALL: begin tcx := cx-4+Random(8); tcy := cy-12+Random(24); end;
1984 MOVE_HITLAND: begin tcx := cx-12+Random(24); tcy := cy-10+Random(8); end;
1985 MOVE_HITCEIL: begin tcx := cx-12+Random(24); tcy := cy+6+Random(8); end;
1986 else begin tcx := cx-4+Random(8); tcy := cy-4+Random(8); end;
1987 end;
1988 g_GFX_OnceAnim(tcx-(Anim.Width div 2), tcy-(Anim.Height div 2), Anim, ONCEANIM_SMOKE);
1989 Anim.Free();
1990 //g_DynLightExplosion(tcx, tcy, 1, 1, 0.8, 0.3);
1991 end;
1992 end;
1994 WEAPON_BFG: // BFG
1995 begin
1996 // Ïîïàëà â âîäó - ýëåêòðîøîê ïî âîäå:
1997 if WordBool(st and (MOVE_INWATER or MOVE_HITWATER)) then
1998 begin
1999 g_Sound_PlayExAt('SOUND_WEAPON_BFGWATER', Obj.X, Obj.Y);
2000 if g_Game_IsServer then CheckTrap(i, 1000, HIT_ELECTRO);
2001 ShotType := 0;
2002 Continue;
2003 end;
2005 // Ïîïàëè â êîãî-òî èëè â ñòåíó:
2006 if WordBool(st and (MOVE_HITWALL or MOVE_HITLAND or MOVE_HITCEIL)) or
2007 (g_Weapon_Hit(@Obj, SHOT_BFG_DAMAGE, SpawnerUID, HIT_BFG, False) <> 0) or
2008 (Timeout < 1) then
2009 begin
2010 // Ëó÷è BFG:
2011 if g_Game_IsServer then g_Weapon_BFG9000(cx, cy, SpawnerUID);
2013 // Âçðûâ BFG:
2014 if g_Frames_Get(TextureID, 'FRAMES_EXPLODE_BFG') then
2015 begin
2016 Anim := TAnimation.Create(TextureID, False, 6);
2017 Anim.Blending := False;
2018 g_GFX_OnceAnim(cx-64, cy-64, Anim);
2019 Anim.Free();
2020 g_DynLightExplosion(cx, cy, 96, 0, 1, 0);
2021 end;
2023 g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEBFG', Obj.X, Obj.Y);
2025 ShotType := 0;
2026 end;
2027 end;
2029 WEAPON_IMP_FIRE, WEAPON_CACO_FIRE, WEAPON_BARON_FIRE: // Âûñòðåëû Áåñà, Êàêîäåìîíà Ðûöàðÿ/Áàðîíà àäà
2030 begin
2031 // Âûëåòåë èç âîäû:
2032 if WordBool(st and MOVE_HITAIR) then
2033 g_Obj_SetSpeed(@Obj, 16);
2035 // Âåëè÷èíà óðîíà:
2036 if ShotType = WEAPON_IMP_FIRE then
2037 a := 5
2038 else
2039 if ShotType = WEAPON_CACO_FIRE then
2040 a := 20
2041 else
2042 a := 40;
2044 // Ïîïàëè â êîãî-òî èëè â ñòåíó:
2045 if WordBool(st and (MOVE_HITWALL or MOVE_HITLAND or MOVE_HITCEIL)) or
2046 (g_Weapon_Hit(@Obj, a, SpawnerUID, HIT_SOME) <> 0) or
2047 (Timeout < 1) then
2048 begin
2049 if ShotType = WEAPON_IMP_FIRE then
2050 s := 'FRAMES_EXPLODE_IMPFIRE'
2051 else
2052 if ShotType = WEAPON_CACO_FIRE then
2053 s := 'FRAMES_EXPLODE_CACOFIRE'
2054 else
2055 s := 'FRAMES_EXPLODE_BARONFIRE';
2057 // Âçðûâ:
2058 if g_Frames_Get(TextureID, s) then
2059 begin
2060 Anim := TAnimation.Create(TextureID, False, 6);
2061 Anim.Blending := False;
2062 g_GFX_OnceAnim(cx-32, cy-32, Anim);
2063 Anim.Free();
2064 end;
2066 g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEBALL', Obj.X, Obj.Y);
2068 ShotType := 0;
2069 end;
2070 end;
2072 WEAPON_MANCUB_FIRE: // Âûñòðåë Ìàíêóáóñà
2073 begin
2074 // Âûëåòåë èç âîäû:
2075 if WordBool(st and MOVE_HITAIR) then
2076 g_Obj_SetSpeed(@Obj, 16);
2078 // Ïîïàëè â êîãî-òî èëè â ñòåíó:
2079 if WordBool(st and (MOVE_HITWALL or MOVE_HITLAND or MOVE_HITCEIL)) or
2080 (g_Weapon_Hit(@Obj, 40, SpawnerUID, HIT_SOME, False) <> 0) or
2081 (Timeout < 1) then
2082 begin
2083 // Âçðûâ:
2084 if g_Frames_Get(TextureID, 'FRAMES_EXPLODE_ROCKET') then
2085 begin
2086 Anim := TAnimation.Create(TextureID, False, 6);
2087 Anim.Blending := False;
2088 g_GFX_OnceAnim(cx-64, cy-64, Anim);
2089 Anim.Free();
2090 end;
2092 g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEBALL', Obj.X, Obj.Y);
2094 ShotType := 0;
2095 end;
2096 end;
2097 end; // case ShotType of...
2099 // Åñëè ñíàðÿäà óæå íåò, óäàëÿåì àíèìàöèþ:
2100 if (ShotType = 0) then
2101 begin
2102 if gGameSettings.GameType = GT_SERVER then
2103 MH_SEND_DeleteShot(i, Obj.X, Obj.Y, Loud);
2104 if Animation <> nil then
2105 begin
2106 Animation.Free();
2107 Animation := nil;
2108 end;
2109 end
2110 else if (ShotType <> WEAPON_FLAMETHROWER) and ((oldvx <> Obj.Vel.X) or (oldvy <> Obj.Vel.Y)) then
2111 if gGameSettings.GameType = GT_SERVER then
2112 MH_SEND_UpdateShot(i);
2113 end;
2114 end;
2115 end;
2117 procedure g_Weapon_Draw();
2118 var
2119 i: Integer;
2120 a: SmallInt;
2121 p: TPoint;
2122 begin
2123 if Shots = nil then
2124 Exit;
2126 for i := 0 to High(Shots) do
2127 if Shots[i].ShotType <> 0 then
2128 with Shots[i] do
2129 begin
2130 if (Shots[i].ShotType = WEAPON_ROCKETLAUNCHER) or
2131 (Shots[i].ShotType = WEAPON_BARON_FIRE) or
2132 (Shots[i].ShotType = WEAPON_MANCUB_FIRE) or
2133 (Shots[i].ShotType = WEAPON_SKEL_FIRE) then
2134 a := -GetAngle2(Obj.Vel.X, Obj.Vel.Y)
2135 else
2136 a := 0;
2138 p.X := Obj.Rect.Width div 2;
2139 p.Y := Obj.Rect.Height div 2;
2141 if Animation <> nil then
2142 begin
2143 if (Shots[i].ShotType = WEAPON_BARON_FIRE) or
2144 (Shots[i].ShotType = WEAPON_MANCUB_FIRE) or
2145 (Shots[i].ShotType = WEAPON_SKEL_FIRE) then
2146 Animation.DrawEx(Obj.X, Obj.Y, M_NONE, p, a)
2147 else
2148 Animation.Draw(Obj.X, Obj.Y, M_NONE);
2149 end
2150 else if TextureID <> 0 then
2151 begin
2152 if (Shots[i].ShotType = WEAPON_ROCKETLAUNCHER) then
2153 e_DrawAdv(TextureID, Obj.X, Obj.Y, 0, True, False, a, @p, M_NONE)
2154 else if (Shots[i].ShotType <> WEAPON_FLAMETHROWER) then
2155 e_Draw(TextureID, Obj.X, Obj.Y, 0, True, False);
2156 end;
2158 if g_debug_Frames then
2159 begin
2160 e_DrawQuad(Obj.X+Obj.Rect.X,
2161 Obj.Y+Obj.Rect.Y,
2162 Obj.X+Obj.Rect.X+Obj.Rect.Width-1,
2163 Obj.Y+Obj.Rect.Y+Obj.Rect.Height-1,
2164 0, 255, 0);
2165 end;
2166 end;
2167 end;
2169 function g_Weapon_Danger(UID: Word; X, Y: Integer; Width, Height: Word; Time: Byte): Boolean;
2170 var
2171 a: Integer;
2172 begin
2173 Result := False;
2175 if Shots = nil then
2176 Exit;
2178 for a := 0 to High(Shots) do
2179 if (Shots[a].ShotType <> 0) and (Shots[a].SpawnerUID <> UID) then
2180 if ((Shots[a].Obj.Vel.Y = 0) and (Shots[a].Obj.Vel.X > 0) and (Shots[a].Obj.X < X)) or
2181 (Shots[a].Obj.Vel.Y = 0) and (Shots[a].Obj.Vel.X < 0) and (Shots[a].Obj.X > X) then
2182 if (Abs(X-Shots[a].Obj.X) < Abs(Shots[a].Obj.Vel.X*Time)) and
2183 g_Collide(X, Y, Width, Height, X, Shots[a].Obj.Y,
2184 Shots[a].Obj.Rect.Width, Shots[a].Obj.Rect.Height) and
2185 g_TraceVector(X, Y, Shots[a].Obj.X, Shots[a].Obj.Y) then
2186 begin
2187 Result := True;
2188 Exit;
2189 end;
2190 end;
2192 procedure g_Weapon_SaveState(var Mem: TBinMemoryWriter);
2193 var
2194 count, i, j: Integer;
2195 dw: DWORD;
2196 begin
2197 // Ñ÷èòàåì êîëè÷åñòâî ñóùåñòâóþùèõ ñíàðÿäîâ:
2198 count := 0;
2199 if Shots <> nil then
2200 for i := 0 to High(Shots) do
2201 if Shots[i].ShotType <> 0 then
2202 count := count + 1;
2204 Mem := TBinMemoryWriter.Create((count+1) * 80);
2206 // Êîëè÷åñòâî ñíàðÿäîâ:
2207 Mem.WriteInt(count);
2209 if count = 0 then
2210 Exit;
2212 for i := 0 to High(Shots) do
2213 if Shots[i].ShotType <> 0 then
2214 begin
2215 // Ñèãíàòóðà ñíàðÿäà:
2216 dw := SHOT_SIGNATURE; // 'SHOT'
2217 Mem.WriteDWORD(dw);
2218 // Òèï ñíàðÿäà:
2219 Mem.WriteByte(Shots[i].ShotType);
2220 // Öåëü:
2221 Mem.WriteWord(Shots[i].Target);
2222 // UID ñòðåëÿâøåãî:
2223 Mem.WriteWord(Shots[i].SpawnerUID);
2224 // Ðàçìåð ïîëÿ Triggers:
2225 dw := Length(Shots[i].Triggers);
2226 Mem.WriteDWORD(dw);
2227 // Òðèããåðû, àêòèâèðîâàííûå âûñòðåëîì:
2228 for j := 0 to Integer(dw)-1 do
2229 Mem.WriteDWORD(Shots[i].Triggers[j]);
2230 // Îáúåêò ñíàðÿäà:
2231 Obj_SaveState(@Shots[i].Obj, Mem);
2232 // Êîñòûëèíà åáàíàÿ:
2233 Mem.WriteByte(Shots[i].Stopped);
2234 end;
2235 end;
2237 procedure g_Weapon_LoadState(var Mem: TBinMemoryReader);
2238 var
2239 count, i, j: Integer;
2240 dw: DWORD;
2241 begin
2242 if Mem = nil then
2243 Exit;
2245 // Êîëè÷åñòâî ñíàðÿäîâ:
2246 Mem.ReadInt(count);
2248 SetLength(Shots, count);
2250 if count = 0 then
2251 Exit;
2253 for i := 0 to count-1 do
2254 begin
2255 // Ñèãíàòóðà ñíàðÿäà:
2256 Mem.ReadDWORD(dw);
2257 if dw <> SHOT_SIGNATURE then // 'SHOT'
2258 begin
2259 raise EBinSizeError.Create('g_Weapons_LoadState: Wrong Shot Signature');
2260 end;
2261 // Òèï ñíàðÿäà:
2262 Mem.ReadByte(Shots[i].ShotType);
2263 // Öåëü:
2264 Mem.ReadWord(Shots[i].Target);
2265 // UID ñòðåëÿâøåãî:
2266 Mem.ReadWord(Shots[i].SpawnerUID);
2267 // Ðàçìåð ïîëÿ Triggers:
2268 Mem.ReadDWORD(dw);
2269 SetLength(Shots[i].Triggers, dw);
2270 // Òðèããåðû, àêòèâèðîâàííûå âûñòðåëîì:
2271 for j := 0 to Integer(dw)-1 do
2272 Mem.ReadDWORD(Shots[i].Triggers[j]);
2273 // Îáúåêò ïðåäìåòà:
2274 Obj_LoadState(@Shots[i].Obj, Mem);
2275 // Êîñòûëèíà åáàíàÿ:
2276 Mem.ReadByte(Shots[i].Stopped);
2278 // Óñòàíîâêà òåêñòóðû èëè àíèìàöèè:
2279 Shots[i].TextureID := DWORD(-1);
2280 Shots[i].Animation := nil;
2282 case Shots[i].ShotType of
2283 WEAPON_ROCKETLAUNCHER, WEAPON_SKEL_FIRE:
2284 begin
2285 g_Texture_Get('TEXTURE_WEAPON_ROCKET', Shots[i].TextureID);
2286 end;
2287 WEAPON_PLASMA:
2288 begin
2289 g_Frames_Get(dw, 'FRAMES_WEAPON_PLASMA');
2290 Shots[i].Animation := TAnimation.Create(dw, True, 5);
2291 end;
2292 WEAPON_BFG:
2293 begin
2294 g_Frames_Get(dw, 'FRAMES_WEAPON_BFG');
2295 Shots[i].Animation := TAnimation.Create(dw, True, 6);
2296 end;
2297 WEAPON_IMP_FIRE:
2298 begin
2299 g_Frames_Get(dw, 'FRAMES_WEAPON_IMPFIRE');
2300 Shots[i].Animation := TAnimation.Create(dw, True, 4);
2301 end;
2302 WEAPON_BSP_FIRE:
2303 begin
2304 g_Frames_Get(dw, 'FRAMES_WEAPON_BSPFIRE');
2305 Shots[i].Animation := TAnimation.Create(dw, True, 4);
2306 end;
2307 WEAPON_CACO_FIRE:
2308 begin
2309 g_Frames_Get(dw, 'FRAMES_WEAPON_CACOFIRE');
2310 Shots[i].Animation := TAnimation.Create(dw, True, 4);
2311 end;
2312 WEAPON_BARON_FIRE:
2313 begin
2314 g_Frames_Get(dw, 'FRAMES_WEAPON_BARONFIRE');
2315 Shots[i].Animation := TAnimation.Create(dw, True, 4);
2316 end;
2317 WEAPON_MANCUB_FIRE:
2318 begin
2319 g_Frames_Get(dw, 'FRAMES_WEAPON_MANCUBFIRE');
2320 Shots[i].Animation := TAnimation.Create(dw, True, 4);
2321 end;
2322 end;
2323 end;
2324 end;
2326 procedure g_Weapon_DestroyShot(I: Integer; X, Y: Integer; Loud: Boolean = True);
2327 var
2328 cx, cy: Integer;
2329 Anim: TAnimation;
2330 s: string;
2331 begin
2332 if Shots = nil then
2333 Exit;
2334 if (I > High(Shots)) or (I < 0) then Exit;
2336 with Shots[I] do
2337 begin
2338 if ShotType = 0 then Exit;
2339 Obj.X := X;
2340 Obj.Y := Y;
2341 cx := Obj.X + (Obj.Rect.Width div 2);
2342 cy := Obj.Y + (Obj.Rect.Height div 2);
2344 case ShotType of
2345 WEAPON_ROCKETLAUNCHER, WEAPON_SKEL_FIRE: // Ðàêåòû è ñíàðÿäû Ñêåëåòà
2346 begin
2347 if Loud then
2348 begin
2349 if ShotType = WEAPON_SKEL_FIRE then
2350 begin // Âçðûâ ñíàðÿäà Ñêåëåòà
2351 if g_Frames_Get(TextureID, 'FRAMES_EXPLODE_SKELFIRE') then
2352 begin
2353 Anim := TAnimation.Create(TextureID, False, 8);
2354 Anim.Blending := False;
2355 g_GFX_OnceAnim((Obj.X+32)-32, (Obj.Y+8)-32, Anim);
2356 Anim.Free();
2357 end;
2358 end
2359 else
2360 begin // Âçðûâ Ðàêåòû
2361 if g_Frames_Get(TextureID, 'FRAMES_EXPLODE_ROCKET') then
2362 begin
2363 Anim := TAnimation.Create(TextureID, False, 6);
2364 Anim.Blending := False;
2365 g_GFX_OnceAnim(cx-64, cy-64, Anim);
2366 Anim.Free();
2367 end;
2368 end;
2369 g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEROCKET', Obj.X, Obj.Y);
2370 end;
2371 end;
2373 WEAPON_PLASMA, WEAPON_BSP_FIRE: // Ïëàçìà, ïëàçìà Àðàõíàòðîíà
2374 begin
2375 if ShotType = WEAPON_PLASMA then
2376 s := 'FRAMES_EXPLODE_PLASMA'
2377 else
2378 s := 'FRAMES_EXPLODE_BSPFIRE';
2380 if g_Frames_Get(TextureID, s) and loud then
2381 begin
2382 Anim := TAnimation.Create(TextureID, False, 3);
2383 Anim.Blending := False;
2384 g_GFX_OnceAnim(cx-16, cy-16, Anim);
2385 Anim.Free();
2387 g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEPLASMA', Obj.X, Obj.Y);
2388 end;
2389 end;
2391 WEAPON_BFG: // BFG
2392 begin
2393 // Âçðûâ BFG:
2394 if g_Frames_Get(TextureID, 'FRAMES_EXPLODE_BFG') and Loud then
2395 begin
2396 Anim := TAnimation.Create(TextureID, False, 6);
2397 Anim.Blending := False;
2398 g_GFX_OnceAnim(cx-64, cy-64, Anim);
2399 Anim.Free();
2401 g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEBFG', Obj.X, Obj.Y);
2402 end;
2403 end;
2405 WEAPON_IMP_FIRE, WEAPON_CACO_FIRE, WEAPON_BARON_FIRE: // Âûñòðåëû Áåñà, Êàêîäåìîíà Ðûöàðÿ/Áàðîíà àäà
2406 begin
2407 if ShotType = WEAPON_IMP_FIRE then
2408 s := 'FRAMES_EXPLODE_IMPFIRE'
2409 else
2410 if ShotType = WEAPON_CACO_FIRE then
2411 s := 'FRAMES_EXPLODE_CACOFIRE'
2412 else
2413 s := 'FRAMES_EXPLODE_BARONFIRE';
2415 if g_Frames_Get(TextureID, s) and Loud then
2416 begin
2417 Anim := TAnimation.Create(TextureID, False, 6);
2418 Anim.Blending := False;
2419 g_GFX_OnceAnim(cx-32, cy-32, Anim);
2420 Anim.Free();
2422 g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEBALL', Obj.X, Obj.Y);
2423 end;
2424 end;
2426 WEAPON_MANCUB_FIRE: // Âûñòðåë Ìàíêóáóñà
2427 begin
2428 if g_Frames_Get(TextureID, 'FRAMES_EXPLODE_ROCKET') and Loud then
2429 begin
2430 Anim := TAnimation.Create(TextureID, False, 6);
2431 Anim.Blending := False;
2432 g_GFX_OnceAnim(cx-64, cy-64, Anim);
2433 Anim.Free();
2435 g_Sound_PlayExAt('SOUND_WEAPON_EXPLODEBALL', Obj.X, Obj.Y);
2436 end;
2437 end;
2438 end; // case ShotType of...
2440 ShotType := 0;
2441 Animation.Free();
2442 end;
2443 end;
2446 procedure g_Weapon_AddDynLights();
2447 var
2448 i: Integer;
2449 begin
2450 if Shots = nil then Exit;
2451 for i := 0 to High(Shots) do
2452 begin
2453 if Shots[i].ShotType = 0 then continue;
2454 if (Shots[i].ShotType = WEAPON_ROCKETLAUNCHER) or
2455 (Shots[i].ShotType = WEAPON_BARON_FIRE) or
2456 (Shots[i].ShotType = WEAPON_MANCUB_FIRE) or
2457 (Shots[i].ShotType = WEAPON_SKEL_FIRE) or
2458 (Shots[i].ShotType = WEAPON_IMP_FIRE) or
2459 (Shots[i].ShotType = WEAPON_CACO_FIRE) or
2460 (Shots[i].ShotType = WEAPON_MANCUB_FIRE) or
2461 (Shots[i].ShotType = WEAPON_BSP_FIRE) or
2462 (Shots[i].ShotType = WEAPON_PLASMA) or
2463 (Shots[i].ShotType = WEAPON_BFG) or
2464 (Shots[i].ShotType = WEAPON_FLAMETHROWER) or
2465 false then
2466 begin
2467 if (Shots[i].ShotType = WEAPON_PLASMA) then
2468 g_AddDynLight(Shots[i].Obj.X+(Shots[i].Obj.Rect.Width div 2), Shots[i].Obj.Y+(Shots[i].Obj.Rect.Height div 2), 128, 0, 0.3, 1, 0.4)
2469 else if (Shots[i].ShotType = WEAPON_BFG) then
2470 g_AddDynLight(Shots[i].Obj.X+(Shots[i].Obj.Rect.Width div 2), Shots[i].Obj.Y+(Shots[i].Obj.Rect.Height div 2), 128, 0, 1, 0, 0.5)
2471 else if (Shots[i].ShotType = WEAPON_FLAMETHROWER) then
2472 g_AddDynLight(Shots[i].Obj.X+(Shots[i].Obj.Rect.Width div 2), Shots[i].Obj.Y+(Shots[i].Obj.Rect.Height div 2), 42, 1, 0.8, 0, 0.4)
2473 else
2474 g_AddDynLight(Shots[i].Obj.X+(Shots[i].Obj.Rect.Width div 2), Shots[i].Obj.Y+(Shots[i].Obj.Rect.Height div 2), 128, 1, 0, 0, 0.4);
2475 end;
2476 end;
2477 end;
2480 procedure TShot.positionChanged (); begin end;
2483 end.