X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fgame%2Fg_gfx.pas;h=ab895762d3cae8f6b59ed2cc18fe77fc87ed3650;hb=4caa7355c2a35f38ee6fbd541cfed72751a520a4;hp=37036278d08175ca4dbf3a93c88e724ac32995f7;hpb=e80d55312d7d3bacaa3d642a83cda0c8a1026a97;p=d2df-sdl.git diff --git a/src/game/g_gfx.pas b/src/game/g_gfx.pas index 3703627..ab89576 100644 --- a/src/game/g_gfx.pas +++ b/src/game/g_gfx.pas @@ -14,13 +14,13 @@ * along with this program. If not, see . *) {$INCLUDE ../shared/a_modes.inc} -{.$DEFINE HAS_COLLIDE_BITMAP} +{$DEFINE D2F_NEW_SPARK_THINKER} unit g_gfx; interface uses - g_textures; + e_log, g_textures; const BLOOD_NORMAL = 0; @@ -60,20 +60,21 @@ procedure g_GFX_Update(); procedure g_GFX_Draw(); -{$IF DEFINED(HAS_COLLIDE_BITMAP)} var - gCollideMap: Array of Array of Byte; -{$ENDIF} + gpart_dbg_enabled: Boolean = true; + gpart_dbg_phys_enabled: Boolean = true; implementation uses - g_map, g_basic, Math, e_graphics, GL, GLExt, + g_map, g_panel, g_basic, Math, e_graphics, GL, GLExt, g_options, g_console, SysUtils, g_triggers, MAPDEF, g_game, g_language, g_net; type + PParticle = ^TParticle; + TParticle = record X, Y: Integer; VelX, VelY: Single; @@ -84,6 +85,19 @@ type State: Byte; ParticleType: Byte; offsetX, offsetY: ShortInt; + // for bubbles + liquidTopY: Integer; // don't float higher than this + + //k8: sorry, i have to emulate virtual methods this way, 'cause i haet `Object` + + procedure thinkerBlood (); + procedure thinkerSpark (); + procedure thinkerBubble (); + procedure thinkerWater (); + + function alive (): Boolean; inline; + procedure die (); inline; + procedure think (); inline; end; TOnceAnim = record @@ -102,18 +116,86 @@ const 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 TParticle.alive (): Boolean; inline; begin result := (State <> STATE_FREE); end; +procedure TParticle.die (); inline; begin State := STATE_FREE; end; + +procedure TParticle.think (); inline; +begin + case ParticleType of + PARTICLE_BLOOD: thinkerBlood(); + PARTICLE_SPARK: thinkerSpark(); + PARTICLE_BUBBLES: thinkerBubble(); + PARTICLE_WATER: thinkerWater(); + end; +end; + + +// ////////////////////////////////////////////////////////////////////////// // +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 DEFINED(HAS_COLLIDE_BITMAP)} +{$IF not DEFINED(HAS_COLLIDE_BITMAP)} +begin +end; +{$ELSE} var yy, y2, xx, x2: Integer; -{$ENDIF} begin -{$IF DEFINED(HAS_COLLIDE_BITMAP)} if x < 0 then begin Width := Width + x; @@ -158,16 +240,15 @@ begin for xx := x to x2 do gCollideMap[yy][xx] := gCollideMap[yy][xx] and t; end; -{$ENDIF} end; +{$ENDIF} + -procedure CreateCollideMap(); {$IF DEFINED(HAS_COLLIDE_BITMAP)} +procedure CreateCollideMap(); var a: Integer; -{$ENDIF} begin -{$IF DEFINED(HAS_COLLIDE_BITMAP)} g_Game_SetLoadingText(_lc[I_LOAD_COLLIDE_MAP]+' 1/6', 0, False); SetLength(gCollideMap, gMapInfo.Height+1); for a := 0 to High(gCollideMap) do @@ -237,20 +318,23 @@ begin g_Mark(X, Y, Width, Height, MARK_WALL, True); end; end; -{$ENDIF} 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].die(); CurrentParticle := 0; if OnceAnims <> nil then @@ -260,51 +344,539 @@ begin OnceAnims := nil; end; +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 TParticle.thinkerBlood (); +var + w, h: Integer; + dX, dY: SmallInt; + b: Integer; + s: ShortInt; +begin + w := gMapInfo.Width; + h := gMapInfo.Height; + + 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 + } + 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; + State := STATE_NORMAL; + end + else + if Random(200) = 100 then + begin // Ïðèëåïëåíà - íî âîçìîæíî ñòåêàåò + VelY := 0.5; + AccelY := 0.15; + exit; + end; + + if not isBlockedAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)} then + begin + if isLiftUpAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTUP)} then + begin // Ëèôò ââåðõ + if VelY > -4-Random(3) then + VelY := VelY - 0.8; + if Abs(VelX) > 0.1 then + VelX := VelX - VelX/10.0; + VelX := VelX + (Random-Random)*0.2; + AccelY := 0.15; + end; + 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 isLiftRightAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT)} then + begin // Ïîòîê âïðàâî + if VelX < 8+Random(3) then + VelX := VelX + 0.8; + AccelY := 0.15; + end; + end; + + dX := Round(VelX); + dY := Round(VelY); + + if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) then + if (State <> STATE_STICK) and + (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; + State := STATE_NORMAL; + end; + + if dX <> 0 then + begin + if dX > 0 then + s := 1 + else + s := -1; + + dX := Abs(dX); + + for b := 1 to dX do + begin + if (X+s >= w) or (X+s <= 0) then begin die(); break; end; + + //c := gCollideMap[Y, X+s]; + + if isBlockedAt(X+s, Y) {ByteBool(c and MARK_BLOCKED)} then + begin // Ñòåíà/äâåðü + VelX := 0; + VelY := 0; + AccelX := 0; + AccelY := 0; + State := STATE_STICK; + Break; + end; + + X := X+s; + end; + end; + + if dY <> 0 then + begin + if dY > 0 then + s := 1 + else + s := -1; + + dY := Abs(dY); + + for b := 1 to dY do + begin + if (Y+s >= h) or (Y+s <= 0) then begin die(); break; end; + + //c := gCollideMap[Y+s, X]; + + if isBlockedAt(X, Y+s) {ByteBool(c and MARK_BLOCKED)} then + begin // Ñòåíà/äâåðü + VelX := 0; + VelY := 0; + AccelX := 0; + AccelY := 0; + if (s > 0) and (State <> STATE_STICK) then + State := STATE_NORMAL + else + State := STATE_STICK; + Break; + end; + + Y := Y+s; + end; + end; + end // if gAdvBlood + else + begin + dX := Round(VelX); + dY := Round(VelY); + + if (X+dX >= w) or (Y+dY >= h) or + (X+dX <= 0) or (Y+dY <= 0) or + isBlockedAt(X+dX, Y+dY) {ByteBool(gCollideMap[Y+dY, X+dX] and MARK_BLOCKED)} then + begin // Ñòåíà/äâåðü/ãðàíèöà + die(); + VelX := 0; + VelY := 0; + end + else + begin + Y := Y + dY; + X := X + dX; + end; + end; + + VelX := VelX + AccelX; + VelY := VelY + AccelY; + +// Êðîâü ðàñòâîðÿåòñÿ â æèäêîñòè: + if isLiquidAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIQUID)} then + begin + Inc(Time); + + Alpha := 255 - Trunc((255.0 * Time) / LiveTime); + end; +end; + + +// ////////////////////////////////////////////////////////////////////////// // +procedure TParticle.thinkerSpark (); +var + dX, dY: SmallInt; + {$IF not DEFINED(D2F_NEW_SPARK_THINKER)} + b: Integer; + s: ShortInt; + {$ELSE} + pan: TPanel; + ex, ey: Integer; + {$ENDIF} +begin + dX := Round(VelX); + dY := Round(VelY); - {$IF DEFINED(HAS_COLLIDE_BITMAP)} - gCollideMap := nil; + {$IF DEFINED(D2F_NEW_SPARK_THINKER)} + if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) then + begin + pan := g_Map_traceToNearest(X, Y-1, X, Y+1, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey); + end; + {$ELSE} + if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) and + (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; + end; {$ENDIF} + + if (dX <> 0) then + begin + {$IF DEFINED(D2F_NEW_SPARK_THINKER)} + pan := g_Map_traceToNearest(X, Y, X+dX, Y, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey); + //e_WriteLog(Format('spark h-trace: (%d,%d)-(%d,%d); dx=%d; end=(%d,%d); hit=%d', [X, Y, X+dX, Y, dX, ex, ey, Integer(pan <> nil)]), MSG_NOTIFY); + X := ex; + // free to ride? + if (pan <> nil) then + begin + // nope + if ((pan.tag and (GridTagAcid1 or GridTagAcid2 or GridTagWater)) <> 0) then begin die(); exit; end; + VelX := 0; + AccelX := 0; + end; + if (X < 0) or (X >= gMapInfo.Width) then begin die(); exit; end; + {$ELSE} + if (dX > 0) then s := 1 else s := -1; + dX := Abs(dX); + for b := 1 to dX do + begin + if (X+s >= gMapInfo.Width) or (X+s <= 0) then begin die(); break; end; + //c := gCollideMap[Y, X+s]; + if isBlockedAt(X+s, Y) {ByteBool(c and MARK_BLOCKED)} then + begin // Ñòåíà/äâåðü - ïàäàåò âåðòèêàëüíî + VelX := 0; + AccelX := 0; + Break; + end + else // Ïóñòî: + if not isAnythingAt(X+s, Y) {c = MARK_FREE} then + X := X + s + else // Îñòàëüíîå: + begin + die(); + break; + end; + end; + {$ENDIF} + end; + + if (dY <> 0) then + begin + {$IF DEFINED(D2F_NEW_SPARK_THINKER)} + pan := g_Map_traceToNearest(X, Y, X, Y+dY, (GridTagWall or GridTagDoor or GridTagStep or GridTagAcid1 or GridTagAcid2 or GridTagWater), @ex, @ey); + //e_WriteLog(Format('spark y-trace: (%d,%d)-(%d,%d); dy=%d; end=(%d,%d); hit=%d', [X, Y, X, Y+dY, dY, ex, ey, Integer(pan <> nil)]), MSG_NOTIFY); + (* + if (pan <> nil) then + begin + e_WriteLog(Format('spark y-trace: %08x (%d,%d)-(%d,%d); dy=%d; end=(%d,%d); hittag=%04x', [LongWord(@self), X, Y, X, Y+dY, dY, ex, ey, pan.tag]), MSG_NOTIFY); + end + else + begin + e_WriteLog(Format('spark y-trace: %08x (%d,%d)-(%d,%d); dy=%d; end=(%d,%d); hit=%d', [LongWord(@self), X, Y, X, Y+dY, dY, ex, ey, Integer(pan <> nil)]), MSG_NOTIFY); + end; + *) + Y := ey; + // free to ride? + if (pan <> nil) then + begin + //die(); exit; + // nope + if ((pan.tag and (GridTagAcid1 or GridTagAcid2 or GridTagWater)) <> 0) then begin die(); exit; end; + if (dY < 0) then + begin + VelY := -VelY; + AccelY := abs(AccelY); + end + else + begin + VelX := 0; + AccelX := 0; + VelY := 0; + AccelY := 0.8; + end; + end; + if (Y < 0) or (Y >= gMapInfo.Height) then begin die(); exit; end; + {$ELSE} + if (dY > 0) then s := 1 else s := -1; + dY := Abs(dY); + for b := 1 to dY do + begin + if (Y+s >= gMapInfo.Height) or (Y+s <= 0) then begin die(); break; end; + //c := gCollideMap[Y+s, X]; + if isBlockedAt(X, Y+s) {ByteBool(c and MARK_BLOCKED)} then + begin // Ñòåíà/äâåðü - ïàäàåò âåðòèêàëüíî + if s < 0 then + begin + VelY := -VelY; + AccelY := Abs(AccelY); + end + else // Èëè íå ïàäàåò + begin + VelX := 0; + AccelX := 0; + VelY := 0; + AccelY := 0.8; + end; + + Break; + end + else // Ïóñòî: + if not isAnythingAt(X, Y+s) {c = MARK_FREE} then + Y := Y + s + else // Îñàëüíîå: + begin + die(); + break; + end; + end; + {$ENDIF} + end; + + if (VelX <> 0.0) then VelX += AccelX; + + if (VelY <> 0.0) then + begin + if (AccelY < 10) then AccelY += 0.08; + VelY += AccelY; + end; + + Time += 1; end; -{$IF DEFINED(HAS_COLLIDE_BITMAP)} -procedure CorrectOffsets(id: Integer); +// ////////////////////////////////////////////////////////////////////////// // +procedure TParticle.thinkerBubble (); +var + h: Integer; + dY: SmallInt; + b: Integer; + s: ShortInt; begin - with Particles[id] do + h := gMapInfo.Height; + + dY := Round(VelY); + + if dY <> 0 then 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 // Ñòåíà ñâåðõó + if dY > 0 then + s := 1 else - offsetY := 0; + s := -1; + + for b := 1 to Abs(dY) do + begin + if (Y+s >= h) or (Y+s <= 0) then begin die(); break; end; - 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 // Ñòåíà ñëåâà + (* + if not isLiquidAt(X, Y+s) {ByteBool(gCollideMap[Y+s, X] and MARK_LIQUID)} then + begin // Óæå íå æèäêîñòü + State := STATE_FREE; + Break; + end; + *) + // we traced liquid before, so don't bother checking + if (Y+s <= liquidTopY) then begin die(); break; end; + + Y := Y+s; + end; + end; + + if VelY > -4 then + VelY := VelY + AccelY; + + Time := Time + 1; +end; + + +// ////////////////////////////////////////////////////////////////////////// // +procedure TParticle.thinkerWater (); +var + w, h: Integer; + dX, dY: SmallInt; + b: Integer; + s: ShortInt; +begin + w := gMapInfo.Width; + h := gMapInfo.Height; + + if (State = STATE_STICK) and (Random(30) = 15) then + begin // Ñòåêàåò/îòëèïàåò + VelY := 0.5; + AccelY := 0.15; + 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; + exit; + end; + + if not isBlockedAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_BLOCKED)} then + begin + if isLiftUpAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTUP)} then + begin // Ëèôò ââåðõ + if VelY > -4-Random(3) then + VelY := VelY - 0.8; + if Abs(VelX) > 0.1 then + VelX := VelX - VelX/10.0; + VelX := VelX + (Random-Random)*0.2; + AccelY := 0.15; + end; + 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 isLiftRightAt(X, Y) {ByteBool(gCollideMap[Y, X] and MARK_LIFTRIGHT)} then + begin // Ïîòîê âïðàâî + if VelX < 8+Random(3) then + VelX := VelX + 0.8; + AccelY := 0.15; + end; + end; + + dX := Round(VelX); + dY := Round(VelY); + + if (Abs(VelX) < 0.1) and (Abs(VelY) < 0.1) then + if (State <> STATE_STICK) and + (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; + State := STATE_NORMAL; + end; + + if dX <> 0 then + begin + if dX > 0 then + s := 1 else - offsetX := 0; + s := -1; + + for b := 1 to Abs(dX) do + begin + // Ñáîêó ãðàíèöà? + if (X+s >= w) or (X+s <= 0) then begin die(); break;end; + + //c := gCollideMap[Y, X+s]; + + // Ñáîêó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò? + if isLiquidAt(X+s, Y) {ByteBool(c and MARK_LIQUID)} and (dY > 0) then begin die(); break; end; + + if isBlockedAt(X+s, Y) {ByteBool(c and MARK_BLOCKED)} then + begin // Ñòåíà/äâåðü + VelX := 0; + VelY := 0; + AccelX := 0; + AccelY := 0; + State := STATE_STICK; + Break; + end; + + X := X+s; + end; end; + + if dY <> 0 then + begin + if dY > 0 then + s := 1 + else + s := -1; + + for b := 1 to Abs(dY) do + begin + // Ñíèçó/ñâåðõó ãðàíèöà + if (Y+s >= h) or (Y+s <= 0) then begin die(); break; end; + + //c := gCollideMap[Y+s, X]; + + // Ñíèçó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò + if isLiquidAt(X, Y+s) {ByteBool(c and MARK_LIQUID)} and (dY > 0) then begin die(); break; end; + + if isBlockedAt(X, Y+s) {ByteBool(c and MARK_BLOCKED)} then + begin // Ñòåíà/äâåðü + VelX := 0; + VelY := 0; + AccelX := 0; + AccelY := 0; + if (s > 0) and (State <> STATE_STICK) then + State := STATE_NORMAL + else + State := STATE_STICK; + Break; + end; + + Y := Y+s; + end; + end; + + VelX := VelX + AccelX; + VelY := VelY + AccelY; + + Time := Time + 1; end; -{$ENDIF} -procedure g_GFX_SparkVel(fX, fY: Integer; Count: Word; VX, VY: Integer; DevX, DevY: Byte); -{$IF DEFINED(HAS_COLLIDE_BITMAP)} +// ////////////////////////////////////////////////////////////////////////// // +procedure g_GFX_SparkVel (fX, fY: Integer; Count: Word; VX, VY: Integer; DevX, DevY: Byte); var a: Integer; DevX1, DevX2, DevY1, DevY2: Byte; l: Integer; -{$ENDIF} begin -{$IF DEFINED(HAS_COLLIDE_BITMAP)} 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; @@ -340,7 +912,7 @@ begin LiveTime := 30+Random(60); ParticleType := PARTICLE_SPARK; - CorrectOffsets(CurrentParticle); + {CorrectOffsets(CurrentParticle);} end; if CurrentParticle+2 > MaxParticles then @@ -348,12 +920,11 @@ begin else CurrentParticle := CurrentParticle+1; end; -{$ENDIF} end; + procedure g_GFX_Blood(fX, fY: Integer; Count: Word; vx, vy: Integer; DevX, DevY: Word; CR, CG, CB: Byte; Kind: Byte = BLOOD_NORMAL); -{$IF DEFINED(HAS_COLLIDE_BITMAP)} var a: Integer; DevX1, DevX2, @@ -361,9 +932,7 @@ var l: Integer; CRnd: Byte; CC: SmallInt; -{$ENDIF} begin -{$IF DEFINED(HAS_COLLIDE_BITMAP)} if Kind = BLOOD_SPARKS then begin g_GFX_SparkVel(fX, fY, 2 + Random(2), -VX div 2, -VY div 2, DevX, DevY); @@ -387,10 +956,13 @@ begin 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; @@ -437,7 +1009,7 @@ begin LiveTime := 120+Random(40); ParticleType := PARTICLE_BLOOD; - CorrectOffsets(CurrentParticle); + {CorrectOffsets(CurrentParticle);} end; if CurrentParticle >= MaxParticles-1 then @@ -445,11 +1017,10 @@ begin else CurrentParticle := CurrentParticle+1; end; -{$ENDIF} end; + procedure g_GFX_Spark(fX, fY: Integer; Count: Word; Angle: SmallInt; DevX, DevY: Byte); -{$IF DEFINED(HAS_COLLIDE_BITMAP)} var a: Integer; b: Single; @@ -457,9 +1028,7 @@ var DevY1, DevY2: Byte; BaseVelX, BaseVelY: Single; l: Integer; -{$ENDIF} begin -{$IF DEFINED(HAS_COLLIDE_BITMAP)} l := Length(Particles); if l = 0 then Exit; @@ -502,7 +1071,7 @@ begin LiveTime := 30+Random(60); ParticleType := PARTICLE_SPARK; - CorrectOffsets(CurrentParticle); + {CorrectOffsets(CurrentParticle);} end; if CurrentParticle+2 > MaxParticles then @@ -510,19 +1079,15 @@ begin else CurrentParticle := CurrentParticle+1; end; -{$ENDIF} end; procedure g_GFX_Water(fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DevX, DevY, Color: Byte); -{$IF DEFINED(HAS_COLLIDE_BITMAP)} var a: Integer; DevX1, DevX2, DevY1, DevY2: Byte; l: Integer; -{$ENDIF} begin -{$IF DEFINED(HAS_COLLIDE_BITMAP)} l := Length(Particles); if l = 0 then Exit; @@ -588,7 +1153,7 @@ begin LiveTime := 60+Random(60); ParticleType := PARTICLE_WATER; - CorrectOffsets(CurrentParticle); + {CorrectOffsets(CurrentParticle);} end; if CurrentParticle+2 > MaxParticles then @@ -596,17 +1161,13 @@ begin else CurrentParticle := CurrentParticle+1; end; -{$ENDIF} end; procedure g_GFX_SimpleWater(fX, fY: Integer; Count: Word; fVelX, fVelY: Single; DefColor, CR, CG, CB: Byte); -{$IF DEFINED(HAS_COLLIDE_BITMAP)} var a: Integer; l: Integer; -{$ENDIF} begin -{$IF DEFINED(HAS_COLLIDE_BITMAP)} l := Length(Particles); if l = 0 then Exit; @@ -677,7 +1238,7 @@ begin LiveTime := 60+Random(60); ParticleType := PARTICLE_WATER; - CorrectOffsets(CurrentParticle); + {CorrectOffsets(CurrentParticle);} end; if CurrentParticle+2 > MaxParticles then @@ -685,19 +1246,16 @@ begin else CurrentParticle := CurrentParticle+1; end; -{$ENDIF} end; + procedure g_GFX_Bubbles(fX, fY: Integer; Count: Word; DevX, DevY: Byte); -{$IF DEFINED(HAS_COLLIDE_BITMAP)} var a: Integer; DevX1, DevX2, DevY1, DevY2: Byte; - l: Integer; -{$ENDIF} + l, liquidx: Integer; begin -{$IF DEFINED(HAS_COLLIDE_BITMAP)} l := Length(Particles); if l = 0 then Exit; @@ -720,8 +1278,15 @@ begin (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; @@ -738,7 +1303,7 @@ begin LiveTime := 65535; ParticleType := PARTICLE_BUBBLES; - CorrectOffsets(CurrentParticle); + {CorrectOffsets(CurrentParticle);} end; if CurrentParticle+2 > MaxParticles then @@ -746,17 +1311,19 @@ begin else CurrentParticle := CurrentParticle+1; end; -{$ENDIF} 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].die(); MaxParticles := Count; - if CurrentParticle >= Count then + //if CurrentParticle >= Count then CurrentParticle := 0; end; @@ -809,15 +1376,10 @@ end; procedure g_GFX_Update(); var a: Integer; -{$IF DEFINED(HAS_COLLIDE_BITMAP)} w, h: Integer; - dX, dY: SmallInt; - b, len: Integer; - s: ShortInt; - c: Byte; -{$ENDIF} + len: Integer; begin -{$IF DEFINED(HAS_COLLIDE_BITMAP)} + if not gpart_dbg_enabled then exit; if Particles <> nil then begin w := gMapInfo.Width; @@ -826,462 +1388,21 @@ begin len := High(Particles); for a := 0 to len do - if Particles[a].State <> 0 then + begin + if Particles[a].alive 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; - - case ParticleType of - PARTICLE_BLOOD: - begin - 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 - begin // Îòëèïëà - êàïàåò - VelY := 0.5; - AccelY := 0.15; - State := STATE_NORMAL; - end - else - if Random(200) = 100 then - begin // Ïðèëåïëåíà - íî âîçìîæíî ñòåêàåò - VelY := 0.5; - AccelY := 0.15; - Continue; - end; - - if not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED) then - begin - if ByteBool(gCollideMap[Y, X] and MARK_LIFTUP) then - begin // Ëèôò ââåðõ - if VelY > -4-Random(3) then - VelY := VelY - 0.8; - if Abs(VelX) > 0.1 then - VelX := VelX - VelX/10.0; - VelX := VelX + (Random-Random)*0.2; - AccelY := 0.15; - end; - if 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 - begin // Ïîòîê âïðàâî - if VelX < 8+Random(3) then - VelX := VelX + 0.8; - AccelY := 0.15; - end; - end; - - dX := Round(VelX); - dY := Round(VelY); - - 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 - begin // Âèñèò â âîçäóõå - êàïàåò - VelY := 0.8; - AccelY := 0.5; - State := STATE_NORMAL; - end; - - if dX <> 0 then - begin - if dX > 0 then - s := 1 - else - s := -1; - - dX := Abs(dX); - - for b := 1 to dX do - begin - if (X+s >= w) or (X+s <= 0) then - begin - State := STATE_FREE; - Break; - end; - - c := gCollideMap[Y, X+s]; - - if ByteBool(c and MARK_BLOCKED) then - begin // Ñòåíà/äâåðü - VelX := 0; - VelY := 0; - AccelX := 0; - AccelY := 0; - State := STATE_STICK; - Break; - end; - - X := X+s; - end; - end; - - if dY <> 0 then - begin - if dY > 0 then - s := 1 - else - s := -1; - - dY := Abs(dY); - - for b := 1 to dY do - begin - if (Y+s >= h) or (Y+s <= 0) then - begin - State := STATE_FREE; - Break; - end; - - c := gCollideMap[Y+s, X]; - - if ByteBool(c and MARK_BLOCKED) then - begin // Ñòåíà/äâåðü - VelX := 0; - VelY := 0; - AccelX := 0; - AccelY := 0; - if (s > 0) and (State <> STATE_STICK) then - State := STATE_NORMAL - else - State := STATE_STICK; - Break; - end; - - Y := Y+s; - end; - end; - end // if gAdvBlood - else - begin - dX := Round(VelX); - dY := Round(VelY); - - 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 - begin // Ñòåíà/äâåðü/ãðàíèöà - State := STATE_FREE; - VelX := 0; - VelY := 0; - end - else - begin - Y := Y + dY; - X := X + dX; - end; - end; - - VelX := VelX + AccelX; - VelY := VelY + AccelY; - - // Êðîâü ðàñòâîðÿåòñÿ â æèäêîñòè: - if ByteBool(gCollideMap[Y, X] and MARK_LIQUID) then - begin - Inc(Time); - - Alpha := 255 - Trunc((255.0 * Time) / LiveTime); - end; - end; - - PARTICLE_SPARK: - begin - dX := Round(VelX); - 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 - begin // Âèñèò â âîçäóõå - VelY := 0.8; - AccelY := 0.5; - end; - - if dX <> 0 then - begin - if dX > 0 then - s := 1 - else - s := -1; - - dX := Abs(dX); - - for b := 1 to dX do - begin - if (X+s >= w) or (X+s <= 0) then - begin - State := STATE_FREE; - Break; - end; - - c := gCollideMap[Y, X+s]; - - if ByteBool(c and MARK_BLOCKED) then - begin // Ñòåíà/äâåðü - ïàäàåò âåðòèêàëüíî - VelX := 0; - AccelX := 0; - Break; - end - else // Ïóñòî: - if c = MARK_FREE then - X := X + s - else // Îñòàëüíîå: - begin - State := STATE_FREE; - Break; - end; - end; - end; - - if dY <> 0 then - begin - if dY > 0 then - s := 1 - else - s := -1; - - dY := Abs(dY); - - for b := 1 to dY do - begin - if (Y+s >= h) or (Y+s <= 0) then - begin - State := STATE_FREE; - Break; - end; - - c := gCollideMap[Y+s, X]; - - if ByteBool(c and MARK_BLOCKED) then - begin // Ñòåíà/äâåðü - ïàäàåò âåðòèêàëüíî - if s < 0 then - begin - VelY := -VelY; - AccelY := Abs(AccelY); - end - else // Èëè íå ïàäàåò - begin - VelX := 0; - AccelX := 0; - VelY := 0; - AccelY := 0.8; - end; - - Break; - end - else // Ïóñòî: - if c = MARK_FREE then - Y := Y + s - else // Îñàëüíîå: - begin - State := STATE_FREE; - Break; - end; - end; - end; - - if VelX <> 0.0 then - VelX := VelX + AccelX; - if VelY <> 0.0 then - begin - if AccelY < 10 then - AccelY := AccelY + 0.08; - VelY := VelY + AccelY; - end; - - Time := Time + 1; - end; - - PARTICLE_WATER: - begin - if (State = STATE_STICK) and (Random(30) = 15) then - 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 - State := STATE_NORMAL; - Continue; - end; - - if not ByteBool(gCollideMap[Y, X] and MARK_BLOCKED) then - begin - if ByteBool(gCollideMap[Y, X] and MARK_LIFTUP) then - begin // Ëèôò ââåðõ - if VelY > -4-Random(3) then - VelY := VelY - 0.8; - if Abs(VelX) > 0.1 then - VelX := VelX - VelX/10.0; - VelX := VelX + (Random-Random)*0.2; - AccelY := 0.15; - end; - if 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 - begin // Ïîòîê âïðàâî - if VelX < 8+Random(3) then - VelX := VelX + 0.8; - AccelY := 0.15; - end; - end; - - dX := Round(VelX); - dY := Round(VelY); - - 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 - begin // Âèñèò â âîçäóõå - êàïàåò - VelY := 0.8; - AccelY := 0.5; - State := STATE_NORMAL; - end; - - if dX <> 0 then - begin - if dX > 0 then - s := 1 - else - s := -1; - - for b := 1 to Abs(dX) do - begin - if (X+s >= w) or (X+s <= 0) then - begin // Ñáîêó ãðàíèöà - State := STATE_FREE; - Break; - end; - - c := gCollideMap[Y, X+s]; - - if ByteBool(c and MARK_LIQUID) and (dY > 0) then - begin // Ñáîêó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò - State := STATE_FREE; - Break; - end; - - if ByteBool(c and MARK_BLOCKED) then - begin // Ñòåíà/äâåðü - VelX := 0; - VelY := 0; - AccelX := 0; - AccelY := 0; - State := STATE_STICK; - Break; - end; - - X := X+s; - end; - end; - - if dY <> 0 then - begin - if dY > 0 then - s := 1 - else - s := -1; - - for b := 1 to Abs(dY) do - begin - if (Y+s >= h) or (Y+s <= 0) then - begin // Ñíèçó/ñâåðõó ãðàíèöà - State := STATE_FREE; - Break; - end; - - c := gCollideMap[Y+s, X]; - - if ByteBool(c and MARK_LIQUID) and (dY > 0) then - begin // Ñíèçó æèäêîñòü, à ÷àñòèöà óæå ïàäàåò - State := STATE_FREE; - Break; - end; - - if ByteBool(c and MARK_BLOCKED) then - begin // Ñòåíà/äâåðü - VelX := 0; - VelY := 0; - AccelX := 0; - AccelY := 0; - if (s > 0) and (State <> STATE_STICK) then - State := STATE_NORMAL - else - State := STATE_STICK; - Break; - end; - - Y := Y+s; - end; - end; - - VelX := VelX + AccelX; - VelY := VelY + AccelY; - - Time := Time + 1; - end; - - PARTICLE_BUBBLES: - begin - dY := Round(VelY); - - if dY <> 0 then - begin - if dY > 0 then - s := 1 - else - s := -1; - - for b := 1 to Abs(dY) do - begin - if (Y+s >= h) or (Y+s <= 0) then - begin - State := STATE_FREE; - Break; - end; - - if not ByteBool(gCollideMap[Y+s, X] and MARK_LIQUID) then - begin // Óæå íå æèäêîñòü - State := STATE_FREE; - Break; - end; - - Y := Y+s; - end; - end; - - if VelY > -4 then - VelY := VelY + AccelY; - - Time := Time + 1; - end; - end; // case - - CorrectOffsets(a); - end; + if (Time = LiveTime) then begin die(); continue; end; + if (X+1 >= w) or (Y+1 >= h) or (X <= 0) or (Y <= 0) then begin die(); end; + //if not alive then Continue; + //e_WriteLog(Format('particle #%d: %d', [State, ParticleType]), MSG_NOTIFY); + think(); + {CorrectOffsets(a);} + end; // with + end; // if + end; // for end; // Particles <> nil -{$ENDIF} if OnceAnims <> nil then begin @@ -1327,8 +1448,7 @@ begin for a := 0 to len do with Particles[a] do - if (State <> STATE_FREE) and (X >= sX) and (Y >= sY) and - (X <= sX+sWidth) and (sY <= sY+sHeight) then + if alive and (X >= sX) and (Y >= sY) and (X <= sX+sWidth) and (sY <= sY+sHeight) then begin glColor4ub(Red, Green, Blue, Alpha); glVertex2i(X + offsetX, Y + offsetY);