diff --git a/src/game/g_gfx.pas b/src/game/g_gfx.pas
index e24db1f6858c312aa2780b23c283750d7b0ccf38..c84ba47eda80a1e2c6097a134a78d5ba0929a212 100644 (file)
--- a/src/game/g_gfx.pas
+++ b/src/game/g_gfx.pas
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*)
-{$INCLUDE g_amodes.inc}
+{$INCLUDE ../shared/a_modes.inc}
unit g_gfx;
interface
uses
- g_textures;
+ e_log, g_textures;
const
BLOOD_NORMAL = 0;
procedure g_GFX_Update();
procedure g_GFX_Draw();
+
var
- gCollideMap: Array of Array of Byte;
+ gpart_dbg_enabled: Boolean = true;
+ gpart_dbg_phys_enabled: Boolean = true;
+
implementation
g_game, g_language, g_net;
type
+ PParticle = ^TParticle;
TParticle = record
X, Y: Integer;
VelX, VelY: Single;
State: Byte;
ParticleType: Byte;
offsetX, offsetY: ShortInt;
+ // for bubbles
+ liquidTopY: Integer; // don't float higher than this
end;
TOnceAnim = record
STATE_STICK = 2;
var
- Particles: Array of TParticle;
- OnceAnims: Array of TOnceAnim;
+ Particles: array of TParticle;
+ OnceAnims: array of TOnceAnim;
MaxParticles: Integer;
CurrentParticle: Integer;
+
+function isBlockedAt (x, y: Integer): Boolean; inline;
+begin
+ if not gpart_dbg_phys_enabled then begin result := false; exit; end;
+ result := g_Map_HasAnyPanelAtPoint(x, y, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_STEP));
+end;
+
+// ???
+function isWallAt (x, y: Integer): Boolean; inline;
+begin
+ if not gpart_dbg_phys_enabled then begin result := false; exit; end;
+ result := g_Map_HasAnyPanelAtPoint(x, y, (PANEL_WALL or PANEL_STEP));
+end;
+
+function isLiftUpAt (x, y: Integer): Boolean; inline;
+begin
+ if not gpart_dbg_phys_enabled then begin result := false; exit; end;
+ result := g_Map_HasAnyPanelAtPoint(x, y, PANEL_LIFTUP);
+end;
+
+function isLiftDownAt (x, y: Integer): Boolean; inline;
+begin
+ if not gpart_dbg_phys_enabled then begin result := false; exit; end;
+ result := g_Map_HasAnyPanelAtPoint(x, y, PANEL_LIFTDOWN);
+end;
+
+function isLiftLeftAt (x, y: Integer): Boolean; inline;
+begin
+ if not gpart_dbg_phys_enabled then begin result := false; exit; end;
+ result := g_Map_HasAnyPanelAtPoint(x, y, PANEL_LIFTLEFT);
+end;
+
+function isLiftRightAt (x, y: Integer): Boolean; inline;
+begin
+ if not gpart_dbg_phys_enabled then begin result := false; exit; end;
+ result := g_Map_HasAnyPanelAtPoint(x, y, PANEL_LIFTRIGHT);
+end;
+
+function isLiquidAt (x, y: Integer): Boolean; inline;
+begin
+ if not gpart_dbg_phys_enabled then begin result := false; exit; end;
+ result := g_Map_HasAnyPanelAtPoint(x, y, (PANEL_WATER or PANEL_ACID1 or PANEL_ACID2));
+end;
+
+function isAnythingAt (x, y: Integer): Boolean; inline;
+begin
+ if not gpart_dbg_phys_enabled then begin result := false; exit; end;
+ result := g_Map_HasAnyPanelAtPoint(x, y, (PANEL_WALL or PANEL_CLOSEDOOR or PANEL_OPENDOOR or PANEL_WATER or PANEL_ACID1 or PANEL_ACID2 or PANEL_STEP or PANEL_LIFTUP or PANEL_LIFTDOWN or PANEL_LIFTLEFT or PANEL_LIFTRIGHT));
+end;
+
+
procedure g_Mark(x, y, Width, Height: Integer; t: Byte; st: Boolean);
+{$IF not DEFINED(HAS_COLLIDE_BITMAP)}
+begin
+end;
+{$ELSE}
var
yy, y2, xx, x2: Integer;
begin
gCollideMap[yy][xx] := gCollideMap[yy][xx] and t;
end;
end;
+{$ENDIF}
+
+{$IF DEFINED(HAS_COLLIDE_BITMAP)}
procedure CreateCollideMap();
var
a: Integer;
end;
end;
end;
+{$ENDIF}
+
procedure g_GFX_Init();
begin
- CreateCollideMap();
+ //CreateCollideMap();
end;
+
procedure g_GFX_Free();
var
a: Integer;
begin
Particles := nil;
SetLength(Particles, MaxParticles);
+ for a := 0 to High(Particles) do Particles[a].State := STATE_FREE;
CurrentParticle := 0;
if OnceAnims <> nil then
OnceAnims := nil;
end;
-
- gCollideMap := nil;
end;
-procedure CorrectOffsets(id: Integer);
-begin
- with Particles[id] do
- begin
- if (X >= 0) and (Y > 0) and
- (Y < Length(gCollideMap)) and (X < Length(gCollideMap[0])) and
- (ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) then
- offsetY := 1 // Ñòåíà ñâåðõó
- else
- offsetY := 0;
- if (X > 0) and (Y >= 0) and
- (Y < Length(gCollideMap)) and (X < Length(gCollideMap[0])) and
- (ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)) then
- offsetX := 1 // Ñòåíà ñëåâà
- else
- offsetX := 0;
- end;
+{
+procedure CorrectOffsets(id: Integer); inline;
+var
+ part: PParticle;
+begin
+ part := @Particles[id];
+ part.offsetX := 0;
+ part.offsetY := 0;
+ // check for upper wall
+ if isBlockedAt(part.X, part.Y-1) then part.offsetY := 1;
+ // check for left wall
+ if isBlockedAt(part.X-1, part.Y) then part.offsetX := 1;
end;
+}
+
-procedure g_GFX_SparkVel(fX, fY: Integer; Count: Word; VX, VY: Integer; DevX, DevY: Byte);
+procedure g_GFX_SparkVel (fX, fY: Integer; Count: Word; VX, VY: Integer; DevX, DevY: Byte);
var
a: Integer;
DevX1, DevX2,
l: Integer;
begin
l := Length(Particles);
- if l = 0 then
- Exit;
- if Count > l then
- Count := l;
+ if l = 0 then exit;
+ if Count > l then Count := l;
DevX1 := DevX div 2;
DevX2 := DevX + 1;
LiveTime := 30+Random(60);
ParticleType := PARTICLE_SPARK;
- CorrectOffsets(CurrentParticle);
+ {CorrectOffsets(CurrentParticle);}
end;
if CurrentParticle+2 > MaxParticles then
end;
end;
+
procedure g_GFX_Blood(fX, fY: Integer; Count: Word; vx, vy: Integer;
DevX, DevY: Word; CR, CG, CB: Byte; Kind: Byte = BLOOD_NORMAL);
var
X := fX - DevX1 + Random(DevX2);
Y := fY - DevY1 + Random(DevY2);
+ {
if (X < 0) or (X > gMapInfo.Width-1) or
(Y < 0) or (Y > gMapInfo.Height-1) or
ByteBool(gCollideMap[Y, X] and MARK_WALL) then
Continue;
+ }
+ if isWallAt(X, Y) then continue;
VelX := vx + (Random-Random)*3;
VelY := vy + (Random-Random)*3;
LiveTime := 120+Random(40);
ParticleType := PARTICLE_BLOOD;
- CorrectOffsets(CurrentParticle);
+ {CorrectOffsets(CurrentParticle);}
end;
if CurrentParticle >= MaxParticles-1 then
end;
end;
+
procedure g_GFX_Spark(fX, fY: Integer; Count: Word; Angle: SmallInt; DevX, DevY: Byte);
var
a: Integer;
LiveTime := 30+Random(60);
ParticleType := PARTICLE_SPARK;
- CorrectOffsets(CurrentParticle);
+ {CorrectOffsets(CurrentParticle);}
end;
if CurrentParticle+2 > MaxParticles then
LiveTime := 60+Random(60);
ParticleType := PARTICLE_WATER;
- CorrectOffsets(CurrentParticle);
+ {CorrectOffsets(CurrentParticle);}
end;
if CurrentParticle+2 > MaxParticles then
LiveTime := 60+Random(60);
ParticleType := PARTICLE_WATER;
- CorrectOffsets(CurrentParticle);
+ {CorrectOffsets(CurrentParticle);}
end;
if CurrentParticle+2 > MaxParticles then
end;
end;
+
procedure g_GFX_Bubbles(fX, fY: Integer; Count: Word; DevX, DevY: Byte);
var
a: Integer;
DevX1, DevX2,
DevY1, DevY2: Byte;
- l: Integer;
+ l, liquidx: Integer;
begin
l := Length(Particles);
if l = 0 then
(Y >= gMapInfo.Height) or (Y <= 0) then
Continue;
- if not ByteBool(gCollideMap[Y, X] and MARK_LIQUID) then
+ (*
+ // don't spawn bubbles outside of the liquid
+ if not isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
Continue;
+ *)
+
+ // trace liquid, so we'll know where it ends; do it in 8px steps for speed
+ // tracer will return `false` if we started outside of the liquid
+ if not g_Map_TraceLiquid(X, Y, 0, -8, liquidx, liquidTopY) then continue;
VelX := 0;
VelY := -1-Random;
LiveTime := 65535;
ParticleType := PARTICLE_BUBBLES;
- CorrectOffsets(CurrentParticle);
+ {CorrectOffsets(CurrentParticle);}
end;
if CurrentParticle+2 > MaxParticles then
end;
procedure g_GFX_SetMax(Count: Integer);
+var
+ a: Integer;
begin
- if Count > 50000 then
- Count := 50000;
+ if Count > 50000 then Count := 50000;
+ if (Count < 1) then Count := 1;
SetLength(Particles, Count);
+ for a := 0 to High(Particles) do Particles[a].State := STATE_FREE;
MaxParticles := Count;
- if CurrentParticle >= Count then
+ //if CurrentParticle >= Count then
CurrentParticle := 0;
end;
dX, dY: SmallInt;
b, len: Integer;
s: ShortInt;
- c: Byte;
+ //c: Byte;
begin
+ if not gpart_dbg_enabled then exit;
if Particles <> nil then
begin
w := gMapInfo.Width;
len := High(Particles);
for a := 0 to len do
- if Particles[a].State <> 0 then
+ begin
+ if Particles[a].State <> STATE_FREE then
+ begin
with Particles[a] do
begin
- if Time = LiveTime then
- State := STATE_FREE;
- if (X+1 >= w) or (Y+1 >= h) or (X <= 0) or (Y <= 0) then
- State := STATE_FREE;
- if State = STATE_FREE then
- Continue;
+ if Time = LiveTime then State := STATE_FREE;
+ if (X+1 >= w) or (Y+1 >= h) or (X <= 0) or (Y <= 0) then State := STATE_FREE;
+ if State = STATE_FREE then Continue;
+ //e_WriteLog(Format('particle #%d: %d', [State, ParticleType]), MSG_NOTIFY);
case ParticleType of
PARTICLE_BLOOD:
if gAdvBlood then
begin
if (State = STATE_STICK) then
+ {
if (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
(not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) and
(not ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)) and
- (not ByteBool(gCollideMap[Y, X+1] and MARK_BLOCKED)) then
+ (not ByteBool(gCollideMap[Y, X+1] and MARK_BLOCKED))
+ then
+ }
+ if (not isBlockedAt(X, Y-1)) and
+ (not isBlockedAt(X, Y+1)) and
+ (not isBlockedAt(X-1, Y)) and
+ (not isBlockedAt(X+1, Y))
+ then
begin // Îòëèïëà - êàïàåò
VelY := 0.5;
AccelY := 0.15;
Continue;
end;
- if not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED) then
+ if not isBlockedAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)} then
begin
- if ByteBool(gCollideMap[Y, X] and MARK_LIFTUP) then
+ if isLiftUpAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTUP)} then
begin // Ëèôò ââåðõ
if VelY > -4-Random(3) then
VelY := VelY - 0.8;
VelX := VelX + (Random-Random)*0.2;
AccelY := 0.15;
end;
- if ByteBool(gCollideMap[Y, X] and MARK_LIFTLEFT) then
+ if isLiftLeftAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTLEFT)} then
begin // Ïîòîê âëåâî
if VelX > -8-Random(3) then
VelX := VelX - 0.8;
AccelY := 0.15;
end;
- if ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT) then
+ if isLiftRightAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT)} then
begin // Ïîòîê âïðàâî
if VelX < 8+Random(3) then
VelX := VelX + 0.8;
if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) then
if (State <> STATE_STICK) and
- (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
- (not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)) and
- (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) then
+ (not isBlockedAt(X, Y-1) {ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)}) and
+ (not isBlockedAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)}) and
+ (not isBlockedAt(X, Y+1) {ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)}) then
begin // Âèñèò â âîçäóõå - êàïàåò
VelY := 0.8;
AccelY := 0.5;
Break;
end;
- c := gCollideMap[Y, X+s];
+ //c := gCollideMap[Y, X+s];
- if ByteBool(c and MARK_BLOCKED) then
+ if isBlockedAt(X+s, Y) {ByteBool(c and MARK_BLOCKED)} then
begin // Ñòåíà/äâåðü
VelX := 0;
VelY := 0;
Break;
end;
- c := gCollideMap[Y+s, X];
+ //c := gCollideMap[Y+s, X];
- if ByteBool(c and MARK_BLOCKED) then
+ if isBlockedAt(X, Y+s) {ByteBool(c and MARK_BLOCKED)} then
begin // Ñòåíà/äâåðü
VelX := 0;
VelY := 0;
if (X+dX >= w) or (Y+dY >= h) or
(X+dX <= 0) or (Y+dY <= 0) or
- ByteBool(gCollideMap[Y+dY, X+dX] and MARK_BLOCKED) then
+ isBlockedAt(X+dX, Y+dY) {ByteBool(gCollideMap[Y+dY, X+dX] and MARK_BLOCKED)} then
begin // Ñòåíà/äâåðü/ãðàíèöà
State := STATE_FREE;
VelX := 0;
VelY := VelY + AccelY;
// Êðîâü ðàñòâîðÿåòñÿ â æèäêîñòè:
- if ByteBool(gCollideMap[Y, X] and MARK_LIQUID) then
+ if isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then
begin
Inc(Time);
dY := Round(VelY);
if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) and
- (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
- (not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)) and
- (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) then
+ (not isBlockedAt(X, Y-1) {ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)}) and
+ (not isBlockedAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)}) and
+ (not isBlockedAt(X, Y+1) {ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)}) then
begin // Âèñèò â âîçäóõå
VelY := 0.8;
AccelY := 0.5;
Break;
end;
- c := gCollideMap[Y, X+s];
+ //c := gCollideMap[Y, X+s];
- if ByteBool(c and MARK_BLOCKED) then
+ if isBlockedAt(X+s, Y) {ByteBool(c and MARK_BLOCKED)} then
begin // Ñòåíà/äâåðü - ïàäàåò âåðòèêàëüíî
VelX := 0;
AccelX := 0;
Break;
end
else // Ïóñòî:
- if c = MARK_FREE then
+ if not isAnythingAt(X+s, Y) {c = MARK_FREE} then
X := X + s
else // Îñòàëüíîå:
begin
Break;
end;
- c := gCollideMap[Y+s, X];
+ //c := gCollideMap[Y+s, X];
- if ByteBool(c and MARK_BLOCKED) then
+ if isBlockedAt(X, Y+s) {ByteBool(c and MARK_BLOCKED)} then
begin // Ñòåíà/äâåðü - ïàäàåò âåðòèêàëüíî
if s < 0 then
begin
Break;
end
else // Ïóñòî:
- if c = MARK_FREE then
+ if not isAnythingAt(X, Y+s) {c = MARK_FREE} then
Y := Y + s
else // Îñàëüíîå:
begin
begin // Ñòåêàåò/îòëèïàåò
VelY := 0.5;
AccelY := 0.15;
- if (not ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)) and
- (not ByteBool(gCollideMap[Y, X+1] and MARK_BLOCKED)) then
+ if (not isBlockedAt(X-1, Y) {ByteBool(gCollideMap[Y, X-1] and MARK_BLOCKED)}) and
+ (not isBlockedAt(X+1, Y) {ByteBool(gCollideMap[Y, X+1] and MARK_BLOCKED)}) then
State := STATE_NORMAL;
Continue;
end;
- if not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED) then
+ if not isBlockedAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)} then
begin
- if ByteBool(gCollideMap[Y, X] and MARK_LIFTUP) then
+ if isLiftUpAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTUP)} then
begin // Ëèôò ââåðõ
if VelY > -4-Random(3) then
VelY := VelY - 0.8;
VelX := VelX + (Random-Random)*0.2;
AccelY := 0.15;
end;
- if ByteBool(gCollideMap[Y, X] and MARK_LIFTLEFT) then
+ if isLiftLeftAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTLEFT)} then
begin // Ïîòîê âëåâî
if VelX > -8-Random(3) then
VelX := VelX - 0.8;
AccelY := 0.15;
end;
- if ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT) then
+ if isLiftRightAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT)} then
begin // Ïîòîê âïðàâî
if VelX < 8+Random(3) then
VelX := VelX + 0.8;
if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) then
if (State <> STATE_STICK) and
- (not ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)) and
- (not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)) and
- (not ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)) then
+ (not isBlockedAt(X, Y-1) {ByteBool(gCollideMap[Y-1, X] and MARK_BLOCKED)}) and
+ (not isBlockedAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)}) and
+ (not isBlockedAt(X, Y+1) {ByteBool(gCollideMap[Y+1, X] and MARK_BLOCKED)}) then
begin // Âèñèò â âîçäóõå - êàïàåò
VelY := 0.8;
AccelY := 0.5;
Break;
end;
- c := gCollideMap[Y, X+s];
+ //c := gCollideMap[Y, X+s];
- if ByteBool(c and MARK_LIQUID) and (dY > 0) then
+ if isLiquidAt(X+s, Y) {ByteBool(c and MARK_LIQUID)} and (dY > 0) then
begin // Ñáîêó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò
State := STATE_FREE;
Break;
end;
- if ByteBool(c and MARK_BLOCKED) then
+ if isBlockedAt(X+s, Y) {ByteBool(c and MARK_BLOCKED)} then
begin // Ñòåíà/äâåðü
VelX := 0;
VelY := 0;
Break;
end;
- c := gCollideMap[Y+s, X];
+ //c := gCollideMap[Y+s, X];
- if ByteBool(c and MARK_LIQUID) and (dY > 0) then
+ if isLiquidAt(X, Y+s) {ByteBool(c and MARK_LIQUID)} and (dY > 0) then
begin // Ñíèçó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò
State := STATE_FREE;
Break;
end;
- if ByteBool(c and MARK_BLOCKED) then
+ if isBlockedAt(X, Y+s) {ByteBool(c and MARK_BLOCKED)} then
begin // Ñòåíà/äâåðü
VelX := 0;
VelY := 0;
Break;
end;
- if not ByteBool(gCollideMap[Y+s, X] and MARK_LIQUID) then
+ if not isLiquidAt(X, Y+s) {ByteBool(gCollideMap[Y+s, X] and MARK_LIQUID)} then
begin // Óæå íå æèäêîñòü
State := STATE_FREE;
Break;
end;
end; // case
- CorrectOffsets(a);
- end;
+ {CorrectOffsets(a);}
+ end; // with
+ end; // if
+ end; // for
end; // Particles <> nil
if OnceAnims <> nil then