# HG changeset patch # User unC0Rr # Date 1692686146 -7200 # Node ID 2146cb7be36f3a783a732ebfefda2dd7252bc49d # Parent 772a43d88e6b2d147e42240f6df355e2b62cd2de# Parent 8bb07b0f50ca3d1aca09682240c2c26c44d892a5 Merge default diff -r 8bb07b0f50ca -r 2146cb7be36f .gitignore --- a/.gitignore Thu Aug 10 20:48:54 2023 -0400 +++ b/.gitignore Tue Aug 22 08:35:46 2023 +0200 @@ -32,7 +32,7 @@ misc/libphysfs/Xcode/build/ misc/libphyslayer/Xcode/build/ moc_*.cxx_parameters -relre:^release\/ +relre:^release/ *.log *.cmd *.diff diff -r 8bb07b0f50ca -r 2146cb7be36f CMakeLists.txt --- a/CMakeLists.txt Thu Aug 10 20:48:54 2023 -0400 +++ b/CMakeLists.txt Tue Aug 22 08:35:46 2023 +0200 @@ -139,10 +139,10 @@ add_flag_append(CMAKE_CXX_FLAGS_DEBUG "/Od") else() add_flag_append(CMAKE_C_FLAGS "-Wall -pipe") - add_flag_append(CMAKE_C_FLAGS_RELEASE "-O2") + add_flag_append(CMAKE_C_FLAGS_RELEASE "-O3") add_flag_append(CMAKE_C_FLAGS_DEBUG "-Wextra -O0") add_flag_append(CMAKE_CXX_FLAGS "-Wall -pipe") - add_flag_append(CMAKE_CXX_FLAGS_RELEASE "-O2") + add_flag_append(CMAKE_CXX_FLAGS_RELEASE "-O3") add_flag_append(CMAKE_CXX_FLAGS_DEBUG "-Wextra -O0") endif() diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/SDLh.pas --- a/hedgewars/SDLh.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/SDLh.pas Tue Aug 22 08:35:46 2023 +0200 @@ -931,6 +931,9 @@ TLongWordArray = array[0..16383] of LongWord; PLongWordArray = ^TLongWordArray; + TWordArray = array[0..16383] of Word; + PWordArray = ^TWordArray; + PSDL_Thread = Pointer; PSDL_mutex = Pointer; PSDL_sem = Pointer; @@ -1033,14 +1036,14 @@ {$IFDEF WINDOWS} TThreadFunction = function (p: pointer): Longword; stdcall; pfnSDL_CurrentBeginThread = function ( - _Security: pointer; + _Security: pointer; _StackSize: LongWord; _StartAddress: TThreadFunction; _ArgList: pointer; _InitFlag: Longword; _ThrdAddr: PLongword): PtrUInt; cdecl; pfnSDL_CurrentEndThread = procedure (_Retval: LongInt); cdecl; -{$ENDIF} +{$ENDIF} ///////////////////////////////////////////////////////////////// ///////////////////// FUNCTION DEFINITIONS ///////////////////// @@ -1142,7 +1145,7 @@ procedure SDL_SetEventFilter(filter: TSDL_EventFilter); cdecl; external SDLLibName; function SDL_ShowCursor(toggle: LongInt): LongInt; cdecl; external SDLLibName; -procedure SDL_WarpMouse(x, y: Word); inline; +procedure SDL_WarpMouse(x, y: Word); function SDL_GetKeyboardState(numkeys: PLongInt): PByteArray; cdecl; external SDLLibName; @@ -1297,7 +1300,7 @@ // for sdl2 we provide a SDL_WarpMouse() which calls the right SDL_WarpMouseInWindow() function // this has the advantage of reducing 'uses' and 'ifdef' statements // (SDLwindow is a private member of uStore module) -procedure SDL_WarpMouse(x, y: Word); inline; +procedure SDL_WarpMouse(x, y: Word); begin WarpMouse(x, y); end; @@ -1340,7 +1343,7 @@ function SDL_CreateThread(fn: Pointer; name: PChar; data: Pointer): PSDL_Thread; cdecl; begin SDL_CreateThread:= SDL_CreateThread(fn, name, data, nil, nil) -end; +end; {$ENDIF} end. diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/options.inc --- a/hedgewars/options.inc Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/options.inc Tue Aug 22 08:35:46 2023 +0200 @@ -65,6 +65,8 @@ {$DEFINE _S:=} {$DEFINE _P:=} +{$optimization autoInline} + //{$DEFINE TRACEAIACTIONS} //{$DEFINE COUNTTICKS} diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uAIAmmoTests.pas --- a/hedgewars/uAIAmmoTests.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uAIAmmoTests.pas Tue Aug 22 08:35:46 2023 +0200 @@ -25,7 +25,7 @@ amtest_Rare = $00000001; // check only several positions amtest_NoTarget = $00000002; // each pos, but no targetting amtest_MultipleAttacks = $00000004; // test could result in multiple attacks, set AttacksNum - amtest_NoTrackFall = $00000008; // skip fall tracing. + amtest_NoTrackFall = $00000008; // skip fall tracing. amtest_LaserSight = $00000010; // supports laser sighting amtest_NoVampiric = $00000020; // don't use vampirism with this ammo amtest_NoInvulnerable = $00000040; // don't use invulnerable with this with ammo @@ -151,9 +151,9 @@ ); implementation -uses uVariables, uUtils, uGearsHandlers; +uses uVariables, uUtils, uGearsHandlers, uLandUtils; -function Metric(x1, y1, x2, y2: LongInt): LongInt; inline; +function Metric(x1, y1, x2, y2: LongInt): LongInt; begin Metric:= abs(x1 - x2) + abs(y1 - y2) end; @@ -1081,7 +1081,7 @@ if ((ix and LAND_WIDTH_MASK) = 0) and ((iy and LAND_HEIGHT_MASK) = 0) then repeat - if Land[iy, ix] <> 0 then + if LandGet(iy, ix) <> 0 then inc(d); x:= x + vX; y:= y + vY; @@ -1137,7 +1137,7 @@ x:= x + vX; y:= y + vY; if ((trunc(x) and LAND_WIDTH_MASK) = 0)and((trunc(y) and LAND_HEIGHT_MASK) = 0) - and (Land[trunc(y), trunc(x)] <> 0) then + and (LandGet(trunc(y), trunc(x)) <> 0) then inc(d); until (Abs(Targ.Point.X - trunc(x)) + Abs(Targ.Point.Y - trunc(y)) < 4) or (x < 0) diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uAIMisc.pas --- a/hedgewars/uAIMisc.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uAIMisc.pas Tue Aug 22 08:35:46 2023 +0200 @@ -71,20 +71,20 @@ procedure freeModule; procedure FillTargets; -procedure ResetTargets; inline; -procedure AddBonus(x, y: LongInt; r: Longword; s: LongInt); inline; +procedure ResetTargets; +procedure AddBonus(x, y: LongInt; r: Longword; s: LongInt); procedure FillBonuses(isAfterAttack: boolean); -procedure AwareOfExplosion(x, y, r: LongInt); inline; +procedure AwareOfExplosion(x, y, r: LongInt); function RatePlace(Gear: PGear): LongInt; -function CheckWrap(x: real): real; inline; -function TestColl(x, y, r: LongInt): boolean; inline; -function TestCollHogsOrObjects(x, y, r: LongInt): boolean; inline; -function TestCollExcludingObjects(x, y, r: LongInt): boolean; inline; -function TestCollExcludingMe(Me: PGear; x, y, r: LongInt): boolean; inline; +function CheckWrap(x: real): real; +function TestColl(x, y, r: LongInt): boolean; +function TestCollHogsOrObjects(x, y, r: LongInt): boolean; +function TestCollExcludingObjects(x, y, r: LongInt): boolean; +function TestCollExcludingMe(Me: PGear; x, y, r: LongInt): boolean; -function RateExplosion(Me: PGear; x, y, r: LongInt): LongInt; inline; -function RateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt; inline; +function RateExplosion(Me: PGear; x, y, r: LongInt): LongInt; +function RateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt; function RealRateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt; function RateShove(Me: PGear; x, y, r, power, kick: LongInt; gdX, gdY: real; Flags: LongWord): LongInt; function RateShotgun(Me: PGear; gdX, gdY: real; x, y: LongInt): LongInt; @@ -93,8 +93,8 @@ function RateHammer(Me: PGear): LongInt; function HHGo(Gear, AltGear: PGear; var GoInfo: TGoInfo): boolean; -function AIrndSign(num: LongInt): LongInt; inline; -function AIrndOffset(targ: TTarget; Level: LongWord): LongInt; inline; +function AIrndSign(num: LongInt): LongInt; +function AIrndOffset(targ: TTarget; Level: LongWord): LongInt; var ThinkingHH: PGear; Targets: TTargets; @@ -109,14 +109,14 @@ var dmgMod: real = 1.0; implementation -uses uCollisions, uVariables, uUtils, uGearsUtils, uAIAmmoTests; +uses uCollisions, uVariables, uUtils, uGearsUtils, uAIAmmoTests, uLandUtils; var KnownExplosion: record X, Y, Radius: LongInt end = (X: 0; Y: 0; Radius: 0); -procedure ResetTargets; inline; +procedure ResetTargets; var i: LongWord; begin if Targets.reset then @@ -200,7 +200,7 @@ else friendlyfactor:= max(30, 300 - f * 80 div max(1,e)) end; -procedure AddBonus(x, y: LongInt; r: Longword; s: LongInt); inline; +procedure AddBonus(x, y: LongInt; r: Longword; s: LongInt); begin if(bonuses.Count < MAXBONUS) then begin @@ -212,7 +212,7 @@ end; end; -procedure AddWalkBonus(x, y: LongInt; r: Longword; s: LongInt); inline; +procedure AddWalkBonus(x, y: LongInt; r: Longword; s: LongInt); begin if(walkbonuses.Count < MAXBONUS div 8) then begin @@ -334,7 +334,7 @@ end; end; -procedure AwareOfExplosion(x, y, r: LongInt); inline; +procedure AwareOfExplosion(x, y, r: LongInt); begin KnownExplosion.X:= x; KnownExplosion.Y:= y; @@ -363,17 +363,17 @@ RatePlace:= rate; end; -function CheckWrap(x: real): real; inline; +function CheckWrap(x: real): real; begin if WorldEdge = weWrap then if (x < leftX) then x:= x + (rightX - leftX) - else if x > rightX then + else if x > rightX then x:= x - (rightX - leftX); CheckWrap:= x; end; -function CheckBounds(x, y, r: Longint): boolean; inline; +function CheckBounds(x, y, r: Longint): boolean; begin CheckBounds := (((x-r) and LAND_WIDTH_MASK) = 0) and (((x+r) and LAND_WIDTH_MASK) = 0) and @@ -383,60 +383,60 @@ // Check for collision with anything -function TestCollWithEverything(x, y, r: LongInt): boolean; inline; +function TestCollWithEverything(x, y, r: LongInt): boolean; begin if not CheckBounds(x, y, r) then exit(false); - if (Land[y-r, x-r] <> 0) or - (Land[y+r, x-r] <> 0) or - (Land[y-r, x+r] <> 0) or - (Land[y+r, x+r] <> 0) then + if (LandGet(y-r, x-r) <> 0) or + (LandGet(y+r, x-r) <> 0) or + (LandGet(y-r, x+r) <> 0) or + (LandGet(y+r, x+r) <> 0) then exit(true); TestCollWithEverything := false; end; // Check for collision with non-objects -function TestCollExcludingObjects(x, y, r: LongInt): boolean; inline; +function TestCollExcludingObjects(x, y, r: LongInt): boolean; begin if not CheckBounds(x, y, r) then exit(false); - if (Land[y-r, x-r] > lfAllObjMask) or - (Land[y+r, x-r] > lfAllObjMask) or - (Land[y-r, x+r] > lfAllObjMask) or - (Land[y+r, x+r] > lfAllObjMask) then + if (LandGet(y-r, x-r) > lfAllObjMask) or + (LandGet(y+r, x-r) > lfAllObjMask) or + (LandGet(y-r, x+r) > lfAllObjMask) or + (LandGet(y+r, x+r) > lfAllObjMask) then exit(true); TestCollExcludingObjects:= false; end; // Check for collision with something other than current hedgehog or crate -function TestColl(x, y, r: LongInt): boolean; inline; +function TestColl(x, y, r: LongInt): boolean; begin if not CheckBounds(x, y, r) then exit(false); - if (Land[y-r, x-r] and lfNotCurHogCrate <> 0) or - (Land[y+r, x-r] and lfNotCurHogCrate <> 0) or - (Land[y-r, x+r] and lfNotCurHogCrate <> 0) or - (Land[y+r, x+r] and lfNotCurHogCrate <> 0) then + if (LandGet(y-r, x-r) and lfNotCurHogCrate <> 0) or + (LandGet(y+r, x-r) and lfNotCurHogCrate <> 0) or + (LandGet(y-r, x+r) and lfNotCurHogCrate <> 0) or + (LandGet(y+r, x+r) and lfNotCurHogCrate <> 0) then exit(true); TestColl:= false; end; // Check for collision with hedgehog or object -function TestCollHogsOrObjects(x, y, r: LongInt): boolean; inline; +function TestCollHogsOrObjects(x, y, r: LongInt): boolean; begin if not CheckBounds(x, y, r) then exit(false); - if (Land[y-r, x-r] and lfAllObjMask <> 0) or - (Land[y+r, x-r] and lfAllObjMask <> 0) or - (Land[y-r, x+r] and lfAllObjMask <> 0) or - (Land[y+r, x+r] and lfAllObjMask <> 0) then + if (LandGet(y-r, x-r) and lfAllObjMask <> 0) or + (LandGet(y+r, x-r) and lfAllObjMask <> 0) or + (LandGet(y-r, x+r) and lfAllObjMask <> 0) or + (LandGet(y+r, x+r) and lfAllObjMask <> 0) then exit(true); TestCollHogsOrObjects:= false; @@ -445,7 +445,7 @@ // Check for collision with something other than the given "Me" gear. // Wrapper to test various approaches. If it works reasonably, will just replace. // Right now, converting to hwFloat is a tad inefficient since the x/y were hwFloat to begin with... -function TestCollExcludingMe(Me: PGear; x, y, r: LongInt): boolean; inline; +function TestCollExcludingMe(Me: PGear; x, y, r: LongInt): boolean; var MeX, MeY: LongInt; begin if ((x and LAND_WIDTH_MASK) = 0) and ((y and LAND_HEIGHT_MASK) = 0) then @@ -453,7 +453,7 @@ MeX:= hwRound(Me^.X); MeY:= hwRound(Me^.Y); // We are still inside the hog. Skip radius test - if ((sqr(x-MeX) + sqr(y-MeY)) < 256) and (Land[y, x] and lfObjMask = 0) then + if ((sqr(x-MeX) + sqr(y-MeY)) < 256) and (LandGet(y, x) and lfObjMask = 0) then exit(false); end; TestCollExcludingMe:= TestCollWithEverything(x, y, r) @@ -527,7 +527,7 @@ { if ((trunc(y) and LAND_HEIGHT_MASK) = 0) and ((trunc(x) and LAND_WIDTH_MASK) = 0) then begin - LandPixels[trunc(y), trunc(x)]:= v; + LandPixelGet(trunc(y), trunc(x)):= v; UpdateLandTexture(trunc(X), 1, trunc(Y), 1, true); end;} @@ -566,12 +566,12 @@ end; end; -function RateExplosion(Me: PGear; x, y, r: LongInt): LongInt; inline; +function RateExplosion(Me: PGear; x, y, r: LongInt): LongInt; begin RateExplosion:= RealRateExplosion(Me, x, y, r, 0); ResetTargets; end; -function RateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt; inline; +function RateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt; begin RateExplosion:= RealRateExplosion(Me, x, y, r, Flags); ResetTargets; @@ -637,7 +637,7 @@ if pY - y < 0 then dY:= -dY; if (x and LAND_WIDTH_MASK = 0) and ((y+cHHRadius+2) and LAND_HEIGHT_MASK = 0) and - (Land[y+cHHRadius+2, x] and lfIndestructible <> 0) then + (LandGet(y+cHHRadius+2, x) and lfIndestructible <> 0) then fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, 0, Targets.ar[i]) * dmgMod) else fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, erasure, Targets.ar[i]) * dmgMod) end; @@ -831,7 +831,7 @@ ((abs(dY) < 0.15) and (abs(dX) < 0.15))) then dX:= 0; if (x and LAND_WIDTH_MASK = 0) and ((y+cHHRadius+2) and LAND_HEIGHT_MASK = 0) and - (Land[y+cHHRadius+2, x] and lfIndestructible <> 0) then + (LandGet(y+cHHRadius+2, x) and lfIndestructible <> 0) then fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, 0, Targets.ar[i]) * dmgMod) else fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, erasure, Targets.ar[i]) * dmgMod) end; @@ -1083,7 +1083,7 @@ repeat {if ((hwRound(Gear^.Y) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X) and LAND_WIDTH_MASK) = 0) then begin - LandPixels[hwRound(Gear^.Y), hwRound(Gear^.X)]:= Gear^.Hedgehog^.Team^.Clan^.Color; + LandPixelGet(hwRound(Gear^.Y), hwRound(Gear^.X)):= Gear^.Hedgehog^.Team^.Clan^.Color; UpdateLandTexture(hwRound(Gear^.X), 1, hwRound(Gear^.Y), 1, true); end;} @@ -1149,7 +1149,7 @@ repeat {if ((hwRound(Gear^.Y) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X) and LAND_WIDTH_MASK) = 0) then begin - LandPixels[hwRound(Gear^.Y), hwRound(Gear^.X)]:= random($FFFFFFFF);//Gear^.Hedgehog^.Team^.Clan^.Color; + LandPixelGet(hwRound(Gear^.Y), hwRound(Gear^.X)):= random($FFFFFFFF);//Gear^.Hedgehog^.Team^.Clan^.Color; UpdateLandTexture(hwRound(Gear^.X), 1, hwRound(Gear^.Y), 1, true); end;} @@ -1206,7 +1206,7 @@ HHJump(AltGear, jmpHJump, GoInfo); end; -function AIrndSign(num: LongInt): LongInt; inline; +function AIrndSign(num: LongInt): LongInt; begin if random(2) = 0 then AIrndSign:= num @@ -1214,7 +1214,7 @@ AIrndSign:= - num end; -function AIrndOffset(targ: TTarget; Level: LongWord): LongInt; inline; +function AIrndOffset(targ: TTarget; Level: LongWord): LongInt; begin if Level <> 1 then exit(0); // at present level 2 doesn't track falls on most things diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uChat.pas --- a/hedgewars/uChat.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uChat.pas Tue Aug 22 08:35:46 2023 +0200 @@ -108,7 +108,7 @@ procedure UpdateCursorCoords(); forward; // relevant for UTF-8 handling -function IsFirstCharByte(c: char): boolean; inline; +function IsFirstCharByte(c: char): boolean; begin // based on https://en.wikipedia.org/wiki/UTF-8#Description IsFirstCharByte:= (byte(c) and $C0) <> $80; diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uCollisions.pas --- a/hedgewars/uCollisions.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uCollisions.pas Tue Aug 22 08:35:46 2023 +0200 @@ -70,11 +70,11 @@ function CheckGearsLineCollision(Gear: PGear; oX, oY, tX, tY: hwFloat): PGearArray; function CheckAllGearsLineCollision(SourceGear: PGear; oX, oY, tX, tY: hwFloat): PGearArray; -function UpdateHitOrder(Gear: PGear; Order: LongInt): boolean; inline; -function UpdateHitOrder(Gear: PGear; Order: LongInt; Global: boolean): boolean; inline; -function UpdateGlobalHitOrder(Gear: PGear; Order: LongInt): boolean; inline; -procedure ClearHitOrderLeq(MinOrder: LongInt); inline; -procedure ClearGlobalHitOrderLeq(MinOrder: LongInt); inline; +function UpdateHitOrder(Gear: PGear; Order: LongInt): boolean; +function UpdateHitOrder(Gear: PGear; Order: LongInt; Global: boolean): boolean; +function UpdateGlobalHitOrder(Gear: PGear; Order: LongInt): boolean; +procedure ClearHitOrderLeq(MinOrder: LongInt); +procedure ClearGlobalHitOrderLeq(MinOrder: LongInt); procedure ClearHitOrder(); procedure RefillProximityCache(SourceGear: PGear; radius: LongInt); @@ -84,16 +84,16 @@ function TestCollisionXImpl(centerX, centerY, radius, direction: LongInt; collisionMask: Word): Word; function TestCollisionYImpl(centerX, centerY, radius, direction: LongInt; collisionMask: Word): Word; -function TestCollisionXwithGear(Gear: PGear; Dir: LongInt): Word; inline; -function TestCollisionYwithGear(Gear: PGear; Dir: LongInt): Word; inline; +function TestCollisionXwithGear(Gear: PGear; Dir: LongInt): Word; +function TestCollisionYwithGear(Gear: PGear; Dir: LongInt): Word; -function TestCollisionX(Gear: PGear; Dir: LongInt): Word; inline; -function TestCollisionY(Gear: PGear; Dir: LongInt): Word; inline; +function TestCollisionX(Gear: PGear; Dir: LongInt): Word; +function TestCollisionY(Gear: PGear; Dir: LongInt): Word; -function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt): Word; inline; -function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word; inline; -function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt): Word; inline; -function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word; inline; +function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt): Word; +function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word; +function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt): Word; +function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word; function TestCollisionXKickImpl(centerX, centerY, radius, direction: LongInt; collisionMask, kickMask: Word): TKickTest; function TestCollisionYKickImpl(centerX, centerY, radius, direction: LongInt; collisionMask, kickMask: Word): TKickTest; @@ -103,7 +103,7 @@ function TestRectangleForObstacle(x1, y1, x2, y2: LongInt; landOnly: boolean): boolean; -function CheckCoordInWater(X, Y: LongInt): boolean; inline; +function CheckCoordInWater(X, Y: LongInt): boolean; // returns: negative sign if going downhill to left, value is steepness (noslope/error = _0, 45 = _0_5) function CalcSlopeBelowGear(Gear: PGear): hwFloat; @@ -113,7 +113,7 @@ function CheckGearsUnderSprite(Sprite: TSprite; sprX, sprY, Frame: LongInt): boolean; implementation -uses uConsts, uLandGraphics, uVariables, SDLh, uLandTexture, uDebug; +uses uConsts, uLandGraphics, uVariables, SDLh, uLandTexture, uDebug, uLandUtils; type TCollisionEntry = record X, Y, Radius: LongInt; @@ -159,7 +159,7 @@ end; end; -function CheckCoordInWater(X, Y: LongInt): boolean; inline; +function CheckCoordInWater(X, Y: LongInt): boolean; begin CheckCoordInWater:= (Y > cWaterLine) or ((WorldEdge = weSea) and ((X < leftX) or (X > rightX))); @@ -221,7 +221,7 @@ function LineCollisionTest(oX, oY, dirX, dirY, dirNormSqr, dirNormBound: hwFloat; width: LongInt; Gear: PGear): - TLineCollision; inline; + TLineCollision; var toCenterX, toCenterY, r, b, bSqr, c, desc, t: hwFloat; realT: extended; @@ -367,12 +367,12 @@ end end; -function UpdateHitOrder(Gear: PGear; Order: LongInt): boolean; inline; +function UpdateHitOrder(Gear: PGear; Order: LongInt): boolean; begin UpdateHitOrder := UpdateHitOrderImpl(@ordera, Gear, Order); end; -function UpdateHitOrder(Gear: PGear; Order: LongInt; Global: boolean): boolean; inline; +function UpdateHitOrder(Gear: PGear; Order: LongInt; Global: boolean): boolean; begin if Global then UpdateHitOrder := UpdateHitOrderImpl(@globalordera, Gear, Order) @@ -380,7 +380,7 @@ UpdateHitOrder := UpdateHitOrderImpl(@ordera, Gear, Order) end; -function UpdateGlobalHitOrder(Gear: PGear; Order: LongInt): boolean; inline; +function UpdateGlobalHitOrder(Gear: PGear; Order: LongInt): boolean; begin UpdateGlobalHitOrder := UpdateHitOrderImpl(@globalordera, Gear, Order); end; @@ -408,12 +408,12 @@ end end; -procedure ClearHitOrderLeq(MinOrder: LongInt); inline; +procedure ClearHitOrderLeq(MinOrder: LongInt); begin ClearHitOrderLeqImpl(@ordera, MinOrder); end; -procedure ClearGlobalHitOrderLeq(MinOrder: LongInt); inline; +procedure ClearGlobalHitOrderLeq(MinOrder: LongInt); begin ClearHitOrderLeqImpl(@globalordera, MinOrder); end; @@ -480,8 +480,8 @@ minY := max(centerY - radius + 1, 0); maxY := min(centerY + radius - 1, LAND_HEIGHT - 1); for y := minY to maxY do - if Land[y, x] and collisionMask <> 0 then - exit(Land[y, x] and collisionMask); + if LandGet(y, x) and collisionMask <> 0 then + exit(LandGet(y, x) and collisionMask); end; TestCollisionXImpl := 0; end; @@ -499,18 +499,18 @@ minX := max(centerX - radius + 1, 0); maxX := min(centerX + radius - 1, LAND_WIDTH - 1); for x := minX to maxX do - if Land[y, x] and collisionMask <> 0 then - exit(Land[y, x] and collisionMask); + if LandGet(y, x) and collisionMask <> 0 then + exit(LandGet(y, x) and collisionMask); end; TestCollisionYImpl := 0; end; -function TestCollisionX(Gear: PGear; Dir: LongInt): Word; inline; +function TestCollisionX(Gear: PGear; Dir: LongInt): Word; begin TestCollisionX := TestCollisionXImpl(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Radius, Dir, Gear^.CollisionMask and lfLandMask); end; -function TestCollisionY(Gear: PGear; Dir: LongInt): Word; inline; +function TestCollisionY(Gear: PGear; Dir: LongInt): Word; begin TestCollisionY := TestCollisionYImpl(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Radius, Dir, Gear^.CollisionMask and lfLandMask); end; @@ -533,19 +533,19 @@ Gear^.CollisionMask:= lfAll; end; -function TestCollisionXwithGear(Gear: PGear; Dir: LongInt): Word; inline; +function TestCollisionXwithGear(Gear: PGear; Dir: LongInt): Word; begin LegacyFixupX(Gear); TestCollisionXwithGear:= TestCollisionXImpl(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Radius, Dir, Gear^.CollisionMask); end; -function TestCollisionYwithGear(Gear: PGear; Dir: LongInt): Word; inline; +function TestCollisionYwithGear(Gear: PGear; Dir: LongInt): Word; begin LegacyFixupY(Gear); TestCollisionYwithGear:= TestCollisionYImpl(hwRound(Gear^.X), hwRound(Gear^.Y), Gear^.Radius, Dir, Gear^.CollisionMask); end; -function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word; inline; +function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word; var collisionMask: Word; begin if withGear then @@ -559,7 +559,7 @@ TestCollisionXwithXYShift := TestCollisionXImpl(hwRound(Gear^.X + ShiftX), hwRound(Gear^.Y) + ShiftY, Gear^.Radius, Dir, collisionMask) end; -function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word; inline; +function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt; withGear: boolean): Word; var collisionMask: Word; begin if withGear then @@ -573,12 +573,12 @@ TestCollisionYwithXYShift := TestCollisionYImpl(hwRound(Gear^.X) + ShiftX, hwRound(Gear^.Y) + ShiftY, Gear^.Radius, Dir, collisionMask) end; -function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt): Word; inline; +function TestCollisionXwithXYShift(Gear: PGear; ShiftX: hwFloat; ShiftY: LongInt; Dir: LongInt): Word; begin TestCollisionXwithXYShift:= TestCollisionXwithXYShift(Gear, ShiftX, ShiftY, Dir, true); end; -function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt): Word; inline; +function TestCollisionYwithXYShift(Gear: PGear; ShiftX, ShiftY: LongInt; Dir: LongInt): Word; begin TestCollisionYwithXYShift:= TestCollisionYwithXYShift(Gear, ShiftX, ShiftY, Dir, true); end; @@ -599,16 +599,16 @@ minY := max(centerY - radius + 1, 0); maxY := min(centerY + radius - 1, LAND_HEIGHT - 1); for y := minY to maxY do - if Land[y, x] and collisionMask <> 0 then + if LandGet(y, x) and collisionMask <> 0 then begin TestCollisionXKickImpl.kick := false; - TestCollisionXKickImpl.collisionMask := Land[y, x] and collisionMask; + TestCollisionXKickImpl.collisionMask := LandGet(y, x) and collisionMask; exit end - else if Land[y, x] and kickMask <> 0 then + else if LandGet(y, x) and kickMask <> 0 then begin TestCollisionXKickImpl.kick := true; - TestCollisionXKickImpl.collisionMask := Land[y, x] and kickMask; + TestCollisionXKickImpl.collisionMask := LandGet(y, x) and kickMask; end; end; end; @@ -629,16 +629,16 @@ minX := max(centerX - radius + 1, 0); maxX := min(centerX + radius - 1, LAND_WIDTH - 1); for x := minX to maxX do - if Land[y, x] and collisionMask <> 0 then + if LandGet(y, x) and collisionMask <> 0 then begin TestCollisionYKickImpl.kick := false; - TestCollisionYKickImpl.collisionMask := Land[y, x] and collisionMask; + TestCollisionYKickImpl.collisionMask := LandGet(y, x) and collisionMask; exit end - else if Land[y, x] and kickMask <> 0 then + else if LandGet(y, x) and kickMask <> 0 then begin TestCollisionYKickImpl.kick := true; - TestCollisionYKickImpl.collisionMask := Land[y, x] and kickMask; + TestCollisionYKickImpl.collisionMask := LandGet(y, x) and kickMask; end; end; end; @@ -767,7 +767,7 @@ for y := y1 to y2 do for x := x1 to x2 do - if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] > TestWord) then + if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (LandGet(y, x) > TestWord) then exit; TestRectangleForObstacle:= false @@ -816,7 +816,7 @@ tmpy:= collisionY + k * my; if (((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK) = 0) then - if (Land[tmpy,tmpx] > TestWord) then + if (LandGet(tmpy,tmpx) > TestWord) then begin // remember the index belonging to the first and last collision (if in 1st half) if (i <> 0) then @@ -867,7 +867,7 @@ tmpx:= ldx + k * offset[tmpo,0]; tmpy:= ldy + k * offset[tmpo,1]; if (((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK) = 0) - and (Land[tmpy,tmpx] > TestWord) then + and (LandGet(tmpy,tmpx) > TestWord) then begin ldx:= tmpx; ldy:= tmpy; @@ -891,7 +891,7 @@ tmpx:= rdx + k * offset[tmpo,0]; tmpy:= rdy + k * offset[tmpo,1]; if (((tmpy) and LAND_HEIGHT_MASK) = 0) and (((tmpx) and LAND_WIDTH_MASK) = 0) - and (Land[tmpy,tmpx] > TestWord) then + and (LandGet(tmpy,tmpx) > TestWord) then begin rdx:= tmpx; rdy:= tmpy; @@ -934,7 +934,7 @@ i:= x + Gear^.Radius * 2 - 2; repeat if (x and LAND_WIDTH_MASK) = 0 then - if Land[y, x] <> 0 then + if LandGet(y, x) <> 0 then if (not isColl) or (abs(x-gx) < abs(collX-gx)) then begin isColl:= true; @@ -957,7 +957,7 @@ i:= y + Gear^.Radius * 2 - 2; repeat if (y and LAND_HEIGHT_MASK) = 0 then - if Land[y, x] <> 0 then + if LandGet(y, x) <> 0 then if (not isColl) or (abs(y-gy) < abs(collY-gy)) then begin isColl:= true; @@ -1026,7 +1026,7 @@ i:= x + Gear^.Radius * 2 - 2; repeat if (x and LAND_WIDTH_MASK) = 0 then - if (Land[y, x] and lfLandMask) <> 0 then + if (LandGet(y, x) and lfLandMask) <> 0 then if (not isColl) or (abs(x-gx) < abs(collX-gx)) then begin isColl:= true; diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uCommandHandlers.pas --- a/hedgewars/uCommandHandlers.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uCommandHandlers.pas Tue Aug 22 08:35:46 2023 +0200 @@ -587,7 +587,7 @@ if bShowAmmoMenu then bShowAmmoMenu:= false - else if not(CurrentTeam^.Extdriven) and ((Gear = nil) or ((Gear^.State and (gstAttacking or gstAttacked)) <> 0) + else if ((Gear = nil) or ((Gear^.State and (gstAttacking or gstAttacked)) <> 0) or ((Gear^.State and gstHHDriven) = 0)) then begin end diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uCommands.pas --- a/hedgewars/uCommands.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uCommands.pas Tue Aug 22 08:35:46 2023 +0200 @@ -30,7 +30,7 @@ procedure freeModule; procedure RegisterVariable(Name: shortstring; p: TCommandHandler; Trusted: boolean; Rand: boolean); procedure RegisterVariable(Name: shortstring; p: TCommandHandler; Trusted: boolean); -procedure ParseCommand(CmdStr: shortstring; TrustedSource: boolean); inline; +procedure ParseCommand(CmdStr: shortstring; TrustedSource: boolean); procedure ParseCommand(CmdStr: shortstring; TrustedSource, ExternalSource: boolean); procedure ParseTeamCommand(s: shortstring); procedure StopMessages(Message: Longword); @@ -76,7 +76,7 @@ end; -procedure ParseCommand(CmdStr: shortstring; TrustedSource: boolean); inline; +procedure ParseCommand(CmdStr: shortstring; TrustedSource: boolean); begin ParseCommand(CmdStr, TrustedSource, false) end; diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uDebug.pas --- a/hedgewars/uDebug.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uDebug.pas Tue Aug 22 08:35:46 2023 +0200 @@ -23,7 +23,7 @@ interface procedure OutError(Msg: shortstring; isFatalError: boolean); -//procedure TryDo(Assert: boolean; Msg: shortstring; isFatal: boolean); inline; +//procedure TryDo(Assert: boolean; Msg: shortstring; isFatal: boolean); function checkFails(Assert: boolean; Msg: shortstring; isFatal: boolean): boolean; function SDLCheck(Assert: boolean; Msg: shortstring; isFatal: boolean): boolean; diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uFloat.pas --- a/hedgewars/uFloat.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uFloat.pas Tue Aug 22 08:35:46 2023 +0200 @@ -56,45 +56,45 @@ {$ENDIF} // Returns an hwFloat that represents the value of integer parameter i -function int2hwFloat (const i: LongInt) : hwFloat; inline; -function hwFloat2Float (const i: hwFloat) : extended; inline; +function int2hwFloat (const i: LongInt) : hwFloat; +function hwFloat2Float (const i: hwFloat) : extended; // The implemented operators -operator = (const z1, z2: hwFloat) z : boolean; inline; +operator = (const z1, z2: hwFloat) z : boolean; {$IFDEF PAS2C} -operator <> (const z1, z2: hwFloat) z : boolean; inline; +operator <> (const z1, z2: hwFloat) z : boolean; {$ENDIF} -operator + (const z1, z2: hwFloat) z : hwFloat; inline; -operator - (const z1, z2: hwFloat) z : hwFloat; inline; -operator - (const z1: hwFloat) z : hwFloat; inline; +operator + (const z1, z2: hwFloat) z : hwFloat; +operator - (const z1, z2: hwFloat) z : hwFloat; +operator - (const z1: hwFloat) z : hwFloat; -operator * (const z1, z2: hwFloat) z : hwFloat; inline; -operator * (const z1: hwFloat; const z2: LongInt) z : hwFloat; inline; -operator / (const z1: hwFloat; z2: hwFloat) z : hwFloat; inline; -operator / (const z1: hwFloat; const z2: LongInt) z : hwFloat; inline; +operator * (const z1, z2: hwFloat) z : hwFloat; +operator * (const z1: hwFloat; const z2: LongInt) z : hwFloat; +operator / (const z1: hwFloat; z2: hwFloat) z : hwFloat; +operator / (const z1: hwFloat; const z2: LongInt) z : hwFloat; -operator < (const z1, z2: hwFloat) b : boolean; inline; -operator > (const z1, z2: hwFloat) b : boolean; inline; +operator < (const z1, z2: hwFloat) b : boolean; +operator > (const z1, z2: hwFloat) b : boolean; // Various functions for hwFloat (some are inlined in the resulting code for better performance) function cstr(const z: hwFloat): shortstring; // Returns a shortstring representations of the hwFloat. -function hwRound(const t: hwFloat): LongInt; inline; // Does NOT really round but returns the integer representation of the hwFloat without fractional digits. (-_0_9 -> -0, _1_5 -> _1) -function hwAbs(const t: hwFloat): hwFloat; inline; // Returns the value of t with positive sign. -function hwSqr(const t: hwFloat): hwFloat; inline; // Returns the square value of parameter t. -function hwSqrt1(const t: hwFloat): hwFloat; inline; // Returns the the positive square root of parameter t. -function hwSqrt(const x: hwFloat): hwFloat; inline; // Returns the the positive square root of parameter t. +function hwRound(const t: hwFloat): LongInt; // Does NOT really round but returns the integer representation of the hwFloat without fractional digits. (-_0_9 -> -0, _1_5 -> _1) +function hwAbs(const t: hwFloat): hwFloat; // Returns the value of t with positive sign. +function hwSqr(const t: hwFloat): hwFloat; // Returns the square value of parameter t. +function hwSqrt1(const t: hwFloat): hwFloat; // Returns the the positive square root of parameter t. +function hwSqrt(const x: hwFloat): hwFloat; // Returns the the positive square root of parameter t. function Distance(const dx, dy: hwFloat): hwFloat; // Returns the distance between two points in 2-dimensional space, of which the parameters are the horizontal and vertical distance. function DistanceI(const dx, dy: LongInt): hwFloat; // Same as above for integer parameters. function AngleSin(const Angle: Longword): hwFloat; function AngleCos(const Angle: Longword): hwFloat; function vector2Angle(const x, y: hwFloat): LongInt; -function SignAs(const num, signum: hwFloat): hwFloat; inline; // Returns an hwFloat with the value of parameter num and the sign of signum. -function hwSign(r: hwFloat): LongInt; inline; // Returns an integer with value 1 and sign of parameter r. -function hwSignf(r: real): LongInt; inline; // Returns an integer with value 1 and sign of parameter r. -function isZero(const z: hwFloat): boolean; inline; +function SignAs(const num, signum: hwFloat): hwFloat; // Returns an hwFloat with the value of parameter num and the sign of signum. +function hwSign(r: hwFloat): LongInt; // Returns an integer with value 1 and sign of parameter r. +function hwSignf(r: real): LongInt; // Returns an integer with value 1 and sign of parameter r. +function isZero(const z: hwFloat): boolean; {$WARNINGS OFF} // some hwFloat constants @@ -195,33 +195,33 @@ uses uSinTable; -function int2hwFloat (const i: LongInt) : hwFloat; inline; +function int2hwFloat (const i: LongInt) : hwFloat; begin int2hwFloat.isNegative:= i < 0; int2hwFloat.Round:= abs(i); int2hwFloat.Frac:= 0 end; -function hwFloat2Float (const i: hwFloat) : extended; inline; +function hwFloat2Float (const i: hwFloat) : extended; begin hwFloat2Float:= i.Frac / $100000000 + i.Round; if i.isNegative then hwFloat2Float:= -hwFloat2Float; end; -operator = (const z1, z2: hwFloat) z : boolean; inline; +operator = (const z1, z2: hwFloat) z : boolean; begin z:= (z1.isNegative = z2.isNegative) and (z1.QWordValue = z2.QWordValue); end; {$IFDEF PAS2C} -operator <> (const z1, z2: hwFloat) z : boolean; inline; +operator <> (const z1, z2: hwFloat) z : boolean; begin z:= (z1.isNegative <> z2.isNegative) or (z1.QWordValue <> z2.QWordValue); end; {$ENDIF} -operator + (const z1, z2: hwFloat) z : hwFloat; inline; +operator + (const z1, z2: hwFloat) z : hwFloat; begin if z1.isNegative = z2.isNegative then begin @@ -241,7 +241,7 @@ end end; -operator - (const z1, z2: hwFloat) z : hwFloat; inline; +operator - (const z1, z2: hwFloat) z : hwFloat; begin if z1.isNegative = z2.isNegative then if z1.QWordValue > z2.QWordValue then @@ -261,12 +261,12 @@ end end; -function isZero(const z: hwFloat): boolean; inline; +function isZero(const z: hwFloat): boolean; begin isZero := z.QWordValue = 0; end; -operator < (const z1, z2: hwFloat) b : boolean; inline; +operator < (const z1, z2: hwFloat) b : boolean; begin if z1.isNegative xor z2.isNegative then b:= z1.isNegative @@ -277,7 +277,7 @@ b:= (z2.QWordValue < z1.QWordValue) = z1.isNegative end; -operator > (const z1, z2: hwFloat) b : boolean; inline; +operator > (const z1, z2: hwFloat) b : boolean; begin if z1.isNegative xor z2.isNegative then b:= z2.isNegative @@ -288,14 +288,14 @@ b:= (z1.QWordValue > z2.QWordValue) <> z2.isNegative end; -operator - (const z1: hwFloat) z : hwFloat; inline; +operator - (const z1: hwFloat) z : hwFloat; begin z:= z1; z.isNegative:= not z.isNegative end; -operator * (const z1, z2: hwFloat) z : hwFloat; inline; +operator * (const z1, z2: hwFloat) z : hwFloat; begin z.isNegative:= z1.isNegative xor z2.isNegative; @@ -310,13 +310,13 @@ end end; -operator * (const z1: hwFloat; const z2: LongInt) z : hwFloat; inline; +operator * (const z1: hwFloat; const z2: LongInt) z : hwFloat; begin z.isNegative:= z1.isNegative xor (z2 < 0); z.QWordValue:= z1.QWordValue * abs(z2) end; -operator / (const z1: hwFloat; z2: hwFloat) z : hwFloat; inline; +operator / (const z1: hwFloat; z2: hwFloat) z : hwFloat; var t: QWord; begin z.isNegative:= z1.isNegative xor z2.isNegative; @@ -337,7 +337,7 @@ end end; -operator / (const z1: hwFloat; const z2: LongInt) z : hwFloat; inline; +operator / (const z1: hwFloat; const z2: LongInt) z : hwFloat; begin z.isNegative:= z1.isNegative xor (z2 < 0); z.QWordValue:= z1.QWordValue div abs(z2) @@ -371,7 +371,7 @@ hwAbs.isNegative:= false end; -function hwSqr(const t: hwFloat): hwFloat; inline; +function hwSqr(const t: hwFloat): hwFloat; begin hwSqr.isNegative:= false; hwSqr.QWordValue:= ((QWord(t.Round) * t.Round) shl 32) + QWord(t.Round) * t.Frac * 2 + ((QWord(t.Frac) * t.Frac) shr 32); diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uGearsHandlers.pas --- a/hedgewars/uGearsHandlers.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uGearsHandlers.pas Tue Aug 22 08:35:46 2023 +0200 @@ -36,13 +36,13 @@ (x: 0; y: 1), (x: -1; y: 0)); -procedure PrevAngle(Gear: PGear; dA: LongInt); inline; +procedure PrevAngle(Gear: PGear; dA: LongInt); begin inc(Gear^.WDTimer); Gear^.Angle := (LongInt(Gear^.Angle) - dA) and 3 end; -procedure NextAngle(Gear: PGear; dA: LongInt); inline; +procedure NextAngle(Gear: PGear; dA: LongInt); begin inc(Gear^.WDTimer); Gear^.Angle := (LongInt(Gear^.Angle) + dA) and 3 diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uGearsHandlersMess.pas --- a/hedgewars/uGearsHandlersMess.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uGearsHandlersMess.pas Tue Aug 22 08:35:46 2023 +0200 @@ -152,7 +152,7 @@ uses uConsts, uVariables, uVisualGearsList, uRandom, uCollisions, uGearsList, uUtils, uSound , SDLh, uScript, uGearsHedgehog, uGearsUtils, uIO, uCaptions, uLandGraphics , uGearsHandlers, uTextures, uRenderUtils, uAmmos, uTeams, uLandTexture - , uStore, uAI, uStats, uLocale; + , uStore, uAI, uStats, uLocale, uLandUtils; procedure doStepPerPixel(Gear: PGear; step: TGearStepProcedure; onlyCheckIfChanged: boolean); var @@ -528,7 +528,7 @@ end else if (collV < 0) and (collH < 0) and tdX.isNegative and tdY.isNegative then Gear^.dX.isNegative := false; - + isFalling := false; Gear^.AdvBounce := 10; end; @@ -884,45 +884,45 @@ else if (cGravity.isNegative) and (yy < LAND_HEIGHT-1200) then move:=true // Solid pixel encountered - else if ((yy and LAND_HEIGHT_MASK) = 0) and ((xx and LAND_WIDTH_MASK) = 0) and (Land[yy, xx] <> 0) then - begin - lf:= Land[yy, xx] and (lfObject or lfBasic or lfIndestructible); + else if ((yy and LAND_HEIGHT_MASK) = 0) and ((xx and LAND_WIDTH_MASK) = 0) and (LandGet(yy, xx) <> 0) then + begin + lf:= LandGet(yy, xx) and (lfObject or lfBasic or lfIndestructible); if lf = 0 then lf:= lfObject; // If there's room below keep falling - if (((yy-1) and LAND_HEIGHT_MASK) = 0) and (Land[yy-1, xx] = 0) then + if (((yy-1) and LAND_HEIGHT_MASK) = 0) and (LandGet(yy-1, xx) = 0) then begin X:= X - cWindSpeed * 1600 - dX; end // If there's room below, on the sides, fill the gaps - else if (((yy-1) and LAND_HEIGHT_MASK) = 0) then + else if (((yy-1) and LAND_HEIGHT_MASK) = 0) then begin - if (((xx - 1) and LAND_WIDTH_MASK) = 0) and (Land[yy - 1, (xx - 1)] = 0) then + if (((xx - 1) and LAND_WIDTH_MASK) = 0) and (LandGet(yy - 1, (xx - 1)) = 0) then begin X:= X - _0_8; Y:= oldY; end - else if (((xx - 2) and LAND_WIDTH_MASK) = 0) and (Land[yy - 1, (xx - 2)] = 0) then + else if (((xx - 2) and LAND_WIDTH_MASK) = 0) and (LandGet(yy - 1, (xx - 2)) = 0) then begin X:= X - _1_6; Y:= oldY; end - else if (((xx + 1) and LAND_WIDTH_MASK) = 0) and (Land[yy - 1, (xx + 1)] = 0) then + else if (((xx + 1) and LAND_WIDTH_MASK) = 0) and (LandGet(yy - 1, (xx + 1)) = 0) then begin X:= X + _0_8; Y:= oldY; end - else if (((xx + 2) and LAND_WIDTH_MASK) = 0) and (Land[yy - 1, (xx + 2)] = 0) then + else if (((xx + 2) and LAND_WIDTH_MASK) = 0) and (LandGet(yy - 1, (xx + 2)) = 0) then begin X:= X + _1_6; Y:= oldY; end else - if ((((yy+1) and LAND_HEIGHT_MASK) = 0) and ((Land[yy + 1, xx] and $FF) <> 0)) then - move:=true - else + if ((((yy+1) and LAND_HEIGHT_MASK) = 0) and ((LandGet(yy + 1, xx) and $FF) <> 0)) then + move:=true + else draw:= true end // if there's an hog/object below do nothing - else if ((((yy+1) and LAND_HEIGHT_MASK) = 0) and ((Land[yy+1, xx] and $FF) <> 0)) + else if ((((yy+1) and LAND_HEIGHT_MASK) = 0) and ((LandGet(yy+1, xx) and $FF) <> 0)) then move:=true else draw:= true end @@ -949,7 +949,7 @@ for px:= 0 to Pred(s^.w) do begin lx:=xx + px; ly:=yy + py; - if (ly and LAND_HEIGHT_MASK = 0) and (lx and LAND_WIDTH_MASK = 0) and (Land[ly, lx] and $FF = 0) then + if (ly and LAND_HEIGHT_MASK = 0) and (lx and LAND_WIDTH_MASK = 0) and (LandGet(ly, lx) and $FF = 0) then begin rx:= lx; ry:= ly; @@ -957,21 +957,21 @@ begin rx:= rx div 2;ry:= ry div 2; end; - if Land[yy + py, xx + px] <= lfAllObjMask then + if LandGet(yy + py, xx + px) <= lfAllObjMask then if gun then begin LandDirty[yy div 32, xx div 32]:= 1; - if LandPixels[ry, rx] = 0 then - Land[ly, lx]:= lfDamaged or lfObject - else Land[ly, lx]:= lfDamaged or lfBasic + if LandPixelGet(ry, rx) = 0 then + LandSet(ly, lx, lfDamaged or lfObject) + else LandSet(ly, lx, lfDamaged or lfBasic) end - else Land[ly, lx]:= lf; + else LandSet(ly, lx, lf); if gun then - LandPixels[ry, rx]:= (Gear^.Tint shr 24 shl RShift) or - (Gear^.Tint shr 16 and $FF shl GShift) or - (Gear^.Tint shr 8 and $FF shl BShift) or - (p^[px] and AMask) - else LandPixels[ry, rx]:= addBgColor(LandPixels[ry, rx], p^[px]); + LandPixelSet(ry, rx, (Gear^.Tint shr 24 shl RShift) or + (Gear^.Tint shr 16 and $FF shl GShift) or + (Gear^.Tint shr 8 and $FF shl BShift) or + (p^[px] and AMask)) + else LandPixelSet(ry, rx, addBgColor(LandPixelGet(ry, rx), p^[px])); end else allpx:= false end; @@ -1520,7 +1520,7 @@ if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) then begin - LandFlags:= Land[y, x]; + LandFlags:= LandGet(y, x); if LandFlags <> 0 then inc(Gear^.Damage); isDigging:= (LandFlags and lfLandMask) <> 0; end; @@ -1762,7 +1762,7 @@ if (Gear^.Timer mod 47) = 0 then begin // ok. this was an attempt to turn off dust if not actually drilling land. I have no idea why it isn't working as expected - if (( (y + 12) and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y + 12, x] > 255) then + if (( (y + 12) and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (LandGet(y + 12, x) > 255) then for i:= 0 to 1 do AddVisualGear(x - 5 + Random(10), y + 12, vgtDust); @@ -2194,7 +2194,7 @@ // If in ready timer, or after turn, or in first 5 seconds of turn (really a window due to extra time utility) // or hunting is disabled due to seek radius of 0 then we aren't hunting - if (ReadyTimeLeft > 0) or (TurnTimeLeft = 0) or + if (ReadyTimeLeft > 0) or (TurnTimeLeft = 0) or ((TurnTimeLeft < cHedgehogTurnTime) and (cHedgehogTurnTime-TurnTimeLeft < 5000)) or (Gear^.Angle = 0) then gear^.State:= gear^.State and (not gstChooseTarget) @@ -3452,7 +3452,7 @@ begin DeleteGear(Gear); exit - end; + end; valid:= false; @@ -4246,8 +4246,8 @@ dec(playWidth, 2); for i:= 0 to LAND_HEIGHT - 1 do begin - Land[i, leftX] := 0; - Land[i, rightX] := 0; + LandSet(i, leftX, 0); + LandSet(i, rightX, 0); end; end; @@ -4255,7 +4255,7 @@ begin dec(cWaterLine); for i:= 0 to LAND_WIDTH - 1 do - Land[cWaterLine, i] := 0; + LandSet(cWaterLine, i, 0); SetAllToActive end; @@ -5039,8 +5039,8 @@ doPortalColorSwitch(); // destroy portal if ground it was attached too is gone - if (Land[hwRound(Gear^.Y), hwRound(Gear^.X)] <= lfAllObjMask) - or (Land[hwRound(Gear^.Y), hwRound(Gear^.X)] and lfBouncy <> 0) + if (LandGet(hwRound(Gear^.Y), hwRound(Gear^.X)) <= lfAllObjMask) + or (LandGet(hwRound(Gear^.Y), hwRound(Gear^.X)) and lfBouncy <> 0) or (Gear^.Timer < 1) or (Gear^.Hedgehog^.Team <> CurrentHedgehog^.Team) or CheckCoordInWater(hwRound(Gear^.X), hwRound(Gear^.Y)) then @@ -5407,12 +5407,12 @@ ty := 0; // avoid compiler hints - if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (Land[y, x] > 255) then + if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) and (LandGet(y, x) > 255) then begin Gear^.State := Gear^.State or gstCollision; Gear^.State := Gear^.State and (not gstMoving); - if (Land[y, x] and lfBouncy <> 0) + if (LandGet(y, x) and lfBouncy <> 0) or (not CalcSlopeTangent(Gear, x, y, tx, ty, 255)) or (DistanceI(tx,ty) < _12) then // reject shots at too irregular terrain begin @@ -5773,9 +5773,9 @@ if (not CheckCoordInWater(rX, rY)) or (not CheckCoordInWater(x, y)) then begin if ((y and LAND_HEIGHT_MASK) = 0) and ((x and LAND_WIDTH_MASK) = 0) - and (Land[y, x] <> 0) then + and (LandGet(y, x) <> 0) then begin - if ((GameFlags and gfSolidLand) <> 0) and (Land[y, x] > 255) then + if ((GameFlags and gfSolidLand) <> 0) and (LandGet(y, x) > 255) then Gear^.Damage := initHealth else if justCollided then begin @@ -6683,7 +6683,7 @@ ndY:= -AngleCos(HHGear^.Angle) * _4; if (ndX <> dX) or (ndY <> dY) or (Gear^.Message and (gmUp or gmDown) <> 0) or (((Target.X <> NoPointX) and (Target.X and LAND_WIDTH_MASK = 0) and - (Target.Y and LAND_HEIGHT_MASK = 0) and ((Land[Target.Y, Target.X] = 0)) and + (Target.Y and LAND_HEIGHT_MASK = 0) and ((LandGet(Target.Y, Target.X) = 0)) and (not CheckCoordInWater(Target.X, Target.Y))) and (CheckGearNear(gtAirMine, int2hwFloat(Target.X),int2hwFloat(Target.Y), Gear^.Radius*3, Gear^.Radius*3) = nil) and (not ((WorldEdge = weBounce) and ((Target.X > rightX) or (Target.X < leftX))))) then begin @@ -6717,7 +6717,7 @@ else if CheckCoordInWater(Target.X, Target.Y) or ((Target.X and LAND_WIDTH_MASK = 0) and (Target.Y and LAND_HEIGHT_MASK = 0) and - (Land[Target.Y, Target.X] = lfIce) and + (LandGet(Target.Y, Target.X) = lfIce) and ((Target.Y+iceHeight+5 > cWaterLine) or ((WorldEdge = weSea) and ((Target.X+iceHeight+5 > rightX) or @@ -6799,13 +6799,13 @@ begin iter^.Damage:= 0; iter^.State:= iter^.State or gstFrozen; - if (hwRound(iter^.X) < RightX-16) and (hwRound(iter^.X) > LeftX+16) and + if (hwRound(iter^.X) < RightX-16) and (hwRound(iter^.X) > LeftX+16) and (hwRound(iter^.Y) > topY+16) and (hwRound(iter^.Y) < LAND_HEIGHT-16) then begin AddCI(iter); iter^.X:= int2hwFloat(min(RightX-16,max(hwRound(iter^.X), LeftX+16))); iter^.Y:= int2hwFloat(min(LAND_HEIGHT-16,max(hwRound(iter^.Y),TopY+16))); - ForcePlaceOnLand(hwRound(iter^.X)-16, hwRound(iter^.Y)-16, sprFrozenAirMine, 0, lfIce, $FFFFFFFF, false, false, false); + ForcePlaceOnLand(hwRound(iter^.X)-16, hwRound(iter^.Y)-16, sprFrozenAirMine, 0, lfIce, $FFFFFFFF, false, false, false); iter^.State:= iter^.State or gstInvisible end else @@ -6865,7 +6865,7 @@ end else if (t > 400) and (CheckCoordInWater(gX, gY) or (((gX and LAND_WIDTH_MASK = 0) and (gY and LAND_HEIGHT_MASK = 0)) - and (Land[gY, gX] <> 0))) then + and (LandGet(gY, gX) <> 0))) then begin Target.X:= gX; Target.Y:= gY; @@ -6888,7 +6888,7 @@ Target.Y:= gY; X:= HHGear^.X; Y:= HHGear^.Y - end + end end; end end; @@ -6996,7 +6996,7 @@ tX:=Gear^.X-targ^.X; tY:=Gear^.Y-targ^.Y; // allow escaping - should maybe flag this too - if (GameTicks > Gear^.FlightTime+10000) or + if (GameTicks > Gear^.FlightTime+10000) or ((tX.Round+tY.Round > Gear^.Angle*6) and (hwRound(hwSqr(tX) + hwSqr(tY)) > sqr(Gear^.Angle*6))) then targ:= nil @@ -7005,7 +7005,7 @@ // If in ready timer, or after turn, or in first 5 seconds of turn (really a window due to extra time utility) // or mine is inactive due to lack of gsttmpflag or hunting is disabled due to seek radius of 0 // then we aren't hunting - if (ReadyTimeLeft > 0) or (TurnTimeLeft = 0) or + if (ReadyTimeLeft > 0) or (TurnTimeLeft = 0) or ((TurnTimeLeft < cHedgehogTurnTime) and (cHedgehogTurnTime-TurnTimeLeft < 5000)) or (Gear^.State and gsttmpFlag = 0) or (Gear^.Angle = 0) then @@ -7269,7 +7269,7 @@ MakeSentryStep := true end end; - + function MakeSentryJump(Sentry: PGear; maxXStep, maxYStep: LongInt): Boolean; var x, y, offsetX, offsetY, direction: LongInt; jumpTime: hwFloat; @@ -7322,7 +7322,7 @@ for i := 0 to count - 1 do begin - if (Land[hwRound(fromY), hwRound(fromX)] and mask) <> 0 then + if (LandGet(hwRound(fromY), hwRound(fromX)) and mask) <> 0 then Inc(TraceAttackPath); fromX := fromX + distX; fromY := fromY + distY; diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uGearsHandlersRope.pas --- a/hedgewars/uGearsHandlersRope.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uGearsHandlersRope.pas Tue Aug 22 08:35:46 2023 +0200 @@ -26,7 +26,7 @@ implementation uses uConsts, uFloat, uCollisions, uVariables, uGearsList, uSound, uGearsUtils, - uAmmos, uDebug, uUtils, uGearsHedgehog, uGearsRender; + uAmmos, uDebug, uUtils, uGearsHedgehog, uGearsRender, uLandUtils; const IsNilHHFatal = false; @@ -241,7 +241,7 @@ begin lx := hwRound(nx); ly := hwRound(ny); - if ((ly and LAND_HEIGHT_MASK) = 0) and ((lx and LAND_WIDTH_MASK) = 0) and (Land[ly, lx] > lfAllObjMask) then + if ((ly and LAND_HEIGHT_MASK) = 0) and ((lx and LAND_WIDTH_MASK) = 0) and (LandGet(ly, lx) > lfAllObjMask) then begin tx := _1 / Distance(ropeDx, ropeDy); // old rope pos @@ -358,7 +358,7 @@ HHGear^.dY := HHGear^.dY * len; end; - haveCollision:= ((hwRound(Gear^.Y) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X) and LAND_WIDTH_MASK) = 0) and ((Land[hwRound(Gear^.Y), hwRound(Gear^.X)]) <> 0); + haveCollision:= ((hwRound(Gear^.Y) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X) and LAND_WIDTH_MASK) = 0) and ((LandGet(hwRound(Gear^.Y), hwRound(Gear^.X))) <> 0); if not haveCollision then begin @@ -474,7 +474,7 @@ ty := _0; while tt > _20 do begin - if ((hwRound(Gear^.Y+ty) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X+tx) and LAND_WIDTH_MASK) = 0) and (Land[hwRound(Gear^.Y+ty), hwRound(Gear^.X+tx)] > lfAllObjMask) then + if ((hwRound(Gear^.Y+ty) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X+tx) and LAND_WIDTH_MASK) = 0) and (LandGet(hwRound(Gear^.Y+ty), hwRound(Gear^.X+tx)) > lfAllObjMask) then begin Gear^.X := Gear^.X + tx; Gear^.Y := Gear^.Y + ty; diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uGearsHedgehog.pas --- a/hedgewars/uGearsHedgehog.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uGearsHedgehog.pas Tue Aug 22 08:35:46 2023 +0200 @@ -29,7 +29,7 @@ procedure HedgehogChAngle(HHGear: PGear); procedure PickUp(HH, Gear: PGear); procedure AddPickup(HH: THedgehog; ammo: TAmmoType; cnt, X, Y: LongWord); -procedure CheckIce(Gear: PGear); inline; +procedure CheckIce(Gear: PGear); procedure PlayTaunt(taunt: Longword); function HHGetTimer(Gear: PGear): LongWord; function HHGetTimerMsg(Gear: PGear): LongWord; @@ -1529,7 +1529,7 @@ AllInactive:= false end; -procedure CheckIce(Gear: PGear); inline; +procedure CheckIce(Gear: PGear); (* var x,y,tx,ty: LongInt; tdX, tdY, slope: hwFloat; diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uGearsRender.pas --- a/hedgewars/uGearsRender.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uGearsRender.pas Tue Aug 22 08:35:46 2023 +0200 @@ -56,7 +56,7 @@ end; implementation -uses uRender, uRenderUtils, uGearsUtils, uUtils, uVariables, uAmmos, Math, uVisualGearsList; +uses uRender, uRenderUtils, uGearsUtils, uUtils, uVariables, uAmmos, Math, uVisualGearsList, uLandUtils; procedure DrawRopeLinesRQ(Gear: PGear); var n: LongInt; @@ -72,7 +72,7 @@ if (RopePoints.Count > 0) or (Gear^.Elasticity.QWordValue > 0) then begin EnableTexture(false); - + Tint(Gear^.Tint shr 24 div 3, Gear^.Tint shr 16 and $FF div 3, Gear^.Tint shr 8 and $FF div 3, Gear^.Tint and $FF); n:= RopePoints.Count + 2; @@ -541,7 +541,7 @@ hy:= ty; wraps:= 0; inWorldBounds := ((ty and LAND_HEIGHT_MASK) or (tx and LAND_WIDTH_MASK)) = 0; - while (inWorldBounds and ((Land[ty, tx] and lfAll) = 0)) or (not inWorldBounds) do + while (inWorldBounds and ((LandGet(ty, tx) and lfAll) = 0)) or (not inWorldBounds) do begin if wraps > cMaxLaserSightWraps then break; @@ -1049,7 +1049,7 @@ ty:= hwRound(Gear^.Y) + cHHRadius + 2; if ((tx and LAND_WIDTH_MASK) = 0) and ((ty and LAND_HEIGHT_MASK) = 0) and - (Land[ty, tx] <> 0) then + (LandGet(ty, tx) <> 0) then AddVisualGear(tx - 2 + Random(4), ty - 8, vgtDust); end; @@ -1417,7 +1417,7 @@ DrawSpriteRotated(sprMineOn, x, y, 0, Gear^.DirAngle) else DrawSpriteRotated(sprMineDead, x, y, 0, Gear^.DirAngle); end; - gtAirMine: + gtAirMine: // render air mine based on its state: // frozen if (Gear^.State and gstFrozen <> 0) then diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uGearsUtils.pas --- a/hedgewars/uGearsUtils.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uGearsUtils.pas Tue Aug 22 08:35:46 2023 +0200 @@ -22,7 +22,7 @@ interface uses uTypes, uFloat; -procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword); inline; +procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword); procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword; const Tint: LongWord); procedure AddSplashForGear(Gear: PGear; justSkipping: boolean); procedure AddBounceEffectForGear(Gear: PGear; imageScale: Single); @@ -39,7 +39,7 @@ procedure CalcRotationDirAngle(Gear: PGear); procedure ResurrectHedgehog(var gear: PGear); -procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt); inline; +procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt); procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity: boolean); procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity, deleteOnFail: boolean); procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right, Bottom: LongInt; skipProximity, deleteOnFail: boolean); @@ -48,8 +48,8 @@ function CheckGearNear(Kind: TGearType; X, Y: hwFloat; rX, rY: LongInt): PGear; function CheckGearNear(Gear: PGear; Kind: TGearType; rX, rY: LongInt): PGear; function CheckGearDrowning(var Gear: PGear): boolean; -procedure CheckCollision(Gear: PGear); inline; -procedure CheckCollisionWithLand(Gear: PGear); inline; +procedure CheckCollision(Gear: PGear); +procedure CheckCollisionWithLand(Gear: PGear); procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt); procedure AmmoShoveCache(Ammo: PGear; Damage, Power: LongInt); @@ -63,7 +63,7 @@ procedure SetAllToActive; procedure SetAllHHToActive(Ice: boolean); -procedure SetAllHHToActive(); inline; +procedure SetAllHHToActive(); function GetAmmo(Hedgehog: PHedgehog): TAmmoType; function GetUtility(Hedgehog: PHedgehog): TAmmoType; @@ -84,9 +84,9 @@ uVariables, uLandGraphics, uScript, uStats, uCaptions, uTeams, uStore, uLocale, uTextures, uRenderUtils, uRandom, SDLh, uDebug, uGearsList, Math, uVisualGearsList, uGearsHandlersMess, - uGearsHedgehog; + uGearsHedgehog, uLandUtils; -procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword); inline; +procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword); begin doMakeExplosion(X, Y, Radius, AttackingHog, Mask, $FFFFFFFF); end; @@ -873,7 +873,7 @@ begin if (y and LAND_HEIGHT_MASK) = 0 then for i:= max(x - r, 0) to min(x + r, LAND_WIDTH - 1) do - if (Land[y, i] and mask <> 0) and (Land[y, i] and antimask = 0) then + if (LandGet(y, i) and mask <> 0) and (LandGet(y, i) and antimask = 0) then begin inc(count); if count = c then @@ -895,8 +895,8 @@ begin for i:= r - c + 2 to r do begin - if (Land[y, x - i] and mask <> 0) then inc(cnt); - if (Land[y, x + i] and mask <> 0) then inc(cnt); + if (LandGet(y, x - i) and mask <> 0) then inc(cnt); + if (LandGet(y, x + i) and mask <> 0) then inc(cnt); if cnt >= c then begin @@ -925,12 +925,12 @@ NoGearsToAvoid:= true end; -procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt); inline; +procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt); begin FindPlace(Gear, withFall, Left, Right, false, true); end; -procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity: boolean); inline; +procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity: boolean); begin FindPlace(Gear, withFall, Left, Right, skipProximity, true); end; @@ -965,7 +965,7 @@ repeat if GetRandom(2) = 0 then dir:= -1 else dir:= 1; x:= max(LAND_WIDTH div 2048, LongInt(GetRandom(Delta))); - if dir = 1 then x:= Left + x else x:= Right - x; + if dir = 1 then x:= Left + x else x:= Right - x; repeat cnt:= 0; y:= min(1024, topY) - Gear^.Radius shl 1; @@ -984,7 +984,7 @@ until (y >= Bottom) or (ignoreOverlap and (CountLand(x, y, Gear^.Radius - 1, 1, lfAll, 0) <> 0)) or - (not ignoreOverlap and + (not ignoreOverlap and (CountLand(x, y, Gear^.Radius - 1, 1, lfLandMask, 0) <> 0)); if (y - sy > Gear^.Radius * 2) and (y < Bottom) @@ -1172,7 +1172,7 @@ CheckGearNear := CheckGearNearImpl(Kind, Gear^.X, Gear^.Y, rX, rY, Gear); end; -procedure CheckCollision(Gear: PGear); inline; +procedure CheckCollision(Gear: PGear); begin if (TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) <> 0) or (TestCollisionYwithGear(Gear, hwSign(Gear^.dY)) <> 0) then @@ -1181,7 +1181,7 @@ Gear^.State := Gear^.State and (not gstCollision) end; -procedure CheckCollisionWithLand(Gear: PGear); inline; +procedure CheckCollisionWithLand(Gear: PGear); begin if (TestCollisionX(Gear, hwSign(Gear^.dX)) <> 0) or (TestCollisionY(Gear, hwSign(Gear^.dY)) <> 0) then @@ -1413,8 +1413,8 @@ gtFirePunch, gtKamikaze, gtWhip, gtShover]) and (((Ammo^.Data <> nil) and (PGear(Ammo^.Data) = Gear)) or (not UpdateHitOrder( - Gear, - Ammo^.WDTimer, + Gear, + Ammo^.WDTimer, (Ammo^.Kind = gtMinigunBullet) and (Ammo^.Pos <> 0)))) then continue; @@ -1502,10 +1502,10 @@ else if ((Ammo^.Kind <> gtFlame) or (Gear^.Kind = gtHedgehog)) and (Power <> 0) then begin if (Ammo^.Kind in [gtMinigunBullet]) then - begin + begin Gear^.dX:= Gear^.dX + Ammo^.dX * Power * _0_01; Gear^.dY:= Gear^.dY + Ammo^.dY * Power * _0_01 - end + end else begin Gear^.dX:= Ammo^.dX * Power * _0_01; @@ -1591,7 +1591,7 @@ end end; -procedure SetAllHHToActive; inline; +procedure SetAllHHToActive; begin SetAllHHToActive(true) end; diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uInputHandler.pas --- a/hedgewars/uInputHandler.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uInputHandler.pas Tue Aug 22 08:35:46 2023 +0200 @@ -25,7 +25,7 @@ procedure initModule; procedure freeModule; -function KeyNameToCode(name: shortstring): LongInt; inline; +function KeyNameToCode(name: shortstring): LongInt; function KeyNameToCode(name: shortstring; Modifier: shortstring): LongInt; function KeyBindToCode(bind: shortstring): LongInt; @@ -36,7 +36,7 @@ procedure ProcessMouseMotion(xrel, yrel: LongInt); //procedure ProcessMouseWheel(x, y: LongInt); procedure ProcessMouseWheel(y: LongInt); -procedure ProcessKey(event: TSDL_KeyboardEvent); inline; +procedure ProcessKey(event: TSDL_KeyboardEvent); procedure ProcessKey(code: LongInt; KeyDown: boolean); {$IFDEF USE_AM_NUMCOLUMN} @@ -84,7 +84,7 @@ //ControllerHats: array[0..5] of array[0..19] of Byte; //ControllerButtons: array[0..5] of array[0..19] of Byte; -function KeyNameToCode(name: shortstring): LongInt; inline; +function KeyNameToCode(name: shortstring): LongInt; begin KeyNameToCode:= KeyNameToCode(name, ''); end; @@ -294,7 +294,7 @@ end end; -procedure ProcessKey(event: TSDL_KeyboardEvent); inline; +procedure ProcessKey(event: TSDL_KeyboardEvent); var code: LongInt; begin // TODO diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uLand.pas --- a/hedgewars/uLand.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uLand.pas Tue Aug 22 08:35:46 2023 +0200 @@ -38,13 +38,12 @@ var digest: shortstring; maskOnly: boolean; - procedure PrettifyLandAlpha(); begin if (cReducedQuality and rqBlurryLand) <> 0 then - PrettifyAlpha2D(LandPixels, LAND_HEIGHT div 2, LAND_WIDTH div 2) + PrettifyAlpha2D(LAND_HEIGHT div 2, LAND_WIDTH div 2) else - PrettifyAlpha2D(LandPixels, LAND_HEIGHT, LAND_WIDTH); + PrettifyAlpha2D(LAND_HEIGHT, LAND_WIDTH); end; procedure DrawBorderFromImage(Surface: PSDL_Surface); @@ -64,18 +63,18 @@ begin yd:= LAND_HEIGHT - 1; repeat - while (yd > 0) and ((Land[yd, x] and targetMask) = 0) do dec(yd); + while (yd > 0) and ((LandGet(yd, x) and targetMask) = 0) do dec(yd); if (yd < 0) then yd:= 0; - while (yd < LAND_HEIGHT) and ((Land[yd, x] and targetMask) <> 0) do + while (yd < LAND_HEIGHT) and ((LandGet(yd, x) and targetMask) <> 0) do inc(yd); dec(yd); yu:= yd; - while (yu > 0 ) and ((Land[yu, x] and targetMask) <> 0) do dec(yu); - while (yu < yd ) and ((Land[yu, x] and targetMask) = 0) do inc(yu); + while (yu > 0 ) and ((LandGet(yu, x) and targetMask) <> 0) do dec(yu); + while (yu < yd ) and ((LandGet(yu, x) and targetMask) = 0) do inc(yu); if (yd < LAND_HEIGHT - 1) and ((yd - yu) >= 16) then copyToXYFromRect(tmpsurf, Surface, x mod tmpsurf^.w, 16, 1, 16, x, yd - 15); @@ -100,7 +99,7 @@ for x:= 0 to LAND_WIDTH - 1 do for y:= 0 to LAND_HEIGHT - 1 do - if Land[y, x] = 0 then + if LandGet(y, x) = 0 then if s < y then begin for i:= max(s, y - 8) to y - 1 do @@ -108,9 +107,9 @@ if ((x + i) and 16) = 0 then c:= c1 else c:= c2; if (cReducedQuality and rqBlurryLand) = 0 then - LandPixels[i, x]:= c + LandPixelSet(i, x, c) else - LandPixels[i div 2, x div 2]:= c + LandPixelSet(i div 2, x div 2, c) end; s:= LAND_HEIGHT end @@ -123,9 +122,9 @@ if ((x + y) and 16) = 0 then c:= c1 else c:= c2; if (cReducedQuality and rqBlurryLand) = 0 then - LandPixels[y, x]:= c + LandPixelSet(y, x, c) else - LandPixels[y div 2, x div 2]:= c + LandPixelSet(y div 2, x div 2, c) end; end; @@ -134,7 +133,7 @@ for y:= 0 to LAND_HEIGHT - 1 do for x:= 0 to LAND_WIDTH - 1 do - if Land[y, x] = 0 then + if LandGet(y, x) = 0 then if s < x then begin for i:= max(s, x - 8) to x - 1 do @@ -142,9 +141,9 @@ if ((y + i) and 16) = 0 then c:= c1 else c:= c2; if (cReducedQuality and rqBlurryLand) = 0 then - LandPixels[y, i]:= c + LandPixelSet(y, i, c) else - LandPixels[y div 2, i div 2]:= c + LandPixelSet(y div 2, i div 2, c) end; s:= LAND_WIDTH end @@ -157,9 +156,9 @@ if ((x + y) and 16) = 0 then c:= c1 else c:= c2; if (cReducedQuality and rqBlurryLand) = 0 then - LandPixels[y, x]:= c + LandPixelSet(y, x, c) else - LandPixels[y div 2, x div 2]:= c + LandPixelSet(y div 2, x div 2, c) end; end end; @@ -356,12 +355,12 @@ uLandPainted.Draw; end; -function SelectTemplate: LongInt; +function SelectTemplate: shortstring; var l: LongInt; begin - SelectTemplate:= 0; + SelectTemplate:= ''; if (cReducedQuality and rqLowRes) <> 0 then - SelectTemplate:= SmallTemplates[getrandom(Succ(High(SmallTemplates)))] + SelectTemplate:= 'small' else begin if cTemplateFilter = 0 then @@ -376,20 +375,20 @@ case cTemplateFilter of 0: OutError('Error selecting TemplateFilter. Ask unC0Rr about what you did wrong', true); - 1: SelectTemplate:= SmallTemplates[getrandom(TemplateCounts[cTemplateFilter])]; - 2: SelectTemplate:= MediumTemplates[getrandom(TemplateCounts[cTemplateFilter])]; - 3: SelectTemplate:= LargeTemplates[getrandom(TemplateCounts[cTemplateFilter])]; - 4: SelectTemplate:= CavernTemplates[getrandom(TemplateCounts[cTemplateFilter])]; - 5: SelectTemplate:= WackyTemplates[getrandom(TemplateCounts[cTemplateFilter])]; + 1: SelectTemplate:= 'small'; + 2: SelectTemplate:= 'medium'; + 3: SelectTemplate:= 'large'; + 4: SelectTemplate:= 'cavern'; + 5: SelectTemplate:= 'wacky'; // For lua only! 6: begin - SelectTemplate:= min(LuaTemplateNumber,High(EdgeTemplates)); + SelectTemplate:= 'small'; GetRandom(2) // burn 1 end end end; - WriteLnToConsole('Selected template #'+inttostr(SelectTemplate)+' using filter #'+inttostr(cTemplateFilter)); + WriteLnToConsole('Using template filter '+SelectTemplate); end; procedure LandSurface2LandPixels(Surface: PSDL_Surface); @@ -405,11 +404,11 @@ for y:= 0 to LAND_HEIGHT - 1 do begin for x:= 0 to LAND_WIDTH - 1 do - if Land[y, x] <> 0 then + if LandGet(y, x) <> 0 then if (cReducedQuality and rqBlurryLand) = 0 then - LandPixels[y, x]:= p^[x]// or AMask + LandPixelSet(y, x, p^[x])// or AMask else - LandPixels[y div 2, x div 2]:= p^[x]; + LandPixelSet(y div 2, x div 2, p^[x]); p:= PLongwordArray(@(p^[Surface^.pitch div 4])); end; @@ -439,38 +438,38 @@ for x:= LongWord(leftX+2) to LongWord(rightX-2) do for y:= LongWord(topY+2) to LAND_HEIGHT-3 do - if (Land[y, x] = 0) and - (((Land[y, x-1] = lfBasic) and ((Land[y+1,x] = lfBasic)) or (Land[y-1,x] = lfBasic)) or - ((Land[y, x+1] = lfBasic) and ((Land[y-1,x] = lfBasic) or (Land[y+1,x] = lfBasic)))) then + if (LandGet(y, x) = 0) and + (((LandGet(y, x-1) = lfBasic) and ((LandGet(y+1,x) = lfBasic)) or (LandGet(y-1,x) = lfBasic)) or + ((LandGet(y, x+1) = lfBasic) and ((LandGet(y-1,x) = lfBasic) or (LandGet(y+1,x) = lfBasic)))) then begin if (cReducedQuality and rqBlurryLand) = 0 then begin - if (Land[y, x-1] = lfBasic) and (LandPixels[y, x-1] and AMask <> 0) then - LandPixels[y, x]:= LandPixels[y, x-1] + if (LandGet(y, x-1) = lfBasic) and (LandPixelGet(y, x-1) and AMask <> 0) then + LandPixelSet(y, x, LandPixelGet(y, x-1)) - else if (Land[y, x+1] = lfBasic) and (LandPixels[y, x+1] and AMask <> 0) then - LandPixels[y, x]:= LandPixels[y, x+1] + else if (LandGet(y, x+1) = lfBasic) and (LandPixelGet(y, x+1) and AMask <> 0) then + LandPixelSet(y, x, LandPixelGet(y, x+1)) - else if (Land[y-1, x] = lfBasic) and (LandPixels[y-1, x] and AMask <> 0) then - LandPixels[y, x]:= LandPixels[y-1, x] + else if (LandGet(y-1, x) = lfBasic) and (LandPixelGet(y-1, x) and AMask <> 0) then + LandPixelSet(y, x, LandPixelGet(y-1, x)) - else if (Land[y+1, x] = lfBasic) and (LandPixels[y+1, x] and AMask <> 0) then - LandPixels[y, x]:= LandPixels[y+1, x]; + else if (LandGet(y+1, x) = lfBasic) and (LandPixelGet(y+1, x) and AMask <> 0) then + LandPixelSet(y, x, LandPixelGet(y+1, x)); - if (((LandPixels[y,x] and AMask) shr AShift) > 10) then - LandPixels[y,x]:= (LandPixels[y,x] and (not AMask)) or (128 shl AShift) + if (((LandPixelGet(y,x) and AMask) shr AShift) > 10) then + LandPixelSet(y, x, (LandPixelGet(y,x) and (not AMask)) or (128 shl AShift)) end; - Land[y,x]:= lfObject + LandSet(y, x, lfObject) end - else if (Land[y, x] = 0) and - (((Land[y, x-1] = lfBasic) and (Land[y+1,x-1] = lfBasic) and (Land[y+2,x] = lfBasic)) or - ((Land[y, x-1] = lfBasic) and (Land[y-1,x-1] = lfBasic) and (Land[y-2,x] = lfBasic)) or - ((Land[y, x+1] = lfBasic) and (Land[y+1,x+1] = lfBasic) and (Land[y+2,x] = lfBasic)) or - ((Land[y, x+1] = lfBasic) and (Land[y-1,x+1] = lfBasic) and (Land[y-2,x] = lfBasic)) or - ((Land[y+1, x] = lfBasic) and (Land[y+1,x+1] = lfBasic) and (Land[y,x+2] = lfBasic)) or - ((Land[y-1, x] = lfBasic) and (Land[y-1,x+1] = lfBasic) and (Land[y,x+2] = lfBasic)) or - ((Land[y+1, x] = lfBasic) and (Land[y+1,x-1] = lfBasic) and (Land[y,x-2] = lfBasic)) or - ((Land[y-1, x] = lfBasic) and (Land[y-1,x-1] = lfBasic) and (Land[y,x-2] = lfBasic))) then + else if (LandGet(y, x) = 0) and + (((LandGet(y, x-1) = lfBasic) and (LandGet(y+1,x-1) = lfBasic) and (LandGet(y+2,x) = lfBasic)) or + ((LandGet(y, x-1) = lfBasic) and (LandGet(y-1,x-1) = lfBasic) and (LandGet(y-2,x) = lfBasic)) or + ((LandGet(y, x+1) = lfBasic) and (LandGet(y+1,x+1) = lfBasic) and (LandGet(y+2,x) = lfBasic)) or + ((LandGet(y, x+1) = lfBasic) and (LandGet(y-1,x+1) = lfBasic) and (LandGet(y-2,x) = lfBasic)) or + ((LandGet(y+1, x) = lfBasic) and (LandGet(y+1,x+1) = lfBasic) and (LandGet(y,x+2) = lfBasic)) or + ((LandGet(y-1, x) = lfBasic) and (LandGet(y-1,x+1) = lfBasic) and (LandGet(y,x+2) = lfBasic)) or + ((LandGet(y+1, x) = lfBasic) and (LandGet(y+1,x-1) = lfBasic) and (LandGet(y,x-2) = lfBasic)) or + ((LandGet(y-1, x) = lfBasic) and (LandGet(y-1,x-1) = lfBasic) and (LandGet(y,x-2) = lfBasic))) then begin @@ -478,22 +477,22 @@ begin - if (Land[y, x-1] = lfBasic) and (LandPixels[y,x-1] and AMask <> 0) then - LandPixels[y, x]:= LandPixels[y, x-1] + if (LandGet(y, x-1) = lfBasic) and (LandPixelGet(y,x-1) and AMask <> 0) then + LandPixelSet(y, x, LandPixelGet(y, x-1)) - else if (Land[y, x+1] = lfBasic) and (LandPixels[y,x+1] and AMask <> 0) then - LandPixels[y, x]:= LandPixels[y, x+1] + else if (LandGet(y, x+1) = lfBasic) and (LandPixelGet(y,x+1) and AMask <> 0) then + LandPixelSet(y, x, LandPixelGet(y, x+1)) - else if (Land[y+1, x] = lfBasic) and (LandPixels[y+1,x] and AMask <> 0) then - LandPixels[y, x]:= LandPixels[y+1, x] + else if (LandGet(y+1, x) = lfBasic) and (LandPixelGet(y+1,x) and AMask <> 0) then + LandPixelSet(y, x, LandPixelGet(y+1, x)) - else if (Land[y-1, x] = lfBasic) and (LandPixels[y-1,x] and AMask <> 0) then - LandPixels[y, x]:= LandPixels[y-1, x]; + else if (LandGet(y-1, x) = lfBasic) and (LandPixelGet(y-1,x) and AMask <> 0) then + LandPixelSet(y, x, LandPixelGet(y-1, x)); - if (((LandPixels[y,x] and AMask) shr AShift) > 10) then - LandPixels[y,x]:= (LandPixels[y,x] and (not AMask)) or (64 shl AShift) + if (((LandPixelGet(y,x) and AMask) shr AShift) > 10) then + LandPixelSet(y, x, (LandPixelGet(y,x) and (not AMask)) or (64 shl AShift)) end; - Land[y,x]:= lfObject + LandSet(y, x, lfObject) end; AddProgress(); @@ -527,8 +526,8 @@ begin if (y <= wbm) and ((x - w1) mod (bmWidth * 2) >= bmWidth) then continue; - Land[y,x]:= lfBasic; - Land[y,lastX-x]:= lfBasic; + LandSet(y, x, lfBasic); + LandSet(y, lastX - x, lfBasic); end; end; @@ -545,8 +544,8 @@ // align battlement on inner edge, because real outer edge could be offscreen if (y <= wbm) and ((LAND_WIDTH + x - bmref) mod (bmWidth * 2) >= bmWidth) then continue; - Land[y,x]:= lfBasic; - Land[y,lastX-x]:= lfBasic; + LandSet(y, x, lfBasic); + LandSet(y, lastX - x, lfBasic); end; end; end; @@ -691,7 +690,7 @@ for y:= 0 to Pred(tmpsurf^.h) do begin for x:= 0 to Pred(tmpsurf^.w) do - SetLand(Land[cpY + y, cpX + x], p^[x]); + SetLand(cpY + y, cpX + x, p^[x]); p:= PLongwordArray(@(p^[tmpsurf^.pitch div 4])); end; @@ -756,16 +755,16 @@ for x:= LongWord(leftX) to LongWord(rightX) do begin y:= Longword(cWaterLine) - 1 - w; - Land[y, x]:= lfIndestructible; + LandSet(y, x, lfIndestructible); if (x + y) mod 32 < 16 then c:= AMask else c:= AMask or RMask or GMask; // FF00FFFF if (cReducedQuality and rqBlurryLand) = 0 then - LandPixels[y, x]:= c + LandPixelSet(y, x, c) else - LandPixels[y div 2, x div 2]:= c + LandPixelSet(y div 2, x div 2, c) end end; @@ -794,7 +793,7 @@ begin WriteLnToConsole('Generating land...'); case cMapGen of - mgRandom: GenTemplated(EdgeTemplates[SelectTemplate]); + mgRandom: GenerateTemplatedLand(cFeatureSize, cSeed, SelectTemplate, PathPrefix); mgMaze : begin ResizeLand(4096,2048); GenMaze; end; mgPerlin: begin ResizeLand(4096,2048); GenPerlin; end; mgDrawn : GenDrawnMap; @@ -802,7 +801,7 @@ else OutError('Unknown mapgen', true); end; - if cMapGen <> mgForts then + if (cMapGen <> mgForts) then GenLandSurface end; @@ -815,7 +814,7 @@ else for y:= LongWord(topY) to LongWord(topY + 5) do for x:= LongWord(leftX) to LongWord(rightX) do - if Land[y, x] <> 0 then + if LandGet(y, x) <> 0 then begin inc(c); if c > LongWord((LAND_WIDTH div 2)) then // avoid accidental triggering @@ -834,13 +833,13 @@ for y:= 0 to LAND_HEIGHT - 1 do for x:= 0 to LAND_WIDTH - 1 do if (y < LongWord(topY)) or (x < LongWord(leftX)) or (x > LongWord(rightX)) then - Land[y, x]:= lfIndestructible; + LandSet(y, x, lfIndestructible); end else if topY > 0 then begin for y:= 0 to LongWord(topY - 1) do for x:= 0 to LAND_WIDTH - 1 do - Land[y, x]:= lfIndestructible; + LandSet(y, x, lfIndestructible); end; // Render map border for w:= 0 to (cBorderWidth-1) do @@ -850,8 +849,8 @@ for y:= LongWord(topY) to LAND_HEIGHT - 1 do begin // set land flags - Land[y, leftX + w]:= lfIndestructible; - Land[y, rightX - w]:= lfIndestructible; + LandSet(y, leftX + w, lfIndestructible); + LandSet(y, rightX - w, lfIndestructible); // paint black and yellow stripes if (y + leftX + w) mod 32 < 16 then @@ -865,29 +864,29 @@ if (cReducedQuality and rqBlurryLand) = 0 then begin - LandPixels[y, leftX + w]:= c; - LandPixels[y, rightX - w]:= c2; + LandPixelSet(y, leftX + w, c); + LandPixelSet(y, rightX - w, c2); end else begin - LandPixels[y div 2, (leftX + w) div 2]:= c; - LandPixels[y div 2, (rightX - w) div 2]:= c2; + LandPixelSet(y div 2, (leftX + w) div 2, c); + LandPixelSet(y div 2, (rightX - w) div 2, c2); end; end; // Top border for x:= LongWord(leftX) to LongWord(rightX) do begin - Land[topY + w, x]:= lfIndestructible; + LandSet(topY + w, x, lfIndestructible); if (topY + x + w) mod 32 < 16 then c:= AMask // black else c:= AMask or RMask or GMask; // yellow if (cReducedQuality and rqBlurryLand) = 0 then - LandPixels[topY + w, x]:= c + LandPixelSet(topY + w, x, c) else - LandPixels[(topY + w) div 2, x div 2]:= c; + LandPixelSet((topY + w) div 2, x div 2, c); end; end; end; @@ -915,23 +914,23 @@ for x:= LongWord(leftX) to LongWord(rightX) do for y:= LongWord(topY) to LAND_HEIGHT-1 do begin - w:= LandPixels[y,x]; + w:= LandPixelGet(y,x); w:= round(((w shr RShift and $FF) * RGB_LUMINANCE_RED + (w shr BShift and $FF) * RGB_LUMINANCE_GREEN + (w shr GShift and $FF) * RGB_LUMINANCE_BLUE)); if w > 255 then w:= 255; - w:= (w and $FF shl RShift) or (w and $FF shl BShift) or (w and $FF shl GShift) or (LandPixels[y,x] and AMask); - LandPixels[y,x]:= w or (LandPixels[y, x] and AMask) + w:= (w and $FF shl RShift) or (w and $FF shl BShift) or (w and $FF shl GShift) or (LandPixelGet(y,x) and AMask); + LandPixelSet(y, x, w or (LandPixelGet(y, x) and AMask)) end else for x:= LongWord(leftX div 2) to LongWord(rightX div 2) do for y:= LongWord(topY div 2) to LAND_HEIGHT-1 div 2 do begin - w:= LandPixels[y div 2,x div 2]; + w:= LandPixelGet(y div 2,x div 2); w:= ((w shr RShift and $FF) + (w shr BShift and $FF) + (w shr GShift and $FF)) div 3; - w:= (w and $FF shl RShift) or (w and $FF shl BShift) or (w and $FF shl GShift) or (LandPixels[y div 2,x div 2] and AMask); - LandPixels[y,x]:= w or (LandPixels[y div 2, x div 2] and AMask) + w:= (w and $FF shl RShift) or (w and $FF shl BShift) or (w and $FF shl GShift) or (LandPixelGet(y div 2,x div 2) and AMask); + LandPixelSet(y, x, w or (LandPixelGet(y div 2, x div 2) and AMask)) end end; @@ -949,7 +948,7 @@ begin WriteLnToConsole('Generating preview...'); case cMapGen of - mgRandom: GenTemplated(EdgeTemplates[SelectTemplate]); + mgRandom: GenerateTemplatedLand(cFeatureSize, cSeed, SelectTemplate, PathPrefix); mgMaze: begin ResizeLand(4096,2048); GenMaze; end; mgPerlin: begin ResizeLand(4096,2048); GenPerlin; end; mgDrawn: begin GenDrawnMap; end; @@ -994,7 +993,7 @@ for yy:= y * lh to y * lh + 7 do for xx:= x * lw + cbit to x * lw + cbit + 7 do if ((yy-oy) and LAND_HEIGHT_MASK = 0) and ((xx-ox) and LAND_WIDTH_MASK = 0) - and (Land[yy-oy, xx-ox] <> 0) then + and (LandGet(yy-oy, xx-ox) <> 0) then inc(t); if t > 8 then Preview[y, x]:= Preview[y, x] or ($80 shr bit); @@ -1008,7 +1007,7 @@ begin WriteLnToConsole('Generating preview...'); case cMapGen of - mgRandom: GenTemplated(EdgeTemplates[SelectTemplate]); + mgRandom: GenerateTemplatedLand(cFeatureSize, cSeed, SelectTemplate, PathPrefix); mgMaze: begin ResizeLand(4096,2048); GenMaze; end; mgPerlin: begin ResizeLand(4096,2048); GenPerlin; end; mgDrawn: begin GenDrawnMap; end; @@ -1052,7 +1051,7 @@ for yy:= y * lh - oy to y * lh + lh - 1 - oy do for xx:= x * lw - ox to x * lw + lw - 1 - ox do if (yy and LAND_HEIGHT_MASK = 0) and (xx and LAND_WIDTH_MASK = 0) - and (Land[yy, xx] <> 0) then + and (LandGet(yy, xx) <> 0) then inc(t); Preview[y, x]:= t * 255 div (lh * lw); @@ -1074,7 +1073,7 @@ begin landPixelDigest:= 1; for i:= 0 to LAND_HEIGHT-1 do - landPixelDigest:= Adler32Update(landPixelDigest, @Land[i,0], LAND_WIDTH*2); + landPixelDigest:= Adler32Update(landPixelDigest, LandRow(i), LAND_WIDTH*2); s:= 'M' + IntToStr(syncedPixelDigest)+'|'+IntToStr(landPixelDigest); ScriptSetString('LandDigest',IntToStr(landPixelDigest)); @@ -1093,21 +1092,11 @@ maskOnly:= false; LAND_WIDTH:= 0; LAND_HEIGHT:= 0; -(* - if (cReducedQuality and rqBlurryLand) = 0 then - SetLength(LandPixels, LAND_HEIGHT, LAND_WIDTH) - else - SetLength(LandPixels, LAND_HEIGHT div 2, LAND_WIDTH div 2); - - SetLength(Land, LAND_HEIGHT, LAND_WIDTH); - SetLength(LandDirty, (LAND_HEIGHT div 32), (LAND_WIDTH div 32)); -*) end; procedure freeModule; begin - SetLength(Land, 0, 0); - SetLength(LandPixels, 0, 0); + DisposeLand; SetLength(LandDirty, 0, 0); end; diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uLandGenMaze.pas --- a/hedgewars/uLandGenMaze.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uLandGenMaze.pas Tue Aug 22 08:35:46 2023 +0200 @@ -8,7 +8,8 @@ implementation -uses uRandom, uLandOutline, uLandTemplates, uVariables, uFloat, uConsts, uLandGenTemplateBased, uUtils; +uses uRandom, uLandOutline, uLandTemplates, uVariables, uFloat, uConsts, + uLandGenTemplateBased, uUtils, uLandUtils; type direction = record x, y: LongInt; end; const DIR_N: direction = (x: 0; y: -1); @@ -403,11 +404,11 @@ for x := 0 to playWidth do for y := 0 to off_y - 1 do - Land[y, x] := 0; + LandSet(y, x, 0); for x := 0 to playWidth do for y := off_y to LAND_HEIGHT - 1 do - Land[y, x] := lfBasic; + LandSet(y, x, lfBasic); for y := 0 to num_cells_y - 1 do for x := 0 to num_cells_x - 1 do @@ -527,9 +528,9 @@ else begin x := 0; - while Land[cellsize div 2 + cellsize + off_y, x] = lfBasic do + while LandGet(cellsize div 2 + cellsize + off_y, x) = lfBasic do x := x + 1; - while Land[cellsize div 2 + cellsize + off_y, x] = 0 do + while LandGet(cellsize div 2 + cellsize + off_y, x) = 0 do x := x + 1; FillLand(x+1, cellsize div 2 + cellsize + off_y, 0, 0); end; diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uLandGenPerlin.pas --- a/hedgewars/uLandGenPerlin.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uLandGenPerlin.pas Tue Aug 22 08:35:46 2023 +0200 @@ -11,6 +11,7 @@ , uRandom , uLandOutline // FillLand , uUtils + , uLandUtils ; var p: array[0..511] of LongInt; @@ -39,7 +40,7 @@ 4086, 4088, 4089, 4091, 4092, 4092, 4093, 4094, 4094, 4095, 4095, 4095, 4095, 4095, 4095, 4095); -function fade(t: LongInt) : LongInt; inline; +function fade(t: LongInt) : LongInt; var t0, t1: LongInt; begin t0:= fadear[t shr 8]; @@ -53,13 +54,13 @@ end; -function lerp(t, a, b: LongInt) : LongInt; inline; +function lerp(t, a, b: LongInt) : LongInt; begin lerp:= a + ((Int64(b) - a) * t shr 12) end; -function grad(hash, x, y: LongInt) : LongInt; inline; +function grad(hash, x, y: LongInt) : LongInt; var h, v, u: LongInt; begin h:= hash and 15; @@ -74,7 +75,7 @@ end; -function inoise(x, y: LongInt) : LongInt; inline; +function inoise(x, y: LongInt) : LongInt; const N = $10000; var xx, yy, u, v, A, AA, AB, B, BA, BB: LongInt; begin @@ -205,24 +206,24 @@ } if r < rCutoff then - Land[y, x]:= 0 + LandSet(y, x, 0) else if param1 = 0 then - Land[y, x]:= lfObjMask + LandSet(y, x, lfObjMask) else - Land[y, x]:= lfBasic + LandSet(y, x, lfBasic) end; end; if param1 = 0 then begin for x:= 0 to width do - if Land[height - 1, x] = lfObjMask then FillLand(x, height - 1, 0, lfBasic); + if LandGet(height - 1, x) = lfObjMask then FillLand(x, height - 1, 0, lfBasic); // strip all lfObjMask pixels for y:= minY to LAND_HEIGHT - 1 do for x:= 0 to LAND_WIDTH - 1 do - if Land[y, x] = lfObjMask then - Land[y, x]:= 0; + if LandGet(y, x) = lfObjMask then + LandSet(y, x, 0); end; playWidth:= width; diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uLandGenTemplateBased.pas --- a/hedgewars/uLandGenTemplateBased.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uLandGenTemplateBased.pas Tue Aug 22 08:35:46 2023 +0200 @@ -330,7 +330,7 @@ ResizeLand(Template.TemplateWidth, Template.TemplateHeight); for y:= 0 to LAND_HEIGHT - 1 do for x:= 0 to LAND_WIDTH - 1 do - Land[y, x]:= lfBasic; + LandSet(y, x, lfBasic); minDistance:= sqr(cFeatureSize) div 8 + 10; //dabDiv:= getRandom(41)+60; @@ -368,13 +368,13 @@ for y:= 0 to LAND_HEIGHT - 1 do for x:= 0 to LAND_WIDTH - 1 do if (y < LongWord(topY)) or (x < LongWord(leftX)) or (x > LongWord(rightX)) then - Land[y, x]:= 0 + LandSet(y, x, 0) else begin - if Land[y, x] = 0 then - Land[y, x]:= lfBasic - else if Land[y, x] = lfBasic then - Land[y, x]:= 0; + if LandGet(y, x) = 0 then + LandSet(y, x, lfBasic) + else if LandGet(y, x) = lfBasic then + LandSet(y, x, 0); end; end; end; diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uLandGraphics.pas --- a/hedgewars/uLandGraphics.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uLandGraphics.pas Tue Aug 22 08:35:46 2023 +0200 @@ -47,19 +47,19 @@ function DrawThickLine(X1, Y1, X2, Y2, radius: LongInt; color: Longword): Longword; procedure DumpLandToLog(x, y, r: LongInt); procedure DrawIceBreak(x, y, iceRadius, iceHeight: Longint); -function TryPlaceOnLandSimple(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace, indestructible: boolean): boolean; inline; -function TryPlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace: boolean; LandFlags: Word): boolean; inline; -function ForcePlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; LandFlags: Word; Tint: LongWord; Behind, flipHoriz, flipVert: boolean): boolean; inline; +function TryPlaceOnLandSimple(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace, indestructible: boolean): boolean; +function TryPlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace: boolean; LandFlags: Word): boolean; +function ForcePlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; LandFlags: Word; Tint: LongWord; Behind, flipHoriz, flipVert: boolean): boolean; function TryPlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace, outOfMap, force, behind, flipHoriz, flipVert: boolean; LandFlags: Word; Tint: LongWord): boolean; procedure EraseLandRectRaw(X, Y, width, height: LongWord); procedure EraseLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; LandFlags: Word; eraseOnLFMatch, onlyEraseLF, flipHoriz, flipVert: boolean); function GetPlaceCollisionTex(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt): PTexture; implementation -uses SDLh, uLandTexture, uTextures, uVariables, uUtils, uDebug, uScript; +uses SDLh, uLandTexture, uTextures, uVariables, uUtils, uDebug, uScript, uLandUtils; -procedure calculatePixelsCoordinates(landX, landY: Longint; var pixelX, pixelY: Longint); inline; +procedure calculatePixelsCoordinates(landX, landY: Longint; var pixelX, pixelY: Longint); begin if (cReducedQuality and rqBlurryLand) = 0 then begin @@ -73,33 +73,33 @@ end; end; -function drawPixelBG(landX, landY, pixelX, pixelY: Longint): Longword; inline; +function drawPixelBG(landX, landY, pixelX, pixelY: Longint): Longword; begin drawPixelBG := 0; -if (Land[LandY, landX] and lfIndestructible) = 0 then +if (LandGet(LandY, landX) and lfIndestructible) = 0 then begin - if ((Land[landY, landX] and lfBasic) <> 0) and (((LandPixels[pixelY, pixelX] and AMask) shr AShift) = 255) and (not disableLandBack) then + if ((LandGet(landY, landX) and lfBasic) <> 0) and (((LandPixelGet(pixelY, pixelX) and AMask) shr AShift) = 255) and (not disableLandBack) then begin - LandPixels[pixelY, pixelX]:= LandBackPixel(landX, landY); + LandPixelSet(pixelY, pixelX, LandBackPixel(landX, landY)); inc(drawPixelBG); end - else if ((Land[landY, landX] and lfObject) <> 0) or (((LandPixels[pixelY, pixelX] and AMask) shr AShift) < 255) then - LandPixels[pixelY, pixelX]:= ExplosionBorderColorNoA + else if ((LandGet(landY, landX) and lfObject) <> 0) or (((LandPixelGet(pixelY, pixelX) and AMask) shr AShift) < 255) then + LandPixelSet(pixelY, pixelX, ExplosionBorderColorNoA) end; end; -procedure drawPixelEBC(landX, landY, pixelX, pixelY: Longint); inline; +procedure drawPixelEBC(landX, landY, pixelX, pixelY: Longint); begin -if (Land[landY, landX] and lfIndestructible = 0) and - (((Land[landY, landX] and lfBasic) <> 0) or ((Land[landY, landX] and lfObject) <> 0)) then +if (LandGet(landY, landX) and lfIndestructible = 0) and + (((LandGet(landY, landX) and lfBasic) <> 0) or ((LandGet(landY, landX) and lfObject) <> 0)) then begin - LandPixels[pixelY, pixelX]:= ExplosionBorderColor; - Land[landY, landX]:= (Land[landY, landX] or lfDamaged) and (not lfIce); + LandPixelSet(pixelY, pixelX, ExplosionBorderColor); + LandSet(landY, landX, (LandGet(landY, landX) or lfDamaged) and (not lfIce)); LandDirty[landY div 32, landX div 32]:= 1; end; end; -function isLandscapeEdge(weight:Longint):boolean; inline; +function isLandscapeEdge(weight:Longint):boolean; begin isLandscapeEdge := (weight < 8) and (weight >= 2); end; @@ -118,7 +118,7 @@ (j > LAND_HEIGHT -1) then exit(9); - if Land[j, i] and lfLandMask and (not lfIce) = 0 then + if LandGet(j, i) and lfLandMask and (not lfIce) = 0 then inc(r) end; @@ -126,7 +126,7 @@ end; -procedure fillPixelFromIceSprite(pixelX, pixelY:Longint); inline; +procedure fillPixelFromIceSprite(pixelX, pixelY:Longint); var iceSurface: PSDL_Surface; icePixels: PLongwordArray; @@ -136,7 +136,7 @@ // So. 3 parameters here. Ice colour, Ice opacity, and a bias on the greyscaled pixel towards lightness iceSurface:= SpritesData[sprIceTexture].Surface; icePixels := iceSurface^.pixels; - w:= LandPixels[pixelY, pixelX]; + w:= LandPixelGet(pixelY, pixelX); if w > 0 then begin w:= round(((w shr RShift and $FF) * RGB_LUMINANCE_RED + @@ -144,37 +144,37 @@ (w shr GShift and $FF) * RGB_LUMINANCE_BLUE)); if w < 128 then w:= w+128; if w > 255 then w:= 255; - w:= (w shl RShift) or (w shl BShift) or (w shl GShift) or (LandPixels[pixelY, pixelX] and AMask); - LandPixels[pixelY, pixelX]:= addBgColor(w, IceColor); - LandPixels[pixelY, pixelX]:= addBgColor(LandPixels[pixelY, pixelX], icePixels^[iceSurface^.w * (pixelY mod iceSurface^.h) + (pixelX mod iceSurface^.w)]) + w:= (w shl RShift) or (w shl BShift) or (w shl GShift) or (LandPixelGet(pixelY, pixelX) and AMask); + LandPixelSet(pixelY, pixelX, addBgColor(w, IceColor)); + LandPixelSet(pixelY, pixelX, addBgColor(LandPixelGet(pixelY, pixelX), icePixels^[iceSurface^.w * (pixelY mod iceSurface^.h) + (pixelX mod iceSurface^.w)])) end else begin - LandPixels[pixelY, pixelX]:= IceColor and (not AMask) or $E8 shl AShift; - LandPixels[pixelY, pixelX]:= addBgColor(LandPixels[pixelY, pixelX], icePixels^[iceSurface^.w * (pixelY mod iceSurface^.h) + (pixelX mod iceSurface^.w)]); + LandPixelSet(pixelY, pixelX, IceColor and (not AMask) or $E8 shl AShift); + LandPixelSet(pixelY, pixelX, addBgColor(LandPixelGet(pixelY, pixelX), icePixels^[iceSurface^.w * (pixelY mod iceSurface^.h) + (pixelX mod iceSurface^.w)])); // silly workaround to avoid having to make background erasure a tadb it smarter about sea ice - if LandPixels[pixelY, pixelX] and AMask shr AShift = 255 then - LandPixels[pixelY, pixelX]:= LandPixels[pixelY, pixelX] and (not AMask) or 254 shl AShift; + if LandPixelGet(pixelY, pixelX) and AMask shr AShift = 255 then + LandPixelSet(pixelY, pixelX, LandPixelGet(pixelY, pixelX) and (not AMask) or 254 shl AShift); end; end; -procedure DrawPixelIce(landX, landY, pixelX, pixelY: Longint); inline; +procedure DrawPixelIce(landX, landY, pixelX, pixelY: Longint); begin -if ((Land[landY, landX] and lfIce) <> 0) then exit; +if ((LandGet(landY, landX) and lfIce) <> 0) then exit; if (pixelX < LeftX) or (pixelX > RightX) or (pixelY < TopY) then exit; if isLandscapeEdge(getPixelWeight(landX, landY)) then begin - if (LandPixels[pixelY, pixelX] and AMask < 255) and (LandPixels[pixelY, pixelX] and AMask > 0) then - LandPixels[pixelY, pixelX] := (IceEdgeColor and (not AMask)) or (LandPixels[pixelY, pixelX] and AMask) - else if (LandPixels[pixelY, pixelX] and AMask < 255) or (Land[landY, landX] > 255) then - LandPixels[pixelY, pixelX] := IceEdgeColor + if (LandPixelGet(pixelY, pixelX) and AMask < 255) and (LandPixelGet(pixelY, pixelX) and AMask > 0) then + LandPixelSet(pixelY, pixelX, (IceEdgeColor and (not AMask)) or (LandPixelGet(pixelY, pixelX) and AMask)) + else if (LandPixelGet(pixelY, pixelX) and AMask < 255) or (LandGet(landY, landX) > 255) then + LandPixelSet(pixelY, pixelX, IceEdgeColor) end -else if Land[landY, landX] > 255 then +else if LandGet(landY, landX) > 255 then begin fillPixelFromIceSprite(pixelX, pixelY); end; -if Land[landY, landX] > 255 then Land[landY, landX] := Land[landY, landX] or lfIce and (not lfDamaged); +if LandGet(landY, landX) > 255 then LandSet(landY, landX, LandGet(landY, landX) or lfIce and (not lfDamaged)); end; @@ -202,8 +202,8 @@ for i:= fromPix to toPix do begin calculatePixelsCoordinates(i, y, px, py); - if ((Land[y, i] and lfIndestructible) = 0) and (not disableLandBack or (Land[y, i] > 255)) then - LandPixels[py, px]:= ExplosionBorderColorNoA; + if ((LandGet(y, i) and lfIndestructible) = 0) and (not disableLandBack or (LandGet(y, i) > 255)) then + LandPixelSet(py, px, ExplosionBorderColorNoA); end; icePixel: for i:= fromPix to toPix do @@ -214,41 +214,41 @@ addNotHHObj: for i:= fromPix to toPix do begin - if Land[y, i] and lfNotHHObjMask shr lfNotHHObjShift < lfNotHHObjSize then - Land[y, i]:= (Land[y, i] and (not lfNotHHObjMask)) or ((Land[y, i] and lfNotHHObjMask shr lfNotHHObjShift + 1) shl lfNotHHObjShift); + if LandGet(y, i) and lfNotHHObjMask shr lfNotHHObjShift < lfNotHHObjSize then + LandSet(y, i, (LandGet(y, i) and (not lfNotHHObjMask)) or ((LandGet(y, i) and lfNotHHObjMask shr lfNotHHObjShift + 1) shl lfNotHHObjShift)); end; removeNotHHObj: for i:= fromPix to toPix do begin - if Land[y, i] and lfNotHHObjMask <> 0 then - Land[y, i]:= (Land[y, i] and (not lfNotHHObjMask)) or ((Land[y, i] and lfNotHHObjMask shr lfNotHHObjShift - 1) shl lfNotHHObjShift); + if LandGet(y, i) and lfNotHHObjMask <> 0 then + LandSet(y, i, (LandGet(y, i) and (not lfNotHHObjMask)) or ((LandGet(y, i) and lfNotHHObjMask shr lfNotHHObjShift - 1) shl lfNotHHObjShift)); end; addHH: for i:= fromPix to toPix do begin - if Land[y, i] and lfHHMask < lfHHMask then - Land[y, i]:= Land[y, i] + 1 + if LandGet(y, i) and lfHHMask < lfHHMask then + LandSet(y, i, LandGet(y, i) + 1) end; removeHH: for i:= fromPix to toPix do begin - if Land[y, i] and lfHHMask > 0 then - Land[y, i]:= Land[y, i] - 1; + if LandGet(y, i) and lfHHMask > 0 then + LandSet(y, i, LandGet(y, i) - 1); end; setCurrentHog: for i:= fromPix to toPix do begin - Land[y, i]:= Land[y, i] or lfCurHogCrate + LandSet(y, i, LandGet(y, i) or lfCurHogCrate) end; removeCurrentHog: for i:= fromPix to toPix do begin - Land[y, i]:= Land[y, i] and lfNotCurHogCrate; + LandSet(y, i, LandGet(y, i) and lfNotCurHogCrate); end; end; end; -function FillLandCircleSegmentFT(x, y, dx, dy: LongInt; fill : fillType): Longword; inline; +function FillLandCircleSegmentFT(x, y, dx, dy: LongInt; fill : fillType): Longword; begin FillLandCircleSegmentFT := 0; if ((y + dy) and LAND_HEIGHT_MASK) = 0 then @@ -261,7 +261,7 @@ inc(FillLandCircleSegmentFT, FillLandCircleLineFT(y - dx, Max(x - dy, 0), Min(x + dy, LAND_WIDTH - 1), fill)); end; -function FillRoundInLandFT(X, Y, Radius: LongInt; fill: fillType): Longword; inline; +function FillRoundInLandFT(X, Y, Radius: LongInt; fill: fillType): Longword; var dx, dy, d: LongInt; begin dx:= 0; @@ -323,31 +323,31 @@ if ((y + dy) and LAND_HEIGHT_MASK) = 0 then for i:= Max(x - dx, 0) to Min(x + dx, LAND_WIDTH - 1) do - if (Land[y + dy, i] and lfIndestructible) = 0 then + if (LandGet(y + dy, i) and lfIndestructible) = 0 then begin - if Land[y + dy, i] <> Value then inc(FillCircleLines); - Land[y + dy, i]:= Value; + if LandGet(y + dy, i) <> Value then inc(FillCircleLines); + LandSet(y + dy, i, Value); end; if ((y - dy) and LAND_HEIGHT_MASK) = 0 then for i:= Max(x - dx, 0) to Min(x + dx, LAND_WIDTH - 1) do - if (Land[y - dy, i] and lfIndestructible) = 0 then + if (LandGet(y - dy, i) and lfIndestructible) = 0 then begin - if Land[y - dy, i] <> Value then inc(FillCircleLines); - Land[y - dy, i]:= Value; + if LandGet(y - dy, i) <> Value then inc(FillCircleLines); + LandSet(y - dy, i, Value); end; if ((y + dx) and LAND_HEIGHT_MASK) = 0 then for i:= Max(x - dy, 0) to Min(x + dy, LAND_WIDTH - 1) do - if (Land[y + dx, i] and lfIndestructible) = 0 then + if (LandGet(y + dx, i) and lfIndestructible) = 0 then begin - if Land[y + dx, i] <> Value then inc(FillCircleLines); - Land[y + dx, i]:= Value; + if LandGet(y + dx, i) <> Value then inc(FillCircleLines); + LandSet(y + dx, i, Value); end; if ((y - dx) and LAND_HEIGHT_MASK) = 0 then for i:= Max(x - dy, 0) to Min(x + dy, LAND_WIDTH - 1) do - if (Land[y - dx, i] and lfIndestructible) = 0 then + if (LandGet(y - dx, i) and lfIndestructible) = 0 then begin - if Land[y - dx, i] <> Value then inc(FillCircleLines); - Land[y - dx, i]:= Value; + if LandGet(y - dx, i) <> Value then inc(FillCircleLines); + LandSet(y - dx, i, Value); end; end; @@ -435,9 +435,9 @@ begin for j := iceT to iceB do begin - if Land[j, i] = 0 then + if LandGet(j, i) = 0 then begin - Land[j, i] := lfIce; + LandSet(j, i, lfIce); if (cReducedQuality and rqBlurryLand) = 0 then fillPixelFromIceSprite(i, j) else @@ -478,7 +478,7 @@ for ty:= Max(y - Radius, 0) to Min(y + Radius, TopY) do for tx:= Max(LeftX, ar^[i].Left - Radius) to Min(RightX, ar^[i].Right + Radius) do begin - if (Land[ty, tx] and lfIndestructible) = 0 then + if (LandGet(ty, tx) and lfIndestructible) = 0 then begin if (cReducedQuality and rqBlurryLand) = 0 then begin @@ -488,10 +488,10 @@ begin by:= ty div 2; bx:= tx div 2; end; - if ((Land[ty, tx] and lfBasic) <> 0) and (((LandPixels[by,bx] and AMask) shr AShift) = 255) and (not disableLandBack) then - LandPixels[by, bx]:= LandBackPixel(tx, ty) - else if ((Land[ty, tx] and lfObject) <> 0) or (((LandPixels[by,bx] and AMask) shr AShift) < 255) then - LandPixels[by, bx]:= LandPixels[by, bx] and (not AMASK) + if ((LandGet(ty, tx) and lfBasic) <> 0) and (((LandPixelGet(by,bx) and AMask) shr AShift) = 255) and (not disableLandBack) then + LandPixelSet(by, bx, LandBackPixel(tx, ty)) + else if ((LandGet(ty, tx) and lfObject) <> 0) or (((LandPixelGet(by,bx) and AMask) shr AShift) < 255) then + LandPixelSet(by, bx, LandPixelGet(by, bx) and (not AMASK)) end end; inc(y, dY) @@ -504,14 +504,14 @@ begin for ty:= Max(y - Radius, 0) to Min(y + Radius, TopY) do for tx:= Max(LeftX, ar^[i].Left - Radius) to Min(RightX, ar^[i].Right + Radius) do - if ((Land[ty, tx] and lfBasic) <> 0) or ((Land[ty, tx] and lfObject) <> 0) then + if ((LandGet(ty, tx) and lfBasic) <> 0) or ((LandGet(ty, tx) and lfObject) <> 0) then begin if (cReducedQuality and rqBlurryLand) = 0 then - LandPixels[ty, tx]:= ExplosionBorderColor + LandPixelSet(ty, tx, ExplosionBorderColor) else - LandPixels[ty div 2, tx div 2]:= ExplosionBorderColor; + LandPixelSet(ty div 2, tx div 2, ExplosionBorderColor); - Land[ty, tx]:= (Land[ty, tx] or lfDamaged) and (not lfIce); + LandSet(ty, tx, (LandGet(ty, tx) or lfDamaged) and (not lfIce)); LandDirty[ty div 32, tx div 32]:= 1; end; inc(y, dY) @@ -533,16 +533,16 @@ Y:= Y + dY; tx:= hwRound(X); ty:= hwRound(Y); - if ((ty and LAND_HEIGHT_MASK) = 0) and ((tx and LAND_WIDTH_MASK) = 0) and (((Land[ty, tx] and lfBasic) <> 0) - or ((Land[ty, tx] and lfObject) <> 0)) then + if ((ty and LAND_HEIGHT_MASK) = 0) and ((tx and LAND_WIDTH_MASK) = 0) and (((LandGet(ty, tx) and lfBasic) <> 0) + or ((LandGet(ty, tx) and lfObject) <> 0)) then begin - Land[ty, tx]:= (Land[ty, tx] or lfDamaged) and (not lfIce); + LandSet(ty, tx, (LandGet(ty, tx) or lfDamaged) and (not lfIce)); if despeckle then LandDirty[ty div 32, tx div 32]:= 1; if (cReducedQuality and rqBlurryLand) = 0 then - LandPixels[ty, tx]:= ExplosionBorderColor + LandPixelSet(ty, tx, ExplosionBorderColor) else - LandPixels[ty div 2, tx div 2]:= ExplosionBorderColor + LandPixelSet(ty div 2, tx div 2, ExplosionBorderColor) end end; end; @@ -581,18 +581,18 @@ ty:= hwRound(Y); if ((ty and LAND_HEIGHT_MASK) = 0) and ((tx and LAND_WIDTH_MASK) = 0) - and (((Land[ty, tx] and lfBasic) <> 0) or ((Land[ty, tx] and lfObject) <> 0)) then + and (((LandGet(ty, tx) and lfBasic) <> 0) or ((LandGet(ty, tx) and lfObject) <> 0)) then begin - Land[ty, tx]:= Land[ty, tx] and (not lfIce); + LandSet(ty, tx, LandGet(ty, tx) and (not lfIce)); if despeckle then begin - Land[ty, tx]:= Land[ty, tx] or lfDamaged; + LandSet(ty, tx, LandGet(ty, tx) or lfDamaged); LandDirty[ty div 32, tx div 32]:= 1 end; if (cReducedQuality and rqBlurryLand) = 0 then - LandPixels[ty, tx]:= ExplosionBorderColor + LandPixelSet(ty, tx, ExplosionBorderColor) else - LandPixels[ty div 2, tx div 2]:= ExplosionBorderColor + LandPixelSet(ty div 2, tx div 2, ExplosionBorderColor) end end; nx:= nx - dY; @@ -612,7 +612,7 @@ Y:= Y + dY; tx:= hwRound(X); ty:= hwRound(Y); - if ((ty and LAND_HEIGHT_MASK) = 0) and ((tx and LAND_WIDTH_MASK) = 0) and ((Land[ty, tx] and lfIndestructible) = 0) then + if ((ty and LAND_HEIGHT_MASK) = 0) and ((tx and LAND_WIDTH_MASK) = 0) and ((LandGet(ty, tx) and lfIndestructible) = 0) then begin if (cReducedQuality and rqBlurryLand) = 0 then begin @@ -622,11 +622,11 @@ begin by:= ty div 2; bx:= tx div 2; end; - if ((Land[ty, tx] and lfBasic) <> 0) and (((LandPixels[by,bx] and AMask) shr AShift) = 255) and (not disableLandBack) then - LandPixels[by, bx]:= LandBackPixel(tx, ty) - else if ((Land[ty, tx] and lfObject) <> 0) or (((LandPixels[by,bx] and AMask) shr AShift) < 255) then - LandPixels[by, bx]:= LandPixels[by, bx] and (not AMASK); - Land[ty, tx]:= 0; + if ((LandGet(ty, tx) and lfBasic) <> 0) and (((LandPixelGet(by,bx) and AMask) shr AShift) = 255) and (not disableLandBack) then + LandPixelSet(by, bx, LandBackPixel(tx, ty)) + else if ((LandGet(ty, tx) and lfObject) <> 0) or (((LandPixelGet(by,bx) and AMask) shr AShift) < 255) then + LandPixelSet(by, bx, LandPixelGet(by, bx) and (not AMASK)); + LandSet(ty, tx, 0); end end; DrawExplosionBorder(X, Y, dx, dy, despeckle); @@ -644,16 +644,16 @@ Y:= Y + dY; tx:= hwRound(X); ty:= hwRound(Y); - if ((ty and LAND_HEIGHT_MASK) = 0) and ((tx and LAND_WIDTH_MASK) = 0) and (((Land[ty, tx] and lfBasic) <> 0) - or ((Land[ty, tx] and lfObject) <> 0)) then + if ((ty and LAND_HEIGHT_MASK) = 0) and ((tx and LAND_WIDTH_MASK) = 0) and (((LandGet(ty, tx) and lfBasic) <> 0) + or ((LandGet(ty, tx) and lfObject) <> 0)) then begin - Land[ty, tx]:= (Land[ty, tx] or lfDamaged) and (not lfIce); + LandSet(ty, tx, (LandGet(ty, tx) or lfDamaged) and (not lfIce)); if despeckle then LandDirty[ty div 32, tx div 32]:= 1; if (cReducedQuality and rqBlurryLand) = 0 then - LandPixels[ty, tx]:= ExplosionBorderColor + LandPixelSet(ty, tx, ExplosionBorderColor) else - LandPixels[ty div 2, tx div 2]:= ExplosionBorderColor + LandPixelSet(ty div 2, tx div 2, ExplosionBorderColor) end end; nx:= nx - dY; @@ -692,7 +692,7 @@ end; end; -function TryPlaceOnLandSimple(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace, indestructible: boolean): boolean; inline; +function TryPlaceOnLandSimple(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace, indestructible: boolean): boolean; var lf: Word; begin if indestructible then @@ -702,12 +702,12 @@ TryPlaceOnLandSimple:= TryPlaceOnLand(cpX, cpY, Obj, Frame, doPlace, false, false, false, false, false, lf, $FFFFFFFF); end; -function TryPlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace: boolean; LandFlags: Word): boolean; inline; +function TryPlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; doPlace: boolean; LandFlags: Word): boolean; begin TryPlaceOnLand:= TryPlaceOnLand(cpX, cpY, Obj, Frame, doPlace, false, false, false, false, false, LandFlags, $FFFFFFFF); end; -function ForcePlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; LandFlags: Word; Tint: LongWord; Behind, flipHoriz, flipVert: boolean): boolean; inline; +function ForcePlaceOnLand(cpX, cpY: LongInt; Obj: TSprite; Frame: LongInt; LandFlags: Word; Tint: LongWord; Behind, flipHoriz, flipVert: boolean): boolean; begin ForcePlaceOnLand:= TryPlaceOnLand(cpX, cpY, Obj, Frame, true, false, true, behind, flipHoriz, flipVert, LandFlags, Tint) end; @@ -752,12 +752,12 @@ if (outOfMap and ((cpY + y) < LAND_HEIGHT) and ((cpY + y) >= 0) and ((cpX + x) < LAND_WIDTH) and ((cpX + x) >= 0) and - ((not force) and (Land[cpY + y, cpX + x] <> 0))) or + ((not force) and (LandGet(cpY + y, cpX + x) <> 0))) or (not outOfMap and (((cpY + y) <= topY) or ((cpY + y) >= LAND_HEIGHT) or ((cpX + x) <= leftX) or ((cpX + x) >= rightX) or - ((not force) and (Land[cpY + y, cpX + x] <> 0)))) then + ((not force) and (LandGet(cpY + y, cpX + x) <> 0)))) then begin if SDL_MustLock(Image) then SDL_UnlockSurface(Image); @@ -793,28 +793,28 @@ gX:= (cpX + x) div 2; gY:= (cpY + y) div 2; end; - if (not behind) or (Land[cpY + y, cpX + x] and lfLandMask = 0) then + if (not behind) or (LandGet(cpY + y, cpX + x) and lfLandMask = 0) then begin - if (LandFlags and lfBasic <> 0) or - ((LandPixels[gY, gX] and AMask shr AShift > 128) and // This test assumes lfBasic and lfObject differ only graphically + if (LandFlags and lfBasic <> 0) or + ((LandPixelGet(gY, gX) and AMask shr AShift > 128) and // This test assumes lfBasic and lfObject differ only graphically (LandFlags and (lfObject or lfIce) = 0)) then - Land[cpY + y, cpX + x]:= lfBasic or LandFlags + LandSet(cpY + y, cpX + x, lfBasic or LandFlags) else if (LandFlags and lfIce = 0) then - Land[cpY + y, cpX + x]:= lfObject or LandFlags - else Land[cpY + y, cpX + x]:= LandFlags + LandSet(cpY + y, cpX + x, lfObject or LandFlags) + else LandSet(cpY + y, cpX + x, LandFlags) end; - if (not behind) or (LandPixels[gY, gX] = 0) then + if (not behind) or (LandPixelGet(gY, gX) = 0) then begin if tint = $FFFFFFFF then - LandPixels[gY, gX]:= PLongword(@(p^[x * 4]))^ - else + LandPixelSet(gY, gX, PLongword(@(p^[x * 4]))^) + else begin pixel:= PLongword(@(p^[x * 4]))^; - LandPixels[gY, gX]:= + LandPixelSet(gY, gX, ceil((pixel shr RShift and $FF) * ((tint shr 24) / 255)) shl RShift or ceil((pixel shr GShift and $FF) * ((tint shr 16 and $ff) / 255)) shl GShift or ceil((pixel shr BShift and $FF) * ((tint shr 8 and $ff) / 255)) shl BShift or - ceil((pixel shr AShift and $FF) * ((tint and $ff) / 255)) shl AShift; + ceil((pixel shr AShift and $FF) * ((tint and $ff) / 255)) shl AShift); end end end; @@ -847,8 +847,8 @@ for ty:= 0 to height - 1 do for tx:= 0 to width - 1 do begin - LandPixels[ty, tx]:= 0; - Land[Y + ty, X + tx]:= 0; + LandPixelSet(ty, tx, 0); + LandSet(Y + ty, X + tx, 0); end; end; @@ -913,15 +913,15 @@ gX:= (cpX + x) div 2; gY:= (cpY + y) div 2; end; - if (not eraseOnLFMatch or (Land[cpY + y, cpX + x] and LandFlags <> 0)) and + if (not eraseOnLFMatch or (LandGet(cpY + y, cpX + x) and LandFlags <> 0)) and ((PLongword(@(p^[x * 4]))^) and AMask <> 0) then begin if not onlyEraseLF then begin - LandPixels[gY, gX]:= 0; - Land[cpY + y, cpX + x]:= 0 + LandPixelSet(gY, gX, 0); + LandSet(cpY + y, cpX + x, 0) end - else Land[cpY + y, cpX + x]:= Land[cpY + y, cpX + x] and (not LandFlags) + else LandSet(cpY + y, cpX + x, LandGet(cpY + y, cpX + x) and (not LandFlags)) end end; p:= PByteArray(@(p^[Image^.pitch])); @@ -990,7 +990,7 @@ for x:= 0 to Pred(w) do if ((p^[x] and AMask) <> 0) and (((cpY + y) < topY) or ((cpY + y) >= LAND_HEIGHT) or - ((cpX + x) < leftX) or ((cpX + x) > rightX) or (Land[cpY + y, cpX + x] <> 0)) then + ((cpX + x) < leftX) or ((cpX + x) > rightX) or (LandGet(cpY + y, cpX + x) <> 0)) then pt^[x]:= cWhiteColor else (pt^[x]):= cWhiteColor and (not AMask); @@ -1028,8 +1028,8 @@ yy:= Y div 2; end; - pixelsweep:= (Land[Y, X] <= lfAllObjMask) and ((LandPixels[yy, xx] and AMask) <> 0); - if (((Land[Y, X] and lfDamaged) <> 0) and ((Land[Y, X] and lfIndestructible) = 0)) or pixelsweep then + pixelsweep:= (LandGet(Y, X) <= lfAllObjMask) and ((LandPixelGet(yy, xx) and AMask) <> 0); + if (((LandGet(Y, X) and lfDamaged) <> 0) and ((LandGet(Y, X) and lfIndestructible) = 0)) or pixelsweep then begin c:= 0; for i:= -1 to 1 do @@ -1047,27 +1047,27 @@ ny:= Y div 2 + i; nx:= X div 2 + j; if ((ny and (LAND_HEIGHT_MASK div 2)) = 0) and ((nx and (LAND_WIDTH_MASK div 2)) = 0) then - if (LandPixels[ny, nx] and AMASK) <> 0 then + if (LandPixelGet(ny, nx) and AMASK) <> 0 then inc(c); end - else if (LandPixels[ny, nx] and AMASK) <> 0 then + else if (LandPixelGet(ny, nx) and AMASK) <> 0 then inc(c); end - else if Land[ny, nx] > 255 then + else if LandGet(ny, nx) > 255 then inc(c); end end; if c < 4 then // 0-3 neighbours begin - if ((Land[Y, X] and lfBasic) <> 0) and (not disableLandBack) then - LandPixels[yy, xx]:= LandBackPixel(X, Y) + if ((LandGet(Y, X) and lfBasic) <> 0) and (not disableLandBack) then + LandPixelSet(yy, xx, LandBackPixel(X, Y)) else - LandPixels[yy, xx]:= LandPixels[yy, xx] and (not AMASK); + LandPixelSet(yy, xx, LandPixelGet(yy, xx) and (not AMASK)); if not pixelsweep then begin - Land[Y, X]:= 0; + LandSet(Y, X, 0); exit end end; @@ -1083,7 +1083,7 @@ begin // only AA inwards -if (Land[Y, X] and lfDamaged) = 0 then +if (LandGet(Y, X) and lfDamaged) = 0 then exit; // check location @@ -1104,9 +1104,9 @@ for nx:= X-1 to X+1 do for ny:= Y-1 to Y+1 do // only consider undamaged neighbors (also leads to skipping itself) - if (Land[ny, nx] and lfDamaged) = 0 then + if (LandGet(ny, nx) and lfDamaged) = 0 then begin - pixel:= LandPixels[ny, nx]; + pixel:= LandPixelGet(ny, nx); inc(r, (pixel and RMask) shr RShift); inc(g, (pixel and GMask) shr GShift); inc(b, (pixel and BMask) shr BShift); @@ -1132,95 +1132,95 @@ g:= g div 8; b:= b div 8; a:= a div 8; -LandPixels[y,x]:= (r shl RShift) or (g shl GShift) or (b shl BShift) or (a shl AShift); +LandPixelSet(y, x, (r shl RShift) or (g shl GShift) or (b shl BShift) or (a shl AShift)); end; procedure Smooth_oldImpl(X, Y: LongInt); begin // a bit of AA for explosions -if (Land[Y, X] = 0) and (Y > topY + 1) and +if (LandGet(Y, X) = 0) and (Y > topY + 1) and (Y < LAND_HEIGHT-2) and (X > leftX + 1) and (X < rightX - 1) then begin - if ((((Land[y, x-1] and lfDamaged) <> 0) and (((Land[y+1,x] and lfDamaged) <> 0)) or ((Land[y-1,x] and lfDamaged) <> 0)) - or (((Land[y, x+1] and lfDamaged) <> 0) and (((Land[y-1,x] and lfDamaged) <> 0) or ((Land[y+1,x] and lfDamaged) <> 0)))) then + if ((((LandGet(y, x-1) and lfDamaged) <> 0) and (((LandGet(y+1,x) and lfDamaged) <> 0)) or ((LandGet(y-1,x) and lfDamaged) <> 0)) + or (((LandGet(y, x+1) and lfDamaged) <> 0) and (((LandGet(y-1,x) and lfDamaged) <> 0) or ((LandGet(y+1,x) and lfDamaged) <> 0)))) then begin if (cReducedQuality and rqBlurryLand) = 0 then begin - if ((LandPixels[y,x] and AMask) shr AShift) < 10 then - LandPixels[y,x]:= (ExplosionBorderColor and (not AMask)) or (128 shl AShift) + if ((LandPixelGet(y,x) and AMask) shr AShift) < 10 then + LandPixelSet(y,x, (ExplosionBorderColor and (not AMask)) or (128 shl AShift)) else - LandPixels[y,x]:= - (((((LandPixels[y,x] and RMask shr RShift) div 2)+((ExplosionBorderColor and RMask) shr RShift) div 2) and $FF) shl RShift) or - (((((LandPixels[y,x] and GMask shr GShift) div 2)+((ExplosionBorderColor and GMask) shr GShift) div 2) and $FF) shl GShift) or - (((((LandPixels[y,x] and BMask shr BShift) div 2)+((ExplosionBorderColor and BMask) shr BShift) div 2) and $FF) shl BShift) or ($FF shl AShift) + LandPixelSet(y,x, + (((((LandPixelGet(y,x) and RMask shr RShift) div 2)+((ExplosionBorderColor and RMask) shr RShift) div 2) and $FF) shl RShift) or + (((((LandPixelGet(y,x) and GMask shr GShift) div 2)+((ExplosionBorderColor and GMask) shr GShift) div 2) and $FF) shl GShift) or + (((((LandPixelGet(y,x) and BMask shr BShift) div 2)+((ExplosionBorderColor and BMask) shr BShift) div 2) and $FF) shl BShift) or ($FF shl AShift)) end; { - if (Land[y, x-1] = lfObject) then - Land[y,x]:= lfObject - else if (Land[y, x+1] = lfObject) then - Land[y,x]:= lfObject + if (LandGet(y, x-1) = lfObject) then + LandSet(y,x, lfObject) + else if (LandGet(y, x+1) = lfObject) then + LandSet(y,x, lfObject) else - Land[y,x]:= lfBasic; + LandSet(y,x, lfBasic); } end - else if ((((Land[y, x-1] and lfDamaged) <> 0) and ((Land[y+1,x-1] and lfDamaged) <> 0) and ((Land[y+2,x] and lfDamaged) <> 0)) - or (((Land[y, x-1] and lfDamaged) <> 0) and ((Land[y-1,x-1] and lfDamaged) <> 0) and ((Land[y-2,x] and lfDamaged) <> 0)) - or (((Land[y, x+1] and lfDamaged) <> 0) and ((Land[y+1,x+1] and lfDamaged) <> 0) and ((Land[y+2,x] and lfDamaged) <> 0)) - or (((Land[y, x+1] and lfDamaged) <> 0) and ((Land[y-1,x+1] and lfDamaged) <> 0) and ((Land[y-2,x] and lfDamaged) <> 0)) - or (((Land[y+1, x] and lfDamaged) <> 0) and ((Land[y+1,x+1] and lfDamaged) <> 0) and ((Land[y,x+2] and lfDamaged) <> 0)) - or (((Land[y-1, x] and lfDamaged) <> 0) and ((Land[y-1,x+1] and lfDamaged) <> 0) and ((Land[y,x+2] and lfDamaged) <> 0)) - or (((Land[y+1, x] and lfDamaged) <> 0) and ((Land[y+1,x-1] and lfDamaged) <> 0) and ((Land[y,x-2] and lfDamaged) <> 0)) - or (((Land[y-1, x] and lfDamaged) <> 0) and ((Land[y-1,x-1] and lfDamaged) <> 0) and ((Land[y,x-2] and lfDamaged) <> 0))) then + else if ((((LandGet(y, x-1) and lfDamaged) <> 0) and ((LandGet(y+1,x-1) and lfDamaged) <> 0) and ((LandGet(y+2,x) and lfDamaged) <> 0)) + or (((LandGet(y, x-1) and lfDamaged) <> 0) and ((LandGet(y-1,x-1) and lfDamaged) <> 0) and ((LandGet(y-2,x) and lfDamaged) <> 0)) + or (((LandGet(y, x+1) and lfDamaged) <> 0) and ((LandGet(y+1,x+1) and lfDamaged) <> 0) and ((LandGet(y+2,x) and lfDamaged) <> 0)) + or (((LandGet(y, x+1) and lfDamaged) <> 0) and ((LandGet(y-1,x+1) and lfDamaged) <> 0) and ((LandGet(y-2,x) and lfDamaged) <> 0)) + or (((LandGet(y+1, x) and lfDamaged) <> 0) and ((LandGet(y+1,x+1) and lfDamaged) <> 0) and ((LandGet(y,x+2) and lfDamaged) <> 0)) + or (((LandGet(y-1, x) and lfDamaged) <> 0) and ((LandGet(y-1,x+1) and lfDamaged) <> 0) and ((LandGet(y,x+2) and lfDamaged) <> 0)) + or (((LandGet(y+1, x) and lfDamaged) <> 0) and ((LandGet(y+1,x-1) and lfDamaged) <> 0) and ((LandGet(y,x-2) and lfDamaged) <> 0)) + or (((LandGet(y-1, x) and lfDamaged) <> 0) and ((LandGet(y-1,x-1) and lfDamaged) <> 0) and ((LandGet(y,x-2) and lfDamaged) <> 0))) then begin if (cReducedQuality and rqBlurryLand) = 0 then begin - if ((LandPixels[y,x] and AMask) shr AShift) < 10 then - LandPixels[y,x]:= (ExplosionBorderColor and (not AMask)) or (64 shl AShift) + if ((LandPixelGet(y,x) and AMask) shr AShift) < 10 then + LandPixelSet(y,x, (ExplosionBorderColor and (not AMask)) or (64 shl AShift)) else - LandPixels[y,x]:= - (((((LandPixels[y,x] and RMask shr RShift) * 3 div 4)+((ExplosionBorderColor and RMask) shr RShift) div 4) and $FF) shl RShift) or - (((((LandPixels[y,x] and GMask shr GShift) * 3 div 4)+((ExplosionBorderColor and GMask) shr GShift) div 4) and $FF) shl GShift) or - (((((LandPixels[y,x] and BMask shr BShift) * 3 div 4)+((ExplosionBorderColor and BMask) shr BShift) div 4) and $FF) shl BShift) or ($FF shl AShift) + LandPixelSet(y,x, + (((((LandPixelGet(y,x) and RMask shr RShift) * 3 div 4)+((ExplosionBorderColor and RMask) shr RShift) div 4) and $FF) shl RShift) or + (((((LandPixelGet(y,x) and GMask shr GShift) * 3 div 4)+((ExplosionBorderColor and GMask) shr GShift) div 4) and $FF) shl GShift) or + (((((LandPixelGet(y,x) and BMask shr BShift) * 3 div 4)+((ExplosionBorderColor and BMask) shr BShift) div 4) and $FF) shl BShift) or ($FF shl AShift)) end; { - if (Land[y, x-1] = lfObject) then - Land[y, x]:= lfObject - else if (Land[y, x+1] = lfObject) then - Land[y, x]:= lfObject - else if (Land[y+1, x] = lfObject) then - Land[y, x]:= lfObject - else if (Land[y-1, x] = lfObject) then - Land[y, x]:= lfObject - else Land[y,x]:= lfBasic + if (LandGet(y, x-1) = lfObject) then + LandGet(y, x):= lfObject + else if (LandGet(y, x+1) = lfObject) then + LandGet(y, x):= lfObject + else if (LandGet(y+1, x) = lfObject) then + LandGet(y, x):= lfObject + else if (LandGet(y-1, x) = lfObject) then + LandGet(y, x):= lfObject + else LandGet(y,x):= lfBasic } end end -else if ((cReducedQuality and rqBlurryLand) = 0) and ((LandPixels[Y, X] and AMask) = AMask) -and (Land[Y, X] and (lfDamaged or lfBasic) = lfBasic) +else if ((cReducedQuality and rqBlurryLand) = 0) and ((LandPixelGet(Y, X) and AMask) = AMask) +and (LandGet(Y, X) and (lfDamaged or lfBasic) = lfBasic) and (Y > topY + 1) and (Y < LAND_HEIGHT-2) and (X > leftX + 1) and (X < rightX - 1) then begin - if ((((Land[y, x-1] and lfDamaged) <> 0) and (((Land[y+1,x] and lfDamaged) <> 0)) or ((Land[y-1,x] and lfDamaged) <> 0)) - or (((Land[y, x+1] and lfDamaged) <> 0) and (((Land[y-1,x] and lfDamaged) <> 0) or ((Land[y+1,x] and lfDamaged) <> 0)))) then + if ((((LandGet(y, x-1) and lfDamaged) <> 0) and (((LandGet(y+1,x) and lfDamaged) <> 0)) or ((LandGet(y-1,x) and lfDamaged) <> 0)) + or (((LandGet(y, x+1) and lfDamaged) <> 0) and (((LandGet(y-1,x) and lfDamaged) <> 0) or ((LandGet(y+1,x) and lfDamaged) <> 0)))) then begin - LandPixels[y,x]:= - (((((LandPixels[y,x] and RMask shr RShift) div 2)+((ExplosionBorderColor and RMask) shr RShift) div 2) and $FF) shl RShift) or - (((((LandPixels[y,x] and GMask shr GShift) div 2)+((ExplosionBorderColor and GMask) shr GShift) div 2) and $FF) shl GShift) or - (((((LandPixels[y,x] and BMask shr BShift) div 2)+((ExplosionBorderColor and BMask) shr BShift) div 2) and $FF) shl BShift) or ($FF shl AShift) + LandPixelSet(y,x, + (((((LandPixelGet(y,x) and RMask shr RShift) div 2)+((ExplosionBorderColor and RMask) shr RShift) div 2) and $FF) shl RShift) or + (((((LandPixelGet(y,x) and GMask shr GShift) div 2)+((ExplosionBorderColor and GMask) shr GShift) div 2) and $FF) shl GShift) or + (((((LandPixelGet(y,x) and BMask shr BShift) div 2)+((ExplosionBorderColor and BMask) shr BShift) div 2) and $FF) shl BShift) or ($FF shl AShift)) end - else if ((((Land[y, x-1] and lfDamaged) <> 0) and ((Land[y+1,x-1] and lfDamaged) <> 0) and ((Land[y+2,x] and lfDamaged) <> 0)) - or (((Land[y, x-1] and lfDamaged) <> 0) and ((Land[y-1,x-1] and lfDamaged) <> 0) and ((Land[y-2,x] and lfDamaged) <> 0)) - or (((Land[y, x+1] and lfDamaged) <> 0) and ((Land[y+1,x+1] and lfDamaged) <> 0) and ((Land[y+2,x] and lfDamaged) <> 0)) - or (((Land[y, x+1] and lfDamaged) <> 0) and ((Land[y-1,x+1] and lfDamaged) <> 0) and ((Land[y-2,x] and lfDamaged) <> 0)) - or (((Land[y+1, x] and lfDamaged) <> 0) and ((Land[y+1,x+1] and lfDamaged) <> 0) and ((Land[y,x+2] and lfDamaged) <> 0)) - or (((Land[y-1, x] and lfDamaged) <> 0) and ((Land[y-1,x+1] and lfDamaged) <> 0) and ((Land[y,x+2] and lfDamaged) <> 0)) - or (((Land[y+1, x] and lfDamaged) <> 0) and ((Land[y+1,x-1] and lfDamaged) <> 0) and ((Land[y,x-2] and lfDamaged) <> 0)) - or (((Land[y-1, x] and lfDamaged) <> 0) and ((Land[y-1,x-1] and lfDamaged) <> 0) and ((Land[y,x-2] and lfDamaged) <> 0))) then + else if ((((LandGet(y, x-1) and lfDamaged) <> 0) and ((LandGet(y+1,x-1) and lfDamaged) <> 0) and ((LandGet(y+2,x) and lfDamaged) <> 0)) + or (((LandGet(y, x-1) and lfDamaged) <> 0) and ((LandGet(y-1,x-1) and lfDamaged) <> 0) and ((LandGet(y-2,x) and lfDamaged) <> 0)) + or (((LandGet(y, x+1) and lfDamaged) <> 0) and ((LandGet(y+1,x+1) and lfDamaged) <> 0) and ((LandGet(y+2,x) and lfDamaged) <> 0)) + or (((LandGet(y, x+1) and lfDamaged) <> 0) and ((LandGet(y-1,x+1) and lfDamaged) <> 0) and ((LandGet(y-2,x) and lfDamaged) <> 0)) + or (((LandGet(y+1, x) and lfDamaged) <> 0) and ((LandGet(y+1,x+1) and lfDamaged) <> 0) and ((LandGet(y,x+2) and lfDamaged) <> 0)) + or (((LandGet(y-1, x) and lfDamaged) <> 0) and ((LandGet(y-1,x+1) and lfDamaged) <> 0) and ((LandGet(y,x+2) and lfDamaged) <> 0)) + or (((LandGet(y+1, x) and lfDamaged) <> 0) and ((LandGet(y+1,x-1) and lfDamaged) <> 0) and ((LandGet(y,x-2) and lfDamaged) <> 0)) + or (((LandGet(y-1, x) and lfDamaged) <> 0) and ((LandGet(y-1,x-1) and lfDamaged) <> 0) and ((LandGet(y,x-2) and lfDamaged) <> 0))) then begin - LandPixels[y,x]:= - (((((LandPixels[y,x] and RMask shr RShift) * 3 div 4)+((ExplosionBorderColor and RMask) shr RShift) div 4) and $FF) shl RShift) or - (((((LandPixels[y,x] and GMask shr GShift) * 3 div 4)+((ExplosionBorderColor and GMask) shr GShift) div 4) and $FF) shl GShift) or - (((((LandPixels[y,x] and BMask shr BShift) * 3 div 4)+((ExplosionBorderColor and BMask) shr BShift) div 4) and $FF) shl BShift) or ($FF shl AShift) + LandPixelSet(y,x, + (((((LandPixelGet(y,x) and RMask shr RShift) * 3 div 4)+((ExplosionBorderColor and RMask) shr RShift) div 4) and $FF) shl RShift) or + (((((LandPixelGet(y,x) and GMask shr GShift) * 3 div 4)+((ExplosionBorderColor and GMask) shr GShift) div 4) and $FF) shl GShift) or + (((((LandPixelGet(y,x) and BMask shr BShift) * 3 div 4)+((ExplosionBorderColor and BMask) shr BShift) div 4) and $FF) shl BShift) or ($FF shl AShift)) end end end; @@ -1308,12 +1308,12 @@ // Return true if outside of land or not the value tested, used right now for some X/Y movement that does not use normal hedgehog movement in GSHandlers.inc -function CheckLandValue(X, Y: LongInt; LandFlag: Word): boolean; inline; +function CheckLandValue(X, Y: LongInt; LandFlag: Word): boolean; begin - CheckLandValue:= ((X and LAND_WIDTH_MASK <> 0) or (Y and LAND_HEIGHT_MASK <> 0)) or ((Land[Y, X] and LandFlag) = 0) + CheckLandValue:= ((X and LAND_WIDTH_MASK <> 0) or (Y and LAND_HEIGHT_MASK <> 0)) or ((LandGet(Y, X) and LandFlag) = 0) end; -function LandBackPixel(x, y: LongInt): LongWord; inline; +function LandBackPixel(x, y: LongInt): LongWord; var p: PLongWordArray; begin if LandBackSurface = nil then @@ -1382,30 +1382,30 @@ end; if ((x and LAND_WIDTH_MASK) = 0) and ((y and LAND_HEIGHT_MASK) = 0) then - Land[y, x]:= Color; + LandSet(y, x, Color); end end; -function DrawDots(x, y, xx, yy: Longint; Color: Longword): Longword; inline; +function DrawDots(x, y, xx, yy: Longint; Color: Longword): Longword; begin DrawDots:= 0; - if (((x + xx) and LAND_WIDTH_MASK) = 0) and (((y + yy) and LAND_HEIGHT_MASK) = 0) and (Land[y + yy, x + xx] <> Color) then - begin inc(DrawDots); Land[y + yy, x + xx]:= Color; end; - if (((x + xx) and LAND_WIDTH_MASK) = 0) and (((y - yy) and LAND_HEIGHT_MASK) = 0) and (Land[y - yy, x + xx] <> Color) then - begin inc(DrawDots); Land[y - yy, x + xx]:= Color; end; - if (((x - xx) and LAND_WIDTH_MASK) = 0) and (((y + yy) and LAND_HEIGHT_MASK) = 0) and (Land[y + yy, x - xx] <> Color) then - begin inc(DrawDots); Land[y + yy, x - xx]:= Color; end; - if (((x - xx) and LAND_WIDTH_MASK) = 0) and (((y - yy) and LAND_HEIGHT_MASK) = 0) and (Land[y - yy, x - xx] <> Color) then - begin inc(DrawDots); Land[y - yy, x - xx]:= Color; end; - if (((x + yy) and LAND_WIDTH_MASK) = 0) and (((y + xx) and LAND_HEIGHT_MASK) = 0) and (Land[y + xx, x + yy] <> Color) then - begin inc(DrawDots); Land[y + xx, x + yy]:= Color; end; - if (((x + yy) and LAND_WIDTH_MASK) = 0) and (((y - xx) and LAND_HEIGHT_MASK) = 0) and (Land[y - xx, x + yy] <> Color) then - begin inc(DrawDots); Land[y - xx, x + yy]:= Color; end; - if (((x - yy) and LAND_WIDTH_MASK) = 0) and (((y + xx) and LAND_HEIGHT_MASK) = 0) and (Land[y + xx, x - yy] <> Color) then - begin inc(DrawDots); Land[y + xx, x - yy]:= Color; end; - if (((x - yy) and LAND_WIDTH_MASK) = 0) and (((y - xx) and LAND_HEIGHT_MASK) = 0) and (Land[y - xx, x - yy] <> Color) then - begin inc(DrawDots); Land[y - xx, x - yy]:= Color; end; + if (((x + xx) and LAND_WIDTH_MASK) = 0) and (((y + yy) and LAND_HEIGHT_MASK) = 0) and (LandGet(y + yy, x + xx) <> Color) then + begin inc(DrawDots); LandSet(y + yy, x + xx, Color); end; + if (((x + xx) and LAND_WIDTH_MASK) = 0) and (((y - yy) and LAND_HEIGHT_MASK) = 0) and (LandGet(y - yy, x + xx) <> Color) then + begin inc(DrawDots); LandSet(y - yy, x + xx, Color); end; + if (((x - xx) and LAND_WIDTH_MASK) = 0) and (((y + yy) and LAND_HEIGHT_MASK) = 0) and (LandGet(y + yy, x - xx) <> Color) then + begin inc(DrawDots); LandSet(y + yy, x - xx, Color); end; + if (((x - xx) and LAND_WIDTH_MASK) = 0) and (((y - yy) and LAND_HEIGHT_MASK) = 0) and (LandGet(y - yy, x - xx) <> Color) then + begin inc(DrawDots); LandSet(y - yy, x - xx, Color); end; + if (((x + yy) and LAND_WIDTH_MASK) = 0) and (((y + xx) and LAND_HEIGHT_MASK) = 0) and (LandGet(y + xx, x + yy) <> Color) then + begin inc(DrawDots); LandSet(y + xx, x + yy, Color); end; + if (((x + yy) and LAND_WIDTH_MASK) = 0) and (((y - xx) and LAND_HEIGHT_MASK) = 0) and (LandGet(y - xx, x + yy) <> Color) then + begin inc(DrawDots); LandSet(y - xx, x + yy, Color); end; + if (((x - yy) and LAND_WIDTH_MASK) = 0) and (((y + xx) and LAND_HEIGHT_MASK) = 0) and (LandGet(y + xx, x - yy) <> Color) then + begin inc(DrawDots); LandSet(y + xx, x - yy, Color); end; + if (((x - yy) and LAND_WIDTH_MASK) = 0) and (((y - xx) and LAND_HEIGHT_MASK) = 0) and (LandGet(y - xx, x - yy) <> Color) then + begin inc(DrawDots); LandSet(y - xx, x - yy, Color); end; end; function DrawLines(X1, Y1, X2, Y2, XX, YY: LongInt; color: Longword): Longword; @@ -1512,9 +1512,9 @@ xx:= dx - r + x; if (xx = x) and (yy = y) then s[dx + 1]:= 'X' - else if Land[yy, xx] > 255 then + else if LandGet(yy, xx) > 255 then s[dx + 1]:= 'O' - else if Land[yy, xx] > 0 then + else if LandGet(yy, xx) > 0 then s[dx + 1]:= '*' else s[dx + 1]:= '.' diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uLandObjects.pas --- a/hedgewars/uLandObjects.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uLandObjects.pas Tue Aug 22 08:35:46 2023 +0200 @@ -25,18 +25,18 @@ procedure AddObjects(); procedure FreeLandObjects(); procedure LoadThemeConfig; -procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface); inline; -procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface; LandFlags: Word); inline; +procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface); +procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface; LandFlags: Word); procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface; LandFlags: Word; Flip: boolean); procedure BlitOverlayAndGenerateCollisionInfo(cpX, cpY: Longword; Image: PSDL_Surface); procedure BlitImageUsingMask(cpX, cpY: Longword; Image, Mask: PSDL_Surface); procedure AddOnLandObjects(Surface: PSDL_Surface); -procedure SetLand(var LandWord: Word; Pixel: LongWord); inline; +procedure SetLand(y, x: LongInt; Pixel: LongWord); implementation uses uStore, uConsts, uConsole, uRandom, uSound , uTypes, uVariables, uDebug, uUtils - , uPhysFSLayer, uRenderUtils; + , uPhysFSLayer, uRenderUtils, uLandUtils; const MaxRects = 512; MAXOBJECTRECTS = 16; @@ -84,37 +84,37 @@ ThemeObjects: TThemeObjects; SprayObjects: TSprayObjects; -procedure SetLand(var LandWord: Word; Pixel: LongWord); inline; +procedure SetLand(y, x: LongInt; Pixel: LongWord); begin // this an if instead of masking colours to avoid confusing map creators if ((AMask and Pixel) = 0) then - LandWord:= 0 + LandSet(y, x, 0) else if (Pixel and AMask > 0) and (Pixel and RMask > 0) and (Pixel and GMask > 0) and (Pixel and BMask > 0) then // whiteish - LandWord:= lfObject + LandSet(y, x, lfObject) else if (Pixel and AMask > 0) and (Pixel and RMask = 0) and (Pixel and GMask = 0) and (Pixel and BMask = 0) then // blackish begin - LandWord:= lfBasic; + LandSet(y, x, lfBasic); disableLandBack:= false end else if (Pixel and AMask > 0) and (Pixel and RMask > 0) and (Pixel and GMask = 0) and (Pixel and BMask = 0) then // reddish - LandWord:= lfIndestructible + LandSet(y, x, lfIndestructible) else if (Pixel and AMask > 0) and (Pixel and RMask = 0) and (Pixel and GMask = 0) and (Pixel and BMask > 0) then // blueish - LandWord:= lfObject or lfIce + LandSet(y, x, lfObject or lfIce) else if (Pixel and AMask > 0) and (Pixel and RMask = 0) and (Pixel and GMask > 0) and (Pixel and BMask = 0) then // greenish - LandWord:= lfObject or lfBouncy + LandSet(y, x, lfObject or lfBouncy) end; -procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface); inline; +procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface); begin BlitImageAndGenerateCollisionInfo(cpX, cpY, Width, Image, 0, false); end; -procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface; LandFlags: Word); inline; +procedure BlitImageAndGenerateCollisionInfo(cpX, cpY, Width: Longword; Image: PSDL_Surface; LandFlags: Word); begin BlitImageAndGenerateCollisionInfo(cpX, cpY, Width, Image, LandFlags, false); end; -function LerpByte(src, dst: Byte; l: LongWord): LongWord; inline; +function LerpByte(src, dst: Byte; l: LongWord): LongWord; begin LerpByte:= ((255 - l) * src + l * dst) div 255; end; @@ -153,9 +153,9 @@ color:= p^[x]; if (cReducedQuality and rqBlurryLand) = 0 then - pLandColor:= @LandPixels[cpY + y, cpX + x] + pLandColor:= @(LandPixelRow(cpY + y)^[cpX + x]) else - pLandColor:= @LandPixels[(cpY + y) div 2, (cpX + x) div 2]; + pLandColor:= @(LandPixelRow((cpY + y) div 2)^[(cpX + x) div 2]); landColor:= pLandColor^; alpha:= (landColor and AMask) shr AShift; @@ -173,8 +173,8 @@ end; - if ((color and AMask) <> 0) and (Land[cpY + y, cpX + x] <= lfAllObjMask) then - Land[cpY + y, cpX + x]:= lfObject or LandFlags + if ((color and AMask) <> 0) and (LandGet(cpY + y, cpX + x) <= lfAllObjMask) then + LandSet(cpY + y, cpX + x, lfObject or LandFlags) end; p:= PLongwordArray(@(p^[Image^.pitch shr 2])) end; @@ -208,9 +208,9 @@ if (color and AMask) <> 0 then begin if (cReducedQuality and rqBlurryLand) = 0 then - pLandColor:= @LandPixels[cpY + y, cpX + x] + pLandColor:= @(LandPixelRow(cpY + y)^[cpX + x]) else - pLandColor:= @LandPixels[(cpY + y) div 2, (cpX + x) div 2]; + pLandColor:= @(LandPixelRow((cpY + y) div 2)^[(cpX + x) div 2]); alpha:= (color and AMask) shr AShift; if ((alpha <> $FF) and ((pLandColor^) <> 0)) then @@ -224,8 +224,8 @@ end; pLandColor^:= color; - if Land[cpY + y, cpX + x] <= lfAllObjMask then - Land[cpY + y, cpX + x]:= lfObject + if LandGet(cpY + y, cpX + x) <= lfAllObjMask then + LandSet(cpY + y, cpX + x, lfObject) end; end; p:= PLongwordArray(@(p^[Image^.pitch shr 2])) @@ -263,9 +263,9 @@ color:= p^[x]; if (cReducedQuality and rqBlurryLand) = 0 then - pLandColor:= @LandPixels[cpY + y, cpX + x] + pLandColor:= @(LandPixelRow(cpY + y)^[cpX + x]) else - pLandColor:= @LandPixels[(cpY + y) div 2, (cpX + x) div 2]; + pLandColor:= @(LandPixelRow((cpY + y) div 2)^[(cpX + x) div 2]); landColor:= pLandColor^; alpha:= (landColor and AMask) shr AShift; @@ -282,8 +282,8 @@ or (LerpByte(alpha, 255, (color and AMask) shr AShift) shl AShift); end; - if (Land[cpY + y, cpX + x] <= lfAllObjMask) or (Land[cpY + y, cpX + x] and lfObject <> 0) then - SetLand(Land[cpY + y, cpX + x], mp^[x]); + if (LandGet(cpY + y, cpX + x) <= lfAllObjMask) or (LandGet(cpY + y, cpX + x) and lfObject <> 0) then + SetLand(cpY + y, cpX + x, mp^[x]); end; p:= PLongwordArray(@(p^[Image^.pitch shr 2])); @@ -341,7 +341,7 @@ begin lRes:= 0; for i:= y to Pred(y + h) do - if Land[i, x] <> 0 then + if LandGet(i, x) <> 0 then inc(lRes); CountNonZeroz:= lRes; end; @@ -425,8 +425,8 @@ begin bRes:= ((rect.y and LAND_HEIGHT_MASK) = 0) and ((by and LAND_HEIGHT_MASK) = 0) and ((tmpx and LAND_WIDTH_MASK) = 0) and ((tmpx2 and LAND_WIDTH_MASK) = 0) - and (Land[rect.y, tmpx] = Color) and (Land[by, tmpx] = Color) - and (Land[rect.y, tmpx2] = Color) and (Land[by, tmpx2] = Color); + and (LandGet(rect.y, tmpx) = Color) and (LandGet(by, tmpx) = Color) + and (LandGet(rect.y, tmpx2) = Color) and (LandGet(by, tmpx2) = Color); inc(tmpx); dec(tmpx2) end; @@ -436,8 +436,8 @@ begin bRes:= ((tmpy and LAND_HEIGHT_MASK) = 0) and ((tmpy2 and LAND_HEIGHT_MASK) = 0) and ((rect.x and LAND_WIDTH_MASK) = 0) and ((bx and LAND_WIDTH_MASK) = 0) - and (Land[tmpy, rect.x] = Color) and (Land[tmpy, bx] = Color) - and (Land[tmpy2, rect.x] = Color) and (Land[tmpy2, bx] = Color); + and (LandGet(tmpy, rect.x) = Color) and (LandGet(tmpy, bx) = Color) + and (LandGet(tmpy2, rect.x) = Color) and (LandGet(tmpy2, bx) = Color); inc(tmpy); dec(tmpy2) end; @@ -459,7 +459,7 @@ begin for tmpx := rect.x to bx do begin - if (((Land[rect.y, tmpx] and LandType) or (Land[by, tmpx] and LandType)) <> 0) then + if (((LandGet(rect.y, tmpx) and LandType) or (LandGet(by, tmpx) and LandType)) <> 0) then begin CheckLandAny := true; exit; @@ -467,7 +467,7 @@ end; for tmpy := rect.y to by do begin - if (((Land[tmpy, rect.x] and LandType) or (Land[tmpy, bx] and LandType)) <> 0) then + if (((LandGet(tmpy, rect.x) and LandType) or (LandGet(tmpy, bx) and LandType)) <> 0) then begin CheckLandAny := true; exit; diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uLandOutline.pas --- a/hedgewars/uLandOutline.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uLandOutline.pas Tue Aug 22 08:35:46 2023 +0200 @@ -10,12 +10,11 @@ end; procedure DrawEdge(var pa: TPixAr; value: Word); -procedure FillLand(x, y: LongInt; border, value: Word); procedure BezierizeEdge(var pa: TPixAr; Delta: hwFloat); implementation -uses uLandGraphics, uDebug, uVariables, uLandTemplates; +uses uLandGraphics, uDebug, uVariables, uLandTemplates, uLandUtils; var Stack: record @@ -54,41 +53,6 @@ end end; -procedure FillLand(x, y: LongInt; border, value: Word); -var xl, xr, dir: LongInt; -begin - Stack.Count:= 0; - xl:= x - 1; - xr:= x; - Push(xl, xr, y, -1); - Push(xl, xr, y, 1); - dir:= 0; - while Stack.Count > 0 do - begin - Pop(xl, xr, y, dir); - while (xl > 0) and (Land[y, xl] <> border) and (Land[y, xl] <> value) do - dec(xl); - while (xr < LAND_WIDTH - 1) and (Land[y, xr] <> border) and (Land[y, xr] <> value) do - inc(xr); - while (xl < xr) do - begin - while (xl <= xr) and ((Land[y, xl] = border) or (Land[y, xl] = value)) do - inc(xl); - x:= xl; - while (xl <= xr) and (Land[y, xl] <> border) and (Land[y, xl] <> value) do - begin - Land[y, xl]:= value; - inc(xl) - end; - if x < xl then - begin - Push(x, Pred(xl), y, dir); - Push(x, Pred(xl), y,-dir); - end; - end; - end; -end; - procedure DrawEdge(var pa: TPixAr; value: Word); var i: LongInt; begin diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uLandTexture.pas --- a/hedgewars/uLandTexture.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uLandTexture.pas Tue Aug 22 08:35:46 2023 +0200 @@ -30,7 +30,7 @@ procedure SetLandTexture; implementation -uses uConsts, GLunit, uTypes, uVariables, uTextures, uDebug, uRender, uUtils; +uses uConsts, GLunit, uTypes, uVariables, uTextures, uDebug, uRender, uUtils, uLandUtils; const TEXSIZE = 128; // in avoid tile borders stretch the blurry texture by 1 pixel more @@ -50,7 +50,7 @@ var ty: Longword; begin for ty:= 0 to TEXSIZE - 1 do - Move(LandPixels[y * TEXSIZE + ty, x * TEXSIZE], tmpPixels[ty, 0], sizeof(Longword) * TEXSIZE); + Move(LandPixelRow(y * TEXSIZE + ty)^[x * TEXSIZE], tmpPixels[ty, 0], sizeof(Longword) * TEXSIZE); Pixels:= @tmpPixels end; @@ -60,7 +60,7 @@ begin for ty:= 0 to TEXSIZE - 1 do for tx:= 0 to TEXSIZE - 1 do - tmpPixels[ty, tx]:= Land[y * TEXSIZE + ty, x * TEXSIZE + tx] or AMask; + tmpPixels[ty, tx]:= LandGet(y * TEXSIZE + ty, x * TEXSIZE + tx) or AMask; Pixels2:= @tmpPixels end; @@ -129,14 +129,14 @@ // first check edges while isEmpty and (ty < TEXSIZE) do begin - isEmpty:= LandPixels[ly + ty, lx] and AMask = 0; - if isEmpty then isEmpty:= LandPixels[ly + ty, Pred(lx + TEXSIZE)] and AMask = 0; + isEmpty:= LandPixelGet(ly + ty, lx) and AMask = 0; + if isEmpty then isEmpty:= LandPixelGet(ly + ty, Pred(lx + TEXSIZE)) and AMask = 0; inc(ty) end; while isEmpty and (tx < TEXSIZE-1) do begin - isEmpty:= LandPixels[ly, lx + tx] and AMask = 0; - if isEmpty then isEmpty:= LandPixels[Pred(ly + TEXSIZE), lx + tx] and AMask = 0; + isEmpty:= LandPixelGet(ly, lx + tx) and AMask = 0; + if isEmpty then isEmpty:= LandPixelGet(Pred(ly + TEXSIZE), lx + tx) and AMask = 0; inc(tx) end; // then search every other remaining. does this sort of stuff defeat compiler opts? @@ -146,7 +146,7 @@ tx:= 2; while isEmpty and (tx < TEXSIZE-1) do begin - isEmpty:= LandPixels[ly + ty, lx + tx] and AMask = 0; + isEmpty:= LandPixelGet(ly + ty, lx + tx) and AMask = 0; inc(tx,2) end; inc(ty,2); @@ -158,7 +158,7 @@ tx:= 1; while isEmpty and (tx < TEXSIZE-1) do begin - isEmpty:= LandPixels[ly + ty, lx + tx] and AMask = 0; + isEmpty:= LandPixelGet(ly + ty, lx + tx) and AMask = 0; inc(tx,2) end; inc(ty,2); diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uLandUtils.pas --- a/hedgewars/uLandUtils.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uLandUtils.pas Tue Aug 22 08:35:46 2023 +0200 @@ -1,12 +1,105 @@ unit uLandUtils; interface +uses SDLh; +procedure GenerateTemplatedLand(featureSize: Longword; seed, templateType, dataPath: shortstring); procedure ResizeLand(width, height: LongWord); +procedure DisposeLand(); procedure InitWorldEdges(); +function LandGet(y, x: LongInt): Word; +procedure LandSet(y, x: LongInt; value: Word); +function LandRow(row: LongInt): PWordArray; + +procedure FillLand(x, y: LongInt; border, value: Word); + +function LandPixelGet(y, x: LongInt): Longword; +procedure LandPixelSet(y, x: LongInt; value: Longword); +function LandPixelRow(row: LongInt): PLongwordArray; + implementation uses uUtils, uConsts, uVariables, uTypes; +const LibFutureName = 'hwengine_future'; + +function create_empty_game_field(width, height: Longword): pointer; cdecl; external LibFutureName; +procedure get_game_field_parameters(game_field: pointer; var width: LongInt; var height: LongInt; var play_width: LongInt; var play_height: LongInt); cdecl; external LibFutureName; +procedure dispose_game_field(game_field: pointer); cdecl; external LibFutureName; + +function land_get(game_field: pointer; x, y: LongInt): Word; cdecl; external LibFutureName; +procedure land_set(game_field: pointer; x, y: LongInt; value: Word); cdecl; external LibFutureName; +function land_row(game_field: pointer; row: LongInt): PWordArray; cdecl; external LibFutureName; +procedure land_fill(game_field: pointer; x, y: LongInt; border, fill: Word); cdecl; external LibFutureName; + +function land_pixel_get(game_field: pointer; x, y: LongInt): Longword; cdecl; external LibFutureName; +procedure land_pixel_set(game_field: pointer; x, y: LongInt; value: Longword); cdecl; external LibFutureName; +function land_pixel_row(game_field: pointer; row: LongInt): PLongwordArray; cdecl; external LibFutureName; + +function generate_templated_game_field(feature_size: Longword; seed, template_type, data_path: PChar): pointer; cdecl; external LibFutureName; +procedure apply_theme(game_field: pointer; data_path, theme_name: PChar); cdecl; external LibFutureName; + +var gameField: pointer; + +function LandGet(y, x: LongInt): Word; +begin + LandGet:= land_get(gameField, x, y) +end; + +procedure LandSet(y, x: LongInt; value: Word); +begin + land_set(gameField, x, y, value) +end; + +function LandRow(row: LongInt): PWordArray; +begin + LandRow:= land_row(gameField, row) +end; + +procedure FillLand(x, y: LongInt; border, value: Word); +begin + land_fill(gameField, x, y, border, value) +end; + +function LandPixelGet(y, x: LongInt): Longword; +begin + LandPixelGet:= land_pixel_get(gameField, x, y) +end; + +procedure LandPixelSet(y, x: LongInt; value: Longword); +begin + land_pixel_set(gameField, x, y, value) +end; + +function LandPixelRow(row: LongInt): PLongwordArray; +begin + LandPixelRow:= land_pixel_row(gameField, row) +end; + +procedure GenerateTemplatedLand(featureSize: Longword; seed, templateType, dataPath: shortstring); +begin + seed[byte(seed[0]) + 1]:= #0; + templateType[byte(templateType[0]) + 1]:= #0; + + gameField:= generate_templated_game_field(featureSize, @seed[1], @templateType[1], Str2PChar(dataPath)); + get_game_field_parameters(gameField, LAND_WIDTH, LAND_HEIGHT, playWidth, playHeight); + + MaxHedgehogs:= 32; + hasGirders:= true; + + leftX:= (LAND_WIDTH - playWidth) div 2; + rightX:= Pred(leftX + playWidth); + topY:= LAND_HEIGHT - playHeight; + cWaterLine:= LAND_HEIGHT; + + // let's assume those are powers of two + LAND_WIDTH_MASK:= not(LAND_WIDTH-1); + LAND_HEIGHT_MASK:= not(LAND_HEIGHT-1); + + SetLength(LandDirty, (LAND_HEIGHT div 32), (LAND_WIDTH div 32)); + + initScreenSpaceVars(); +end; + procedure ResizeLand(width, height: LongWord); var potW, potH: LongInt; begin @@ -19,12 +112,8 @@ LAND_WIDTH_MASK:= not(LAND_WIDTH-1); LAND_HEIGHT_MASK:= not(LAND_HEIGHT-1); cWaterLine:= LAND_HEIGHT; - if (cReducedQuality and rqBlurryLand) = 0 then - SetLength(LandPixels, LAND_HEIGHT, LAND_WIDTH) - else - SetLength(LandPixels, LAND_HEIGHT div 2, LAND_WIDTH div 2); - SetLength(Land, LAND_HEIGHT, LAND_WIDTH); + gameField:= create_empty_game_field(LAND_WIDTH, LAND_HEIGHT); SetLength(LandDirty, (LAND_HEIGHT div 32), (LAND_WIDTH div 32)); // 0.5 is already approaching on unplayable if (width div 4096 >= 2) or (height div 2048 >= 2) then cMaxZoomLevel:= cMaxZoomLevel/2; @@ -33,6 +122,11 @@ initScreenSpaceVars(); end; +procedure DisposeLand(); +begin + dispose_game_field(gameField) +end; + procedure InitWorldEdges(); var cy, cx, lx, ly: LongInt; found: boolean; @@ -70,7 +164,7 @@ for cx:= 0 to lx do begin for cy:= ly downto 0 do - if Land[cy, cx] <> 0 then + if LandGet(cy, cx) <> 0 then begin leftX:= max(0, cx - cWorldEdgeDist); // break out of both loops @@ -85,7 +179,7 @@ for cx:= lx downto 0 do begin for cy:= ly downto 0 do - if Land[cy, cx] <> 0 then + if LandGet(cy, cx) <> 0 then begin rightX:= min(lx, cx + cWorldEdgeDist); // break out of both loops diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uMisc.pas --- a/hedgewars/uMisc.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uMisc.pas Tue Aug 22 08:35:46 2023 +0200 @@ -29,10 +29,10 @@ function doSurfaceConversion(tmpsurf: PSDL_Surface): PSDL_Surface; function MakeScreenshot(filename: shortstring; k: LongInt; dump: LongWord): boolean; function GetTeamStatString(p: PTeam): shortstring; -function SDL_RectMake(x, y, width, height: LongInt): TSDL_Rect; inline; +function SDL_RectMake(x, y, width, height: LongInt): TSDL_Rect; implementation -uses uVariables, uUtils +uses uVariables, uUtils, uLandUtils {$IFDEF PNG_SCREENSHOTS}, PNGh, png {$ENDIF}; type PScreenshot = ^TScreenshot; @@ -288,18 +288,18 @@ for y:= 0 to LAND_HEIGHT-1 do for x:= 0 to LAND_WIDTH-1 do if dump = 2 then - PLongWordArray(p)^[y*LAND_WIDTH+x]:= LandPixels[LAND_HEIGHT-1-y, x] + PLongWordArray(p)^[y*LAND_WIDTH+x]:= LandPixelGet(LAND_HEIGHT-1-y, x) else begin - if Land[LAND_HEIGHT-1-y, x] and lfIndestructible = lfIndestructible then + if LandGet(LAND_HEIGHT-1-y, x) and lfIndestructible = lfIndestructible then PLongWordArray(p)^[y*LAND_WIDTH+x]:= (AMask or RMask) - else if Land[LAND_HEIGHT-1-y, x] and lfIce = lfIce then + else if LandGet(LAND_HEIGHT-1-y, x) and lfIce = lfIce then PLongWordArray(p)^[y*LAND_WIDTH+x]:= (AMask or BMask) - else if Land[LAND_HEIGHT-1-y, x] and lfBouncy = lfBouncy then + else if LandGet(LAND_HEIGHT-1-y, x) and lfBouncy = lfBouncy then PLongWordArray(p)^[y*LAND_WIDTH+x]:= (AMask or GMask) - else if Land[LAND_HEIGHT-1-y, x] and lfObject = lfObject then + else if LandGet(LAND_HEIGHT-1-y, x) and lfObject = lfObject then PLongWordArray(p)^[y*LAND_WIDTH+x]:= $FFFFFFFF - else if Land[LAND_HEIGHT-1-y, x] and lfBasic = lfBasic then + else if LandGet(LAND_HEIGHT-1-y, x) and lfBasic = lfBasic then PLongWordArray(p)^[y*LAND_WIDTH+x]:= AMask else PLongWordArray(p)^[y*LAND_WIDTH+x]:= 0 @@ -353,7 +353,7 @@ end; end; -function SDL_RectMake(x, y, width, height: LongInt): TSDL_Rect; inline; +function SDL_RectMake(x, y, width, height: LongInt): TSDL_Rect; begin SDL_RectMake.x:= x; SDL_RectMake.y:= y; diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uRandom.pas --- a/hedgewars/uRandom.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uRandom.pas Tue Aug 22 08:35:46 2023 +0200 @@ -32,8 +32,8 @@ procedure SetRandomSeed(Seed: shortstring; dropAdditionalPart: boolean); // Sets the seed that should be used for generating pseudo-random values. function GetRandomf: hwFloat; // Returns a pseudo-random hwFloat. -function GetRandom(m: LongWord): LongWord; inline; // Returns a positive pseudo-random integer smaller than m. -procedure AddRandomness(r: LongWord); inline; +function GetRandom(m: LongWord): LongWord; // Returns a positive pseudo-random integer smaller than m. +procedure AddRandomness(r: LongWord); function rndSign(num: hwFloat): hwFloat; // Returns num with a random chance of having a inverted sign. @@ -42,13 +42,13 @@ var cirbuf: array[0..63] of Longword; n: byte; -procedure AddRandomness(r: LongWord); inline; +procedure AddRandomness(r: LongWord); begin n:= (n + 1) and $3F; cirbuf[n]:= cirbuf[n] xor r; end; -function GetNext: Longword; inline; +function GetNext: Longword; begin n:= (n + 1) and $3F; cirbuf[n]:= @@ -90,7 +90,7 @@ GetRandomf.QWordValue:= GetNext end; -function GetRandom(m: LongWord): LongWord; inline; +function GetRandom(m: LongWord): LongWord; begin GetNext; GetRandom:= GetNext mod m diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uRender.pas --- a/hedgewars/uRender.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uRender.pas Tue Aug 22 08:35:46 2023 +0200 @@ -30,18 +30,18 @@ procedure DrawSprite (Sprite: TSprite; X, Y, Frame: LongInt); procedure DrawSprite (Sprite: TSprite; X, Y, FrameX, FrameY: LongInt); -procedure DrawSpriteFromRect (Sprite: TSprite; r: TSDL_Rect; X, Y, Height, Position: LongInt); inline; +procedure DrawSpriteFromRect (Sprite: TSprite; r: TSDL_Rect; X, Y, Height, Position: LongInt); procedure DrawSpriteClipped (Sprite: TSprite; X, Y, TopY, RightX, BottomY, LeftX: LongInt); procedure DrawSpriteRotated (Sprite: TSprite; X, Y, Dir: LongInt; Angle: real); procedure DrawSpriteRotatedF (Sprite: TSprite; X, Y, Frame, Dir: LongInt; Angle: real); procedure DrawSpriteRotatedFReal(Sprite: TSprite; X, Y: Real; Frame, Dir: LongInt; Angle: real); procedure DrawSpritePivotedF(Sprite: TSprite; X, Y, Frame, Dir, PivotX, PivotY: LongInt; Angle: real); -procedure DrawTexture (X, Y: LongInt; Texture: PTexture); inline; +procedure DrawTexture (X, Y: LongInt; Texture: PTexture); procedure DrawTexture (X, Y: LongInt; Texture: PTexture; Scale: GLfloat); procedure DrawTexture2 (X, Y: LongInt; Texture: PTexture; Scale, Overlap: GLfloat); -procedure DrawTextureFromRect (X, Y: LongInt; r: PSDL_Rect; SourceTexture: PTexture); inline; -procedure DrawTextureFromRect (X, Y, W, H: LongInt; r: PSDL_Rect; SourceTexture: PTexture); inline; +procedure DrawTextureFromRect (X, Y: LongInt; r: PSDL_Rect; SourceTexture: PTexture); +procedure DrawTextureFromRect (X, Y, W, H: LongInt; r: PSDL_Rect; SourceTexture: PTexture); procedure DrawTextureFromRectDir(X, Y, W, H: LongInt; r: PSDL_Rect; SourceTexture: PTexture; Dir: LongInt); procedure DrawTextureCentered (X, Top: LongInt; Source: PTexture); procedure DrawTextureF (Texture: PTexture; Scale: GLfloat; X, Y, Frame, Dir, w, h: LongInt); @@ -53,9 +53,9 @@ procedure DrawCircle (X, Y, Radius, Width: LongInt; color: LongWord); procedure DrawCircleFilled (X, Y, Radius: LongInt; r, g, b, a: Byte); -procedure DrawLine (X0, Y0, X1, Y1, Width: Single; color: LongWord); inline; +procedure DrawLine (X0, Y0, X1, Y1, Width: Single; color: LongWord); procedure DrawLine (X0, Y0, X1, Y1, Width: Single; r, g, b, a: Byte); -procedure DrawLineWrapped (X0, Y0, X1, Y1, Width: Single; goesLeft: boolean; Wraps: LongWord; color: LongWord); inline; +procedure DrawLineWrapped (X0, Y0, X1, Y1, Width: Single; goesLeft: boolean; Wraps: LongWord; color: LongWord); procedure DrawLineWrapped (X0, Y0, X1, Y1, Width: Single; goesLeft: boolean; Wraps: LongWord; r, g, b, a: Byte); procedure DrawLineOnScreen (X0, Y0, X1, Y1, Width: Single; r, g, b, a: Byte); procedure DrawRect (rect: TSDL_Rect; r, g, b, a: Byte; Fill: boolean); @@ -70,19 +70,19 @@ {$ENDIF} procedure RenderSetClearColor (r, g, b, a: real); procedure Tint (r, g, b, a: Byte); -procedure Tint (c: Longword); inline; -procedure untint(); inline; -procedure setTintAdd (enable: boolean); inline; +procedure Tint (c: Longword); +procedure untint(); +procedure setTintAdd (enable: boolean); // call this to finish the rendering of current frame procedure FinishRender(); -function isAreaOffscreen(X, Y, Width, Height: LongInt): boolean; inline; -function isCircleOffscreen(X, Y, RadiusSquared: LongInt): boolean; inline; +function isAreaOffscreen(X, Y, Width, Height: LongInt): boolean; +function isCircleOffscreen(X, Y, RadiusSquared: LongInt): boolean; // 0 => not offscreen, <0 => left/top of screen >0 => right/below of screen -function isDxAreaOffscreen(X, Width: LongInt): LongInt; inline; -function isDyAreaOffscreen(Y, Height: LongInt): LongInt; inline; +function isDxAreaOffscreen(X, Width: LongInt): LongInt; +function isDyAreaOffscreen(Y, Height: LongInt): LongInt; procedure SetScale(f: GLfloat); procedure UpdateViewLimits(); @@ -97,15 +97,15 @@ procedure EnableTexture(enable:Boolean); -procedure SetTexCoordPointer(p: Pointer;n: Integer); inline; -procedure SetVertexPointer(p: Pointer;n: Integer); inline; -procedure SetColorPointer(p: Pointer;n: Integer); inline; +procedure SetTexCoordPointer(p: Pointer;n: Integer); +procedure SetVertexPointer(p: Pointer;n: Integer); +procedure SetColorPointer(p: Pointer;n: Integer); -procedure UpdateModelviewProjection(); inline; +procedure UpdateModelviewProjection(); -procedure openglPushMatrix (); inline; -procedure openglPopMatrix (); inline; -procedure openglTranslatef (X, Y, Z: GLfloat); inline; +procedure openglPushMatrix (); +procedure openglPopMatrix (); +procedure openglTranslatef (X, Y, Z: GLfloat); implementation @@ -147,12 +147,12 @@ procedure DeleteFramebuffer(var frame, depth, tex: GLuint); forward; {$ENDIF} -function isAreaOffscreen(X, Y, Width, Height: LongInt): boolean; inline; +function isAreaOffscreen(X, Y, Width, Height: LongInt): boolean; begin isAreaOffscreen:= (isDxAreaOffscreen(X, Width) <> 0) or (isDyAreaOffscreen(Y, Height) <> 0); end; -function isCircleOffscreen(X, Y, RadiusSquared: LongInt): boolean; inline; +function isCircleOffscreen(X, Y, RadiusSquared: LongInt): boolean; var dRightX, dBottomY, dLeftX, dTopY: LongInt; begin dRightX:= (X - ViewRightX); @@ -166,14 +166,14 @@ ((dTopY > 0) and (sqr(dTopY) > RadiusSquared)) end; -function isDxAreaOffscreen(X, Width: LongInt): LongInt; inline; +function isDxAreaOffscreen(X, Width: LongInt): LongInt; begin if X > ViewRightX then exit(1); if X + Width < ViewLeftX then exit(-1); isDxAreaOffscreen:= 0; end; -function isDyAreaOffscreen(Y, Height: LongInt): LongInt; inline; +function isDyAreaOffscreen(Y, Height: LongInt): LongInt; begin if Y > ViewBottomY then exit(1); if Y + Height < ViewTopY then exit(-1); @@ -658,7 +658,7 @@ // disable/lower perspective correction (will not need it anyway) end; -procedure openglLoadIdentity(); inline; +procedure openglLoadIdentity(); begin {$IFDEF GL2} hglLoadIdentity(); @@ -667,7 +667,7 @@ {$ENDIF} end; -procedure openglTranslProjMatrix(X, Y, Z: GLfloat); inline; +procedure openglTranslProjMatrix(X, Y, Z: GLfloat); begin {$IFDEF GL2} hglMatrixMode(MATRIX_PROJECTION); @@ -680,7 +680,7 @@ {$ENDIF} end; -procedure openglPushMatrix(); inline; +procedure openglPushMatrix(); begin {$IFDEF GL2} hglPushMatrix(); @@ -689,7 +689,7 @@ {$ENDIF} end; -procedure openglPopMatrix(); inline; +procedure openglPopMatrix(); begin {$IFDEF GL2} hglPopMatrix(); @@ -698,7 +698,7 @@ {$ENDIF} end; -procedure openglTranslatef(X, Y, Z: GLfloat); inline; +procedure openglTranslatef(X, Y, Z: GLfloat); begin {$IFDEF GL2} hglTranslatef(X, Y, Z); @@ -707,7 +707,7 @@ {$ENDIF} end; -procedure openglScalef(ScaleX, ScaleY, ScaleZ: GLfloat); inline; +procedure openglScalef(ScaleX, ScaleY, ScaleZ: GLfloat); begin {$IFDEF GL2} hglScalef(ScaleX, ScaleY, ScaleZ); @@ -716,7 +716,7 @@ {$ENDIF} end; -procedure openglRotatef(RotX, RotY, RotZ: GLfloat; dir: LongInt); inline; +procedure openglRotatef(RotX, RotY, RotZ: GLfloat; dir: LongInt); { workaround for pascal bug https://bugs.freepascal.org/view.php?id=27222 } var tmpdir: LongInt; begin @@ -728,7 +728,7 @@ {$ENDIF} end; -procedure openglUseColorOnly(b :boolean); inline; +procedure openglUseColorOnly(b :boolean); begin if b then begin @@ -755,7 +755,7 @@ EnableTexture(not b); end; -procedure UpdateModelviewProjection(); inline; +procedure UpdateModelviewProjection(); {$IFDEF GL2} var mvp: TMatrix4x4f; @@ -770,7 +770,7 @@ {$ENDIF} end; -procedure SetTexCoordPointer(p: Pointer; n: Integer); inline; +procedure SetTexCoordPointer(p: Pointer; n: Integer); begin {$IFDEF GL2} glBindBuffer(GL_ARRAY_BUFFER, tBuffer); @@ -786,7 +786,7 @@ {$ENDIF} end; -procedure SetVertexPointer(p: Pointer; n: Integer); inline; +procedure SetVertexPointer(p: Pointer; n: Integer); begin {$IFDEF GL2} glBindBuffer(GL_ARRAY_BUFFER, vBuffer); @@ -802,7 +802,7 @@ {$ENDIF} end; -procedure SetColorPointer(p: Pointer; n: Integer); inline; +procedure SetColorPointer(p: Pointer; n: Integer); begin {$IFDEF GL2} glBindBuffer(GL_ARRAY_BUFFER, cBuffer); @@ -887,19 +887,19 @@ UpdateModelviewProjection; end; -procedure DrawSpriteFromRect(Sprite: TSprite; r: TSDL_Rect; X, Y, Height, Position: LongInt); inline; +procedure DrawSpriteFromRect(Sprite: TSprite; r: TSDL_Rect; X, Y, Height, Position: LongInt); begin r.y:= r.y + Height * Position; r.h:= Height; DrawTextureFromRect(X, Y, @r, SpritesData[Sprite].Texture) end; -procedure DrawTextureFromRect(X, Y: LongInt; r: PSDL_Rect; SourceTexture: PTexture); inline; +procedure DrawTextureFromRect(X, Y: LongInt; r: PSDL_Rect; SourceTexture: PTexture); begin DrawTextureFromRectDir(X, Y, r^.w, r^.h, r, SourceTexture, 1) end; -procedure DrawTextureFromRect(X, Y, W, H: LongInt; r: PSDL_Rect; SourceTexture: PTexture); inline; +procedure DrawTextureFromRect(X, Y, W, H: LongInt; r: PSDL_Rect; SourceTexture: PTexture); begin DrawTextureFromRectDir(X, Y, W, H, r, SourceTexture, 1) end; @@ -967,7 +967,7 @@ end; -procedure DrawTexture(X, Y: LongInt; Texture: PTexture); inline; +procedure DrawTexture(X, Y: LongInt; Texture: PTexture); begin DrawTexture(X, Y, Texture, 1.0); end; @@ -1375,7 +1375,7 @@ end; // Same as below, but with color as LongWord -procedure DrawLine(X0, Y0, X1, Y1, Width: Single; color: LongWord); inline; +procedure DrawLine(X0, Y0, X1, Y1, Width: Single; color: LongWord); begin DrawLine(X0, Y0, X1, Y1, Width, (color shr 24) and $FF, (color shr 16) and $FF, (color shr 8) and $FF, color and $FF) end; @@ -1400,7 +1400,7 @@ end; // Same as below, but with color as a longword -procedure DrawLineWrapped(X0, Y0, X1, Y1, Width: Single; goesLeft: boolean; Wraps: LongWord; color: LongWord); inline; +procedure DrawLineWrapped(X0, Y0, X1, Y1, Width: Single; goesLeft: boolean; Wraps: LongWord; color: LongWord); begin DrawLineWrapped(X0, Y0, X1, Y1, Width, goesLeft, Wraps, (color shr 24) and $FF, (color shr 16) and $FF, (color shr 8) and $FF, color and $FF); end; @@ -2073,7 +2073,7 @@ end; -procedure openglTint(r, g, b, a: Byte); inline; +procedure openglTint(r, g, b, a: Byte); {$IFDEF GL2} const scale:Real = 1.0/255.0; @@ -2109,20 +2109,20 @@ LastTint:= nc; end; -procedure Tint(c: Longword); inline; +procedure Tint(c: Longword); begin if c = LastTint then exit; Tint(((c shr 24) and $FF), ((c shr 16) and $FF), (c shr 8) and $FF, (c and $FF)) end; -procedure untint(); inline; +procedure untint(); begin if cWhiteColor = LastTint then exit; openglTint($FF, $FF, $FF, $FF); LastTint:= cWhiteColor; end; -procedure setTintAdd(enable: boolean); inline; +procedure setTintAdd(enable: boolean); begin {$IFDEF GL2} if enable then diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uRenderUtils.pas --- a/hedgewars/uRenderUtils.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uRenderUtils.pas Tue Aug 22 08:35:46 2023 +0200 @@ -26,13 +26,13 @@ procedure flipSurface(Surface: PSDL_Surface; Vertical: Boolean); procedure copyRotatedSurface(src, dest: PSDL_Surface); // this is necessary since width/height are read only in SDL -procedure copyToXY(src, dest: PSDL_Surface; destX, destY: LongInt); inline; +procedure copyToXY(src, dest: PSDL_Surface; destX, destY: LongInt); procedure copyToXYFromRect(src, dest: PSDL_Surface; srcX, srcY, srcW, srcH, destX, destY: LongInt); function GetSurfaceFrameCoordinateX(Surface: PSDL_Surface; Frame, frameWidth, frameHeight: LongInt): LongInt; function GetSurfaceFrameCoordinateY(Surface: PSDL_Surface; Frame, frameHeight: LongInt): LongInt; -procedure DrawSprite2Surf(sprite: TSprite; dest: PSDL_Surface; x,y: LongInt); inline; +procedure DrawSprite2Surf(sprite: TSprite; dest: PSDL_Surface; x,y: LongInt); procedure DrawSpriteFrame2Surf(sprite: TSprite; dest: PSDL_Surface; x,y: LongInt; frame: LongInt); procedure DrawLine2Surf(dest: PSDL_Surface; x0,y0,x1,y1:LongInt; r,g,b: byte); procedure DrawRoundRect(rect: PSDL_Rect; BorderColor, FillColor: Longword; Surface: PSDL_Surface; Clear: boolean); @@ -41,7 +41,7 @@ function RenderStringTexLim(s: ansistring; Color: Longword; font: THWFont; maxLength: LongWord): PTexture; function RenderSpeechBubbleTex(s: ansistring; SpeechType: Longword; font: THWFont): PTexture; -function IsTooDarkToRead(TextColor: Longword): boolean; inline; +function IsTooDarkToRead(TextColor: Longword): boolean; implementation uses uVariables, uConsts, uTextures, SysUtils, uUtils, uDebug; @@ -99,7 +99,7 @@ GetSurfaceFrameCoordinateY:= (Frame mod ny) * frameHeight; end; -function IsTooDarkToRead(TextColor: LongWord): boolean; inline; +function IsTooDarkToRead(TextColor: LongWord): boolean; var clr: TSDL_Color; begin clr.r:= (TextColor shr 16) and $FF; @@ -178,7 +178,7 @@ SDL_UnlockSurface(Surface); end; -procedure copyToXY(src, dest: PSDL_Surface; destX, destY: LongInt); inline; +procedure copyToXY(src, dest: PSDL_Surface; destX, destY: LongInt); begin // copy from complete src copyToXYFromRect(src, dest, 0, 0, src^.w, src^.h, destX, destY); @@ -254,7 +254,7 @@ SDL_UnlockSurface(dest); end; -procedure DrawSprite2Surf(sprite: TSprite; dest: PSDL_Surface; x,y: LongInt); inline; +procedure DrawSprite2Surf(sprite: TSprite; dest: PSDL_Surface; x,y: LongInt); begin DrawSpriteFrame2Surf(sprite, dest, x, y, 0); end; diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uScript.pas --- a/hedgewars/uScript.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uScript.pas Tue Aug 22 08:35:46 2023 +0200 @@ -184,14 +184,14 @@ LuaError('-- SYNTAX: ' + call + ' ( ' + paramsyntax + ' )'); end; -procedure LuaParameterCountError(expected, call, paramsyntax: shortstring; wrongcount: LongInt); inline; +procedure LuaParameterCountError(expected, call, paramsyntax: shortstring; wrongcount: LongInt); begin // TODO: i18n? LuaCallError('Wrong number of parameters! (is: ' + inttostr(wrongcount) + ', should be: '+ expected + ')', call, paramsyntax); end; // compare with allowed count -function CheckLuaParamCount(L : Plua_State; count: LongInt; call, paramsyntax: shortstring): boolean; inline; +function CheckLuaParamCount(L : Plua_State; count: LongInt; call, paramsyntax: shortstring): boolean; var c: LongInt; begin c:= lua_gettop(L); @@ -205,7 +205,7 @@ end; // check if is either count1 or count2 -function CheckAndFetchParamCount(L : Plua_State; count1, count2: LongInt; call, paramsyntax: shortstring; out actual: LongInt): boolean; inline; +function CheckAndFetchParamCount(L : Plua_State; count1, count2: LongInt; call, paramsyntax: shortstring; out actual: LongInt): boolean; begin actual:= lua_gettop(L); if (actual <> count1) and (actual <> count2) then @@ -218,7 +218,7 @@ end; // check if is in range of count1 and count2 -function CheckAndFetchParamCountRange(L : Plua_State; count1, count2: LongInt; call, paramsyntax: shortstring; out actual: LongInt): boolean; inline; +function CheckAndFetchParamCountRange(L : Plua_State; count1, count2: LongInt; call, paramsyntax: shortstring; out actual: LongInt): boolean; begin actual:= lua_gettop(L); if (actual < count1) or (actual > count2) then @@ -231,7 +231,7 @@ end; // check if is same or higher as minCount -function CheckAndFetchLuaParamMinCount(L : Plua_State; minCount: LongInt; call, paramsyntax: shortstring; out actual: LongInt): boolean; inline; +function CheckAndFetchLuaParamMinCount(L : Plua_State; minCount: LongInt; call, paramsyntax: shortstring; out actual: LongInt): boolean; begin actual:= lua_gettop(L); if (actual < minCount) then @@ -243,7 +243,7 @@ CheckAndFetchLuaParamMinCount:= true; end; -function LuaToGearTypeOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline; +function LuaToGearTypeOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; begin if lua_isnoneornil(L, i) then i:= -1 else i:= Trunc(lua_tonumber(L, i)); @@ -256,7 +256,7 @@ LuaToGearTypeOrd:= i; end; -function LuaToVisualGearTypeOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline; +function LuaToVisualGearTypeOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; begin if lua_isnoneornil(L, i) then i:= -1 else i:= Trunc(lua_tonumber(L, i)); @@ -269,7 +269,7 @@ LuaToVisualGearTypeOrd:= i; end; -function LuaToAmmoTypeOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline; +function LuaToAmmoTypeOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; begin if lua_isnoneornil(L, i) then i:= -1 else i:= Trunc(lua_tonumber(L, i)); @@ -282,7 +282,7 @@ LuaToAmmoTypeOrd:= i; end; -function LuaToStatInfoTypeOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline; +function LuaToStatInfoTypeOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; begin if lua_isnoneornil(L, i) then i:= -1 else i:= Trunc(lua_tonumber(L, i)); @@ -295,7 +295,7 @@ LuaToStatInfoTypeOrd:= i; end; -function LuaToSoundOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline; +function LuaToSoundOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; begin if lua_isnoneornil(L, i) then i:= -1 else i:= Trunc(lua_tonumber(L, i)); @@ -334,7 +334,7 @@ LuaToGoalStrIdOrd:= i; end; -function LuaToHogEffectOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline; +function LuaToHogEffectOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; begin if lua_isnoneornil(L, i) then i:= -1 else i:= Trunc(lua_tonumber(L, i)); @@ -347,7 +347,7 @@ LuaToHogEffectOrd:= i; end; -function LuaToCapGroupOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline; +function LuaToCapGroupOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; begin if lua_isnoneornil(L, i) then i:= -1 else i:= Trunc(lua_tonumber(L, i)); @@ -360,7 +360,7 @@ LuaToCapGroupOrd:= i; end; -function LuaToSpriteOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline; +function LuaToSpriteOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; begin if lua_isnoneornil(L, i) then i:= -1 else i:= Trunc(lua_tonumber(L, i)); @@ -373,7 +373,7 @@ LuaToSpriteOrd:= i; end; -function LuaToMapGenOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; inline; +function LuaToMapGenOrd(L : Plua_State; i: LongInt; call, paramsyntax: shortstring): LongInt; begin if lua_isnoneornil(L, i) then i:= -1 else i:= Trunc(lua_tonumber(L, i)); diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uStore.pas --- a/hedgewars/uStore.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uStore.pas Tue Aug 22 08:35:46 2023 +0200 @@ -59,7 +59,7 @@ procedure InitOffscreenOpenGL; {$ENDIF} -procedure WarpMouse(x, y: Word); inline; +procedure WarpMouse(x, y: Word); procedure SwapBuffers; {$IFDEF USE_VIDEO_RECORDING}cdecl{$ELSE}inline{$ENDIF}; procedure SetSkyColor(r, g, b: real); @@ -1381,7 +1381,7 @@ // for sdl2 we provide a SDL_WarpMouse() which just calls this function // this has the advantage of reducing 'uses' and 'ifdef' statements // (SDLwindow is a private member of this module) -procedure WarpMouse(x, y: Word); inline; +procedure WarpMouse(x, y: Word); begin SDL_WarpMouseInWindow(SDLwindow, x, y); end; diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uTextures.pas --- a/hedgewars/uTextures.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uTextures.pas Tue Aug 22 08:35:46 2023 +0200 @@ -26,14 +26,14 @@ procedure Surface2GrayScale(surf: PSDL_Surface); function Surface2Tex(surf: PSDL_Surface; enableClamp: boolean): PTexture; procedure PrettifySurfaceAlpha(surf: PSDL_Surface; pixels: PLongwordArray); -procedure PrettifyAlpha2D(pixels: TLandArray; height, width: LongWord); +procedure PrettifyAlpha2D(height, width: LongWord); procedure FreeAndNilTexture(var tex: PTexture); procedure initModule; procedure freeModule; implementation -uses GLunit, uUtils, uVariables, uConsts, uDebug, uConsole; +uses GLunit, uUtils, uVariables, uConsts, uDebug, uConsole, uLandUtils; var TextureList: PTexture; @@ -194,7 +194,7 @@ PrettifyAlpha(pixels, nil, si, li, w); end; -procedure PrettifyAlpha2D(pixels: TLandArray; height, width: LongWord); +procedure PrettifyAlpha2D(height, width: LongWord); var // current y; last x, second last y of array; y, lx, sly: LongWord; @@ -203,10 +203,10 @@ lx:= width - 1; for y:= 0 to sly do begin - PrettifyAlpha(PLongWordArray(pixels[y]), PLongWordArray(pixels[y+1]), 0, lx, 0); + PrettifyAlpha(LandPixelRow(y), LandPixelRow(y+1), 0, lx, 0); end; // don't forget last row - PrettifyAlpha(PLongWordArray(pixels[sly+1]), nil, 0, lx, 0); + PrettifyAlpha(LandPixelRow(sly+1), nil, 0, lx, 0); end; function Surface2Tex(surf: PSDL_Surface; enableClamp: boolean): PTexture; diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uTouch.pas --- a/hedgewars/uTouch.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uTouch.pas Tue Aug 22 08:35:46 2023 +0200 @@ -613,7 +613,7 @@ fingerHasMoved := trunc(sqrt(sqr(finger.X-finger.historicalX) + sqr(finger.y-finger.historicalY))) > 30; end; -function calculateDelta(finger1, finger2: TTouch_Data): LongInt; inline; +function calculateDelta(finger1, finger2: TTouch_Data): LongInt; begin calculateDelta := Round(sqrt(sqr(finger2.x-finger1.x) + sqr(finger2.y-finger1.y))); end; diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uTypes.pas --- a/hedgewars/uTypes.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uTypes.pas Tue Aug 22 08:35:46 2023 +0200 @@ -99,7 +99,7 @@ // Gears that interact with other Gears and/or Land // first row of gears ( nil) and (cWindSpeedf<0) then exit(Lsprite) @@ -133,7 +133,7 @@ exit(sprite); end; -function GetSpriteData(sprite, SDsprite: TSprite): PSpriteData; inline; +function GetSpriteData(sprite, SDsprite: TSprite): PSpriteData; begin exit(@SpritesData[GetSprite(sprite, SDsprite)]); end; @@ -498,7 +498,7 @@ end; end; -procedure AddFlake; inline; +procedure AddFlake; begin AddVisualGear(cLeftScreenBorder + random(cScreenSpace), LAND_HEIGHT-cCloudOffset+ random(cCloudOffset), vgtFlake); end; diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uVisualGearsHandlers.pas --- a/hedgewars/uVisualGearsHandlers.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uVisualGearsHandlers.pas Tue Aug 22 08:35:46 2023 +0200 @@ -71,7 +71,7 @@ procedure doStepSmoothWindBar(Gear: PVisualGear; Steps: Longword); procedure doStepStraightShot(Gear: PVisualGear; Steps: Longword); -function isSorterActive: boolean; inline; +function isSorterActive: boolean; procedure initModule; implementation @@ -573,7 +573,7 @@ end; currsorter: PVisualGear = nil; -function isSorterActive: boolean; inline; +function isSorterActive: boolean; begin isSorterActive:= currsorter <> nil end; diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uVisualGearsList.pas --- a/hedgewars/uVisualGearsList.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uVisualGearsList.pas Tue Aug 22 08:35:46 2023 +0200 @@ -22,9 +22,9 @@ interface uses uTypes; -function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType): PVisualGear; inline; -function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord): PVisualGear; inline; -function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord; Critical: Boolean): PVisualGear; inline; +function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType): PVisualGear; +function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord): PVisualGear; +function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord; Critical: Boolean): PVisualGear; function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord; Critical: Boolean; Layer: LongInt): PVisualGear; procedure DeleteVisualGear(Gear: PVisualGear); function VisualGearByUID(uid : Longword) : PVisualGear; @@ -39,7 +39,7 @@ implementation uses uCollisions, uFloat, uVariables, uConsts, uTextures, uVisualGearsHandlers, uScript; -function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType): PVisualGear; inline; +function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType): PVisualGear; begin // adjust some visual gear types if underwater if CheckCoordInWater(X, Y) and ((Kind = vgtBeeTrace) or (Kind = vgtSmokeTrace) or (Kind = vgtEvilTrace)) then @@ -48,12 +48,12 @@ AddVisualGear:= AddVisualGear(X, Y, Kind, 0, false, -1); end; -function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord): PVisualGear; inline; +function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord): PVisualGear; begin AddVisualGear:= AddVisualGear(X, Y, Kind, State, false, -1); end; -function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord; Critical: Boolean): PVisualGear; inline; +function AddVisualGear(X, Y: LongInt; Kind: TVisualGearType; State: LongWord; Critical: Boolean): PVisualGear; begin AddVisualGear:= AddVisualGear(X, Y, Kind, State, Critical, -1); end; diff -r 8bb07b0f50ca -r 2146cb7be36f hedgewars/uWorld.pas --- a/hedgewars/uWorld.pas Thu Aug 10 20:48:54 2023 -0400 +++ b/hedgewars/uWorld.pas Tue Aug 22 08:35:46 2023 +0200 @@ -1165,14 +1165,14 @@ var preShiftWorldDx: LongInt; -procedure ShiftWorld(Dir: LongInt); inline; +procedure ShiftWorld(Dir: LongInt); begin preShiftWorldDx:= WorldDx; Dir := Dir * LongInt(playWidth); WorldDx:= WorldDx + Dir; end; -procedure UnshiftWorld(); inline; +procedure UnshiftWorld(); begin WorldDx:= preShiftWorldDx; end; diff -r 8bb07b0f50ca -r 2146cb7be36f rust/integral-geometry/src/lib.rs --- a/rust/integral-geometry/src/lib.rs Thu Aug 10 20:48:54 2023 -0400 +++ b/rust/integral-geometry/src/lib.rs Tue Aug 22 08:35:46 2023 +0200 @@ -164,6 +164,11 @@ } #[inline] + pub fn is_square(&self) -> bool { + self.width == self.height + } + + #[inline] pub const fn contains(&self, other: Self) -> bool { self.width >= other.width && self.height >= other.height } diff -r 8bb07b0f50ca -r 2146cb7be36f rust/land2d/Cargo.toml --- a/rust/land2d/Cargo.toml Thu Aug 10 20:48:54 2023 -0400 +++ b/rust/land2d/Cargo.toml Tue Aug 22 08:35:46 2023 +0200 @@ -2,7 +2,7 @@ name = "land2d" version = "0.1.0" authors = ["Andrey Korotaev "] -edition = "2018" +edition = "2021" [dependencies] vec2d = { path = "../vec2d" } diff -r 8bb07b0f50ca -r 2146cb7be36f rust/land2d/src/lib.rs --- a/rust/land2d/src/lib.rs Thu Aug 10 20:48:54 2023 -0400 +++ b/rust/land2d/src/lib.rs Tue Aug 22 08:35:46 2023 +0200 @@ -1,24 +1,25 @@ -use std::{cmp, ops::Index}; - +use std::{cmp, ops::Index, ops::IndexMut}; +use vec2d::Vec2D; use integral_geometry::{ArcPoints, EquidistantPoints, Line, Point, PotSize, Rect, Size, SizeMask}; +#[derive(Debug)] pub struct Land2D { pixels: vec2d::Vec2D, play_box: Rect, mask: SizeMask, } -impl Land2D { - pub fn new(play_size: Size, fill_value: T) -> Self { +impl Land2D { + pub fn new(play_size: &Size, fill_value: T) -> Self { let real_size = play_size.next_power_of_two(); let top_left = Point::new( ((real_size.width() - play_size.width) / 2) as i32, (real_size.height() - play_size.height) as i32, ); - let play_box = Rect::from_size(top_left, play_size); + let play_box = Rect::from_size(top_left, *play_size); Self { play_box, - pixels: vec2d::Vec2D::new(real_size.size(), fill_value), + pixels: vec2d::Vec2D::new(&real_size.size(), fill_value), mask: real_size.to_mask(), } } @@ -99,6 +100,18 @@ } #[inline] + pub fn get(&self, y: i32, x: i32) -> T { + if self.is_valid_coordinate(x, y) { + unsafe { + // hey, I just checked that coordinates are valid! + *self.pixels.get_unchecked(y as usize, x as usize) + } + } else { + T::default() + } + } + + #[inline] pub fn map_point U>(&mut self, point: Point, f: F) -> U { self.map(point.y, point.x, f) } @@ -288,6 +301,30 @@ } } +impl IndexMut for Land2D { + #[inline] + fn index_mut(&mut self, row: usize) -> &mut [T] { + &mut self.pixels[row] + } +} + +impl From> for Land2D { + fn from(vec: Vec2D) -> Self { + let actual_size = vec.size(); + let pot_size = actual_size.next_power_of_two(); + + assert_eq!(actual_size, pot_size.size()); + + let top_left = Point::new(0, 0); + let play_box = Rect::from_size(top_left, actual_size); + Self { + play_box, + pixels: vec, + mask: pot_size.to_mask(), + } + } +} + #[cfg(test)] mod tests { use super::*; diff -r 8bb07b0f50ca -r 2146cb7be36f rust/landgen/Cargo.toml --- a/rust/landgen/Cargo.toml Thu Aug 10 20:48:54 2023 -0400 +++ b/rust/landgen/Cargo.toml Tue Aug 22 08:35:46 2023 +0200 @@ -2,9 +2,11 @@ name = "landgen" version = "0.1.0" authors = ["Andrey Korotaev "] -edition = "2018" +edition = "2021" [dependencies] integral-geometry = { path = "../integral-geometry" } land2d = { path = "../land2d" } +vec2d = { path = "../vec2d" } itertools = "0.7.8" +png = "0.17" diff -r 8bb07b0f50ca -r 2146cb7be36f rust/landgen/src/lib.rs --- a/rust/landgen/src/lib.rs Thu Aug 10 20:48:54 2023 -0400 +++ b/rust/landgen/src/lib.rs Tue Aug 22 08:35:46 2023 +0200 @@ -1,7 +1,7 @@ -mod outline; -pub mod outline_template; -pub mod template_based; +pub mod outline_template_based; +pub mod wavefront_collapse; +#[derive(Clone, Copy)] pub struct LandGenerationParameters { zero: T, basic: T, @@ -10,7 +10,7 @@ skip_bezier: bool, } -impl LandGenerationParameters { +impl LandGenerationParameters { pub fn new( zero: T, basic: T, @@ -26,20 +26,20 @@ skip_bezier, } } + + pub fn zero(&self) -> T { + self.zero + } + + pub fn basic(&self) -> T { + self.basic + } } pub trait LandGenerator { - fn generate_land>( + fn generate_land>( &self, parameters: &LandGenerationParameters, random_numbers: &mut I, ) -> land2d::Land2D; } - -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} diff -r 8bb07b0f50ca -r 2146cb7be36f rust/landgen/src/outline.rs --- a/rust/landgen/src/outline.rs Thu Aug 10 20:48:54 2023 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,341 +0,0 @@ -use itertools::Itertools; -use std::cmp::min; - -use integral_geometry::{Line, Point, Polygon, Ray, Rect, Size}; -use land2d::Land2D; - -use crate::outline_template::OutlineTemplate; - -pub struct OutlinePoints { - pub islands: Vec, - pub fill_points: Vec, - pub size: Size, - pub play_box: Rect, - intersections_box: Rect, -} - -impl OutlinePoints { - pub fn from_outline_template>( - outline_template: &OutlineTemplate, - play_box: Rect, - size: Size, - random_numbers: &mut I, - ) -> Self { - Self { - play_box, - size, - islands: outline_template - .islands - .iter() - .map(|i| { - i.iter() - .zip(random_numbers.tuples()) - .map(|(rect, (rnd_a, rnd_b))| { - play_box.top_left() + rect.quotient(rnd_a as usize, rnd_b as usize) - }) - .collect::>() - .into() - }) - .collect(), - fill_points: outline_template.fill_points.clone(), - intersections_box: Rect::at_origin(size) - .with_margin(size.to_square().width as i32 * -2), - } - } - - pub fn total_len(&self) -> usize { - self.islands.iter().map(|i| i.edges_count()).sum::() + self.fill_points.len() - } - - pub fn iter(&self) -> impl Iterator { - self.islands - .iter() - .flat_map(|p| p.iter()) - .chain(self.fill_points.iter()) - } - - pub fn iter_mut(&mut self) -> impl Iterator { - self.islands - .iter_mut() - .flat_map(|i| i.iter_mut()) - .chain(self.fill_points.iter_mut()) - } - - fn divide_edge>( - &self, - segment: Line, - distance_divisor: u32, - random_numbers: &mut I, - ) -> Option { - #[inline] - fn intersects(ray: &Ray, edge: &Line) -> bool { - ray.orientation(edge.start) != ray.orientation(edge.end) - } - - #[inline] - fn solve_intersection( - intersections_box: &Rect, - ray: &Ray, - edge: &Line, - ) -> Option<(i32, u32)> { - let edge_dir = edge.scaled_direction(); - let aqpb = ray.direction.cross(edge_dir) as i64; - - if aqpb != 0 { - let mut iy = ((((edge.start.x - ray.start.x) as i64 * ray.direction.y as i64 - + ray.start.y as i64 * ray.direction.x as i64) - * edge_dir.y as i64 - - edge.start.y as i64 * edge_dir.x as i64 * ray.direction.y as i64) - / aqpb) as i32; - - // is there better way to do it? - if iy < intersections_box.top() { - iy = intersections_box.top(); - } else if iy > intersections_box.bottom() { - iy = intersections_box.bottom(); - } - - let ix = if ray.direction.y.abs() > edge_dir.y.abs() { - ray.start.x + ray.direction.cotangent_mul(iy - ray.start.y) - } else { - edge.start.x + edge_dir.cotangent_mul(iy - edge.start.y) - }; - - let intersection_point = Point::new(ix, iy).clamp(intersections_box); - let diff_point = ray.start - intersection_point; - let t = ray.direction.dot(diff_point); - - if diff_point.max_norm() >= std::i16::MAX as i32 { - Some((t, std::i32::MAX as u32)) - } else { - let d = diff_point.integral_norm(); - - Some((t, d)) - } - } else { - None - } - } - - let min_distance = 40; - // new point should fall inside this box - let map_box = self.play_box.with_margin(min_distance); - - let normal = segment.scaled_normal(); - let normal_len = normal.integral_norm(); - let mid_point = segment.center(); - - if (normal_len < min_distance as u32 * 3) || !map_box.contains_inside(mid_point) { - return None; - } - - let normal_ray = Ray::new(mid_point, normal); - let mut dist_left = (self.size.width + self.size.height) as u32; - let mut dist_right = dist_left; - - // find distances to map borders - if normal.x != 0 { - // where the normal line intersects the left map border - let left_intersection = Point::new( - map_box.left(), - mid_point.y + normal.tangent_mul(map_box.left() - mid_point.x), - ); - dist_left = (mid_point - left_intersection).integral_norm(); - - // same for the right border - let right_intersection = Point::new( - map_box.right(), - mid_point.y + normal.tangent_mul(map_box.right() - mid_point.x), - ); - dist_right = (mid_point - right_intersection).integral_norm(); - - if normal.x > 0 { - std::mem::swap(&mut dist_left, &mut dist_right); - } - } - - if normal.y != 0 { - // where the normal line intersects the top map border - let top_intersection = Point::new( - mid_point.x + normal.cotangent_mul(map_box.top() - mid_point.y), - map_box.top(), - ); - let dl = (mid_point - top_intersection).integral_norm(); - - // same for the bottom border - let bottom_intersection = Point::new( - mid_point.x + normal.cotangent_mul(map_box.bottom() - mid_point.y), - map_box.bottom(), - ); - let dr = (mid_point - bottom_intersection).integral_norm(); - - if normal.y < 0 { - dist_left = min(dist_left, dl); - dist_right = min(dist_right, dr); - } else { - dist_left = min(dist_left, dr); - dist_right = min(dist_right, dl); - } - } - - // now go through all other segments - for s in self.segments_iter() { - if s != segment { - if intersects(&normal_ray, &s) { - if let Some((t, d)) = - solve_intersection(&self.intersections_box, &normal_ray, &s) - { - if t > 0 { - dist_right = min(dist_right, d); - } else { - dist_left = min(dist_left, d); - } - } - } - } - } - - // go through all points, including fill points - for pi in self.iter().cloned() { - if pi != segment.start && pi != segment.end { - if intersects(&pi.ray_with_dir(normal), &segment) { - // ray from segment.start - if let Some((t, d)) = solve_intersection( - &self.intersections_box, - &normal_ray, - &segment.start.line_to(pi), - ) { - if t > 0 { - dist_right = min(dist_right, d); - } else { - dist_left = min(dist_left, d); - } - } - - // ray from segment.end - if let Some((t, d)) = solve_intersection( - &self.intersections_box, - &normal_ray, - &segment.end.line_to(pi), - ) { - if t > 0 { - dist_right = min(dist_right, d); - } else { - dist_left = min(dist_left, d); - } - } - } - } - } - - let max_dist = normal_len * 100 / distance_divisor; - dist_left = min(dist_left, max_dist); - dist_right = min(dist_right, max_dist); - - if dist_right + dist_left < min_distance as u32 * 2 + 10 { - // limits are too narrow, just divide - Some(mid_point) - } else { - // select distance within [-dist_right; dist_left], keeping min_distance in mind - let d = -(dist_right as i32) - + min_distance - + random_numbers.next().unwrap() as i32 - % (dist_right as i32 + dist_left as i32 - min_distance * 2); - - Some(mid_point + normal * d / normal_len as i32) - } - } - - fn divide_edges>( - &mut self, - distance_divisor: u32, - random_numbers: &mut I, - ) { - for is in 0..self.islands.len() { - let mut i = 0; - while i < self.islands[is].edges_count() { - let segment = self.islands[is].get_edge(i); - if let Some(new_point) = self.divide_edge(segment, distance_divisor, random_numbers) - { - self.islands[is].split_edge(i, new_point); - i += 2; - } else { - i += 1; - } - } - } - } - - pub fn bezierize(&mut self, segments_number: u32) { - for island in &mut self.islands { - island.bezierize(segments_number); - } - } - - pub fn distort>( - &mut self, - distance_divisor: u32, - random_numbers: &mut I, - ) { - loop { - let old_len = self.total_len(); - self.divide_edges(distance_divisor, random_numbers); - - if self.total_len() == old_len { - break; - } - } - } - - pub fn draw(&self, land: &mut Land2D, value: T) { - for segment in self.segments_iter() { - land.draw_line(segment, value); - } - } - - fn segments_iter<'a>(&'a self) -> impl Iterator + 'a { - self.islands.iter().flat_map(|p| p.iter_edges()) - } - - pub fn mirror(&mut self) { - let r = self.size.width as i32 - 1; - - self.iter_mut().for_each(|p| p.x = r - p.x); - } - - pub fn flip(&mut self) { - let t = self.size.height as i32 - 1; - - self.iter_mut().for_each(|p| p.y = t - p.y); - } -} - -#[test] -fn points_test() { - let size = Size::square(100); - let mut points = OutlinePoints { - islands: vec![ - Polygon::new(&[Point::new(0, 0), Point::new(20, 0), Point::new(30, 30)]), - Polygon::new(&[Point::new(10, 15), Point::new(15, 20), Point::new(20, 15)]), - ], - fill_points: vec![Point::new(1, 1)], - play_box: Rect::at_origin(size).with_margin(10), - size: Size::square(100), - intersections_box: Rect::at_origin(size), - }; - - let segments: Vec = points.segments_iter().collect(); - assert_eq!( - segments.first(), - Some(&Line::new(Point::new(0, 0), Point::new(20, 0))) - ); - assert_eq!( - segments.last(), - Some(&Line::new(Point::new(20, 15), Point::new(10, 15))) - ); - - points.iter_mut().for_each(|p| p.x = 2); - - assert_eq!(points.fill_points[0].x, 2); - assert_eq!(points.islands[0].get_edge(0).start.x, 2); -} diff -r 8bb07b0f50ca -r 2146cb7be36f rust/landgen/src/outline_template.rs --- a/rust/landgen/src/outline_template.rs Thu Aug 10 20:48:54 2023 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -use integral_geometry::{Point, Rect, Size}; - -#[derive(Clone, Debug)] -pub struct OutlineTemplate { - pub islands: Vec>, - pub fill_points: Vec, - pub size: Size, - pub can_flip: bool, - pub can_invert: bool, - pub can_mirror: bool, - pub is_negative: bool, -} - -impl OutlineTemplate { - pub fn new(size: Size) -> Self { - OutlineTemplate { - size, - islands: Vec::new(), - fill_points: Vec::new(), - can_flip: false, - can_invert: false, - can_mirror: false, - is_negative: false, - } - } - - pub fn flippable(self) -> Self { - Self { - can_flip: true, - ..self - } - } - - pub fn mirrorable(self) -> Self { - Self { - can_mirror: true, - ..self - } - } - - pub fn invertable(self) -> Self { - Self { - can_invert: true, - ..self - } - } - - pub fn negative(self) -> Self { - Self { - is_negative: true, - ..self - } - } - - pub fn with_fill_points(self, fill_points: Vec) -> Self { - Self { - fill_points, - ..self - } - } - - pub fn with_islands(self, islands: Vec>) -> Self { - Self { islands, ..self } - } - - pub fn add_fill_points(mut self, points: &[Point]) -> Self { - self.fill_points.extend_from_slice(points); - self - } - - pub fn add_island(mut self, island: &[Rect]) -> Self { - self.islands.push(island.into()); - self - } -} diff -r 8bb07b0f50ca -r 2146cb7be36f rust/landgen/src/outline_template_based/mod.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/landgen/src/outline_template_based/mod.rs Tue Aug 22 08:35:46 2023 +0200 @@ -0,0 +1,3 @@ +mod outline; +pub mod outline_template; +pub mod template_based; diff -r 8bb07b0f50ca -r 2146cb7be36f rust/landgen/src/outline_template_based/outline.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/landgen/src/outline_template_based/outline.rs Tue Aug 22 08:35:46 2023 +0200 @@ -0,0 +1,338 @@ +use itertools::Itertools; +use std::cmp::min; + +use integral_geometry::{Line, Point, Polygon, Ray, Rect, Size}; +use land2d::Land2D; + +use super::outline_template::OutlineTemplate; + +pub struct OutlinePoints { + pub islands: Vec, + pub fill_points: Vec, + pub size: Size, + pub play_box: Rect, + intersections_box: Rect, +} + +impl OutlinePoints { + pub fn from_outline_template>( + outline_template: &OutlineTemplate, + play_box: Rect, + size: Size, + random_numbers: &mut I, + ) -> Self { + Self { + play_box, + size, + islands: outline_template + .islands + .iter() + .map(|i| { + i.iter() + .zip(random_numbers.tuples()) + .map(|(rect, (rnd_a, rnd_b))| { + play_box.top_left() + rect.quotient(rnd_a as usize, rnd_b as usize) + }) + .collect::>() + .into() + }) + .collect(), + fill_points: outline_template.fill_points.clone(), + intersections_box: Rect::at_origin(size) + .with_margin(size.to_square().width as i32 * -2), + } + } + + pub fn total_len(&self) -> usize { + self.islands.iter().map(|i| i.edges_count()).sum::() + self.fill_points.len() + } + + pub fn iter(&self) -> impl Iterator { + self.islands + .iter() + .flat_map(|p| p.iter()) + .chain(self.fill_points.iter()) + } + + pub fn iter_mut(&mut self) -> impl Iterator { + self.islands + .iter_mut() + .flat_map(|i| i.iter_mut()) + .chain(self.fill_points.iter_mut()) + } + + fn divide_edge>( + &self, + segment: Line, + distance_divisor: u32, + random_numbers: &mut I, + ) -> Option { + #[inline] + fn intersects(ray: &Ray, edge: &Line) -> bool { + ray.orientation(edge.start) != ray.orientation(edge.end) + } + + #[inline] + fn solve_intersection( + intersections_box: &Rect, + ray: &Ray, + edge: &Line, + ) -> Option<(i32, u32)> { + let edge_dir = edge.scaled_direction(); + let aqpb = ray.direction.cross(edge_dir) as i64; + + if aqpb != 0 { + let mut iy = ((((edge.start.x - ray.start.x) as i64 * ray.direction.y as i64 + + ray.start.y as i64 * ray.direction.x as i64) + * edge_dir.y as i64 + - edge.start.y as i64 * edge_dir.x as i64 * ray.direction.y as i64) + / aqpb) as i32; + + // is there better way to do it? + if iy < intersections_box.top() { + iy = intersections_box.top(); + } else if iy > intersections_box.bottom() { + iy = intersections_box.bottom(); + } + + let ix = if ray.direction.y.abs() > edge_dir.y.abs() { + ray.start.x + ray.direction.cotangent_mul(iy - ray.start.y) + } else { + edge.start.x + edge_dir.cotangent_mul(iy - edge.start.y) + }; + + let intersection_point = Point::new(ix, iy).clamp(intersections_box); + let diff_point = ray.start - intersection_point; + let t = ray.direction.dot(diff_point); + + if diff_point.max_norm() >= std::i16::MAX as i32 { + Some((t, std::i32::MAX as u32)) + } else { + let d = diff_point.integral_norm(); + + Some((t, d)) + } + } else { + None + } + } + + let min_distance = 40; + // new point should fall inside this box + let map_box = self.play_box.with_margin(min_distance); + + let normal = segment.scaled_normal(); + let normal_len = normal.integral_norm(); + let mid_point = segment.center(); + + if (normal_len < min_distance as u32 * 3) || !map_box.contains_inside(mid_point) { + return None; + } + + let normal_ray = Ray::new(mid_point, normal); + let mut dist_left = (self.size.width + self.size.height) as u32; + let mut dist_right = dist_left; + + // find distances to map borders + if normal.x != 0 { + // where the normal line intersects the left map border + let left_intersection = Point::new( + map_box.left(), + mid_point.y + normal.tangent_mul(map_box.left() - mid_point.x), + ); + dist_left = (mid_point - left_intersection).integral_norm(); + + // same for the right border + let right_intersection = Point::new( + map_box.right(), + mid_point.y + normal.tangent_mul(map_box.right() - mid_point.x), + ); + dist_right = (mid_point - right_intersection).integral_norm(); + + if normal.x > 0 { + std::mem::swap(&mut dist_left, &mut dist_right); + } + } + + if normal.y != 0 { + // where the normal line intersects the top map border + let top_intersection = Point::new( + mid_point.x + normal.cotangent_mul(map_box.top() - mid_point.y), + map_box.top(), + ); + let dl = (mid_point - top_intersection).integral_norm(); + + // same for the bottom border + let bottom_intersection = Point::new( + mid_point.x + normal.cotangent_mul(map_box.bottom() - mid_point.y), + map_box.bottom(), + ); + let dr = (mid_point - bottom_intersection).integral_norm(); + + if normal.y < 0 { + dist_left = min(dist_left, dl); + dist_right = min(dist_right, dr); + } else { + dist_left = min(dist_left, dr); + dist_right = min(dist_right, dl); + } + } + + // now go through all other segments + for s in self.segments_iter() { + if s != segment && intersects(&normal_ray, &s) { + if let Some((t, d)) = solve_intersection(&self.intersections_box, &normal_ray, &s) { + if t > 0 { + dist_right = min(dist_right, d); + } else { + dist_left = min(dist_left, d); + } + } + } + } + + // go through all points, including fill points + for pi in self.iter().cloned() { + if pi != segment.start + && pi != segment.end + && intersects(&pi.ray_with_dir(normal), &segment) + { + // ray from segment.start + if let Some((t, d)) = solve_intersection( + &self.intersections_box, + &normal_ray, + &segment.start.line_to(pi), + ) { + if t > 0 { + dist_right = min(dist_right, d); + } else { + dist_left = min(dist_left, d); + } + } + + // ray from segment.end + if let Some((t, d)) = solve_intersection( + &self.intersections_box, + &normal_ray, + &segment.end.line_to(pi), + ) { + if t > 0 { + dist_right = min(dist_right, d); + } else { + dist_left = min(dist_left, d); + } + } + } + } + + let max_dist = normal_len * 100 / distance_divisor; + dist_left = min(dist_left, max_dist); + dist_right = min(dist_right, max_dist); + + if dist_right + dist_left < min_distance as u32 * 2 + 10 { + // limits are too narrow, just divide + Some(mid_point) + } else { + // select distance within [-dist_right; dist_left], keeping min_distance in mind + let d = -(dist_right as i32) + + min_distance + + random_numbers.next().unwrap() as i32 + % (dist_right as i32 + dist_left as i32 - min_distance * 2); + + Some(mid_point + normal * d / normal_len as i32) + } + } + + fn divide_edges>( + &mut self, + distance_divisor: u32, + random_numbers: &mut I, + ) { + for is in 0..self.islands.len() { + let mut i = 0; + while i < self.islands[is].edges_count() { + let segment = self.islands[is].get_edge(i); + if let Some(new_point) = self.divide_edge(segment, distance_divisor, random_numbers) + { + self.islands[is].split_edge(i, new_point); + i += 2; + } else { + i += 1; + } + } + } + } + + pub fn bezierize(&mut self, segments_number: u32) { + for island in &mut self.islands { + island.bezierize(segments_number); + } + } + + pub fn distort>( + &mut self, + distance_divisor: u32, + random_numbers: &mut I, + ) { + loop { + let old_len = self.total_len(); + self.divide_edges(distance_divisor, random_numbers); + + if self.total_len() == old_len { + break; + } + } + } + + pub fn draw(&self, land: &mut Land2D, value: T) { + for segment in self.segments_iter() { + land.draw_line(segment, value); + } + } + + fn segments_iter<'a>(&'a self) -> impl Iterator + 'a { + self.islands.iter().flat_map(|p| p.iter_edges()) + } + + pub fn mirror(&mut self) { + let r = self.size.width as i32 - 1; + + self.iter_mut().for_each(|p| p.x = r - p.x); + } + + pub fn flip(&mut self) { + let t = self.size.height as i32 - 1; + + self.iter_mut().for_each(|p| p.y = t - p.y); + } +} + +#[test] +fn points_test() { + let size = Size::square(100); + let mut points = OutlinePoints { + islands: vec![ + Polygon::new(&[Point::new(0, 0), Point::new(20, 0), Point::new(30, 30)]), + Polygon::new(&[Point::new(10, 15), Point::new(15, 20), Point::new(20, 15)]), + ], + fill_points: vec![Point::new(1, 1)], + play_box: Rect::at_origin(size).with_margin(10), + size: Size::square(100), + intersections_box: Rect::at_origin(size), + }; + + let segments: Vec = points.segments_iter().collect(); + assert_eq!( + segments.first(), + Some(&Line::new(Point::new(0, 0), Point::new(20, 0))) + ); + assert_eq!( + segments.last(), + Some(&Line::new(Point::new(20, 15), Point::new(10, 15))) + ); + + points.iter_mut().for_each(|p| p.x = 2); + + assert_eq!(points.fill_points[0].x, 2); + assert_eq!(points.islands[0].get_edge(0).start.x, 2); +} diff -r 8bb07b0f50ca -r 2146cb7be36f rust/landgen/src/outline_template_based/outline_template.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/landgen/src/outline_template_based/outline_template.rs Tue Aug 22 08:35:46 2023 +0200 @@ -0,0 +1,75 @@ +use integral_geometry::{Point, Rect, Size}; + +#[derive(Clone, Debug)] +pub struct OutlineTemplate { + pub islands: Vec>, + pub fill_points: Vec, + pub size: Size, + pub can_flip: bool, + pub can_invert: bool, + pub can_mirror: bool, + pub is_negative: bool, +} + +impl OutlineTemplate { + pub fn new(size: Size) -> Self { + OutlineTemplate { + size, + islands: Vec::new(), + fill_points: Vec::new(), + can_flip: false, + can_invert: false, + can_mirror: false, + is_negative: false, + } + } + + pub fn flippable(self) -> Self { + Self { + can_flip: true, + ..self + } + } + + pub fn mirrorable(self) -> Self { + Self { + can_mirror: true, + ..self + } + } + + pub fn invertable(self) -> Self { + Self { + can_invert: true, + ..self + } + } + + pub fn negative(self) -> Self { + Self { + is_negative: true, + ..self + } + } + + pub fn with_fill_points(self, fill_points: Vec) -> Self { + Self { + fill_points, + ..self + } + } + + pub fn with_islands(self, islands: Vec>) -> Self { + Self { islands, ..self } + } + + pub fn add_fill_points(mut self, points: &[Point]) -> Self { + self.fill_points.extend_from_slice(points); + self + } + + pub fn add_island(mut self, island: &[Rect]) -> Self { + self.islands.push(island.into()); + self + } +} diff -r 8bb07b0f50ca -r 2146cb7be36f rust/landgen/src/outline_template_based/template_based.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/landgen/src/outline_template_based/template_based.rs Tue Aug 22 08:35:46 2023 +0200 @@ -0,0 +1,66 @@ +use super::{outline::OutlinePoints, outline_template::OutlineTemplate}; +use crate::{LandGenerationParameters, LandGenerator}; +use land2d::Land2D; + +pub struct TemplatedLandGenerator { + outline_template: OutlineTemplate, +} + +impl TemplatedLandGenerator { + pub fn new(outline_template: OutlineTemplate) -> Self { + Self { outline_template } + } +} + +impl LandGenerator for TemplatedLandGenerator { + fn generate_land>( + &self, + parameters: &LandGenerationParameters, + random_numbers: &mut I, + ) -> Land2D { + let mut land = Land2D::new(&self.outline_template.size, parameters.basic); + + let mut points = OutlinePoints::from_outline_template( + &self.outline_template, + land.play_box(), + land.size().size(), + random_numbers, + ); + + // mirror + if self.outline_template.can_mirror { + if let Some(b) = random_numbers.next() { + if b & 1 != 0 { + points.mirror(); + } + } + } + + // flip + if self.outline_template.can_flip { + if let Some(b) = random_numbers.next() { + if b & 1 != 0 { + points.flip(); + } + } + } + + if !parameters.skip_distort { + points.distort(parameters.distance_divisor, random_numbers); + } + + if !parameters.skip_bezier { + points.bezierize(5); + } + + points.draw(&mut land, parameters.zero); + + for p in &points.fill_points { + land.fill(*p, parameters.zero, parameters.zero) + } + + points.draw(&mut land, parameters.basic); + + land + } +} diff -r 8bb07b0f50ca -r 2146cb7be36f rust/landgen/src/template_based.rs --- a/rust/landgen/src/template_based.rs Thu Aug 10 20:48:54 2023 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -use crate::{ - outline::OutlinePoints, outline_template::OutlineTemplate, LandGenerationParameters, - LandGenerator, -}; -use integral_geometry::{Point, Size}; -use land2d::Land2D; - -pub struct TemplatedLandGenerator { - outline_template: OutlineTemplate, -} - -impl TemplatedLandGenerator { - pub fn new(outline_template: OutlineTemplate) -> Self { - Self { outline_template } - } -} - -impl LandGenerator for TemplatedLandGenerator { - fn generate_land>( - &self, - parameters: &LandGenerationParameters, - random_numbers: &mut I, - ) -> Land2D { - let mut land = Land2D::new(self.outline_template.size, parameters.basic); - - let mut points = OutlinePoints::from_outline_template( - &self.outline_template, - land.play_box(), - land.size().size(), - random_numbers, - ); - - // mirror - if self.outline_template.can_mirror { - if let Some(b) = random_numbers.next() { - if b & 1 != 0 { - points.mirror(); - } - } - } - - // flip - if self.outline_template.can_flip { - if let Some(b) = random_numbers.next() { - if b & 1 != 0 { - points.flip(); - } - } - } - - if !parameters.skip_distort { - points.distort(parameters.distance_divisor, random_numbers); - } - - if !parameters.skip_bezier { - points.bezierize(5); - } - - points.draw(&mut land, parameters.zero); - - for p in &points.fill_points { - land.fill(*p, parameters.zero, parameters.zero) - } - - points.draw(&mut land, parameters.basic); - - land - } -} diff -r 8bb07b0f50ca -r 2146cb7be36f rust/landgen/src/wavefront_collapse/generator.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/landgen/src/wavefront_collapse/generator.rs Tue Aug 22 08:35:46 2023 +0200 @@ -0,0 +1,336 @@ +use super::tile_image::{Edge, TileImage}; +use super::wavefront_collapse::{CollapseRule, Tile, WavefrontCollapse}; +use crate::{LandGenerationParameters, LandGenerator}; +use integral_geometry::Size; +use png::Decoder; +use std::collections::HashSet; +use std::fs::File; +use std::io::{BufReader, Result}; +use std::path::Path; + +#[derive(Clone)] +pub struct EdgeDescription { + pub name: String, + pub reversed: Option, + pub symmetrical: Option, +} + +#[derive(Clone)] +pub struct EdgesDescription { + pub top: EdgeDescription, + pub right: EdgeDescription, + pub bottom: EdgeDescription, + pub left: EdgeDescription, +} + +#[derive(Clone)] +pub struct TileDescription { + pub name: String, + pub edges: EdgesDescription, + pub is_negative: Option, + pub can_flip: Option, + pub can_mirror: Option, + pub can_rotate90: Option, + pub can_rotate180: Option, + pub can_rotate270: Option, +} + +#[derive(Clone)] +pub struct NonStrictEdgesDescription { + pub top: Option, + pub right: Option, + pub bottom: Option, + pub left: Option, +} + +#[derive(Clone)] +pub struct TemplateDescription { + pub size: Size, + pub tiles: Vec, + pub edges: NonStrictEdgesDescription, + pub wrap: bool, +} + +pub struct WavefrontCollapseLandGenerator { + pub template: TemplateDescription, +} + +impl WavefrontCollapseLandGenerator { + pub fn new(template: TemplateDescription) -> Self { + Self { template } + } + + fn load_image_tiles( + parameters: &LandGenerationParameters, + tile_description: &TileDescription, + ) -> Result>> { + let mut result = Vec::new(); + + let file = File::open( + Path::new("../share/hedgewars/Data/Tiles") + .join(&tile_description.name) + .as_path(), + )?; + let decoder = Decoder::new(BufReader::new(file)); + let mut reader = decoder.read_info().unwrap(); + + let info = reader.info(); + let mut tiles_image = vec2d::Vec2D::new( + &Size::new(info.width as usize, info.height as usize), + parameters.zero, + ); + + let mut buf = vec![0; reader.output_buffer_size()]; + let info = reader.next_frame(&mut buf).unwrap(); + let bytes = &buf[..info.buffer_size()]; + + let mut tiles_image_pixels = tiles_image.as_mut_slice().iter_mut(); + + let (zero, basic) = if tile_description.is_negative.unwrap_or_default() { + (parameters.basic(), parameters.zero()) + } else { + (parameters.zero(), parameters.basic()) + }; + + match info.color_type.samples() { + 1 => { + for line in bytes.chunks_exact(info.line_size) { + for value in line.iter() { + *tiles_image_pixels + .next() + .expect("vec2d size matching image dimensions") = + if *value == 0 { zero } else { basic }; + } + } + } + a => { + for line in bytes.chunks_exact(info.line_size) { + for value in line.chunks_exact(a) { + print!("{:?},", value); + *tiles_image_pixels + .next() + .expect("vec2d size matching image dimensions") = + if value[0] == 0u8 { zero } else { basic }; + } + } + } + } + + let [top_edge, right_edge, bottom_edge, left_edge]: [Edge; 4] = [ + (&tile_description.edges.top).into(), + (&tile_description.edges.right).into(), + (&tile_description.edges.bottom).into(), + (&tile_description.edges.left).into(), + ]; + + let tile = + TileImage::::new(tiles_image, top_edge, right_edge, bottom_edge, left_edge); + + result.push(tile.clone()); + + if tile_description.can_flip.unwrap_or_default() { + result.push(tile.flipped()); + } + if tile_description.can_mirror.unwrap_or_default() { + result.push(tile.mirrored()); + } + if tile_description.can_flip.unwrap_or_default() + && tile_description.can_mirror.unwrap_or_default() + { + result.push(tile.mirrored().flipped()); + } + + if tile_description.can_rotate90.unwrap_or_default() { + result.push(tile.rotated90()); + } + if tile_description.can_rotate180.unwrap_or_default() { + result.push(tile.rotated180()); + } + if tile_description.can_rotate270.unwrap_or_default() { + result.push(tile.rotated270()); + } + + Ok(result) + } + + pub fn load_template( + &self, + parameters: &LandGenerationParameters, + ) -> Vec> { + let mut result = Vec::new(); + + for tile_description in self.template.tiles.iter() { + if let Ok(mut tiles) = Self::load_image_tiles(parameters, tile_description) { + result.append(&mut tiles); + } + } + + result + } + + pub fn build_rules( + &self, + tiles: &[TileImage], + ) -> Vec { + let [grid_top_edge, grid_right_edge, grid_bottom_edge, grid_left_edge]: [Option< + Edge, + >; 4] = [ + self.template.edges.top.as_ref(), + self.template.edges.right.as_ref(), + self.template.edges.bottom.as_ref(), + self.template.edges.left.as_ref(), + ] + .map(|opt| opt.map(|d| d.into())); + + let mut rules = Vec::::new(); + + let default_connection = HashSet::from_iter(vec![Tile::Empty].into_iter()); + for (i, tile) in tiles.iter().enumerate() { + let mut right = default_connection.clone(); + let mut bottom = default_connection.clone(); + let mut left = default_connection.clone(); + let mut top = default_connection.clone(); + + // compatibility with grid edges + if grid_top_edge + .as_ref() + .map(|e| e.is_compatible(tile.top_edge())) + .unwrap_or(true) + { + top.insert(Tile::Outside); + } + if grid_right_edge + .as_ref() + .map(|e| e.is_compatible(tile.right_edge())) + .unwrap_or(true) + { + right.insert(Tile::Outside); + } + if grid_bottom_edge + .as_ref() + .map(|e| e.is_compatible(tile.bottom_edge())) + .unwrap_or(true) + { + bottom.insert(Tile::Outside); + } + if grid_left_edge + .as_ref() + .map(|e| e.is_compatible(tile.left_edge())) + .unwrap_or(true) + { + left.insert(Tile::Outside); + } + + // compatibility with itself + if tile.left_edge().is_compatible(tile.right_edge()) { + left.insert(Tile::Numbered(i)); + right.insert(Tile::Numbered(i)); + } + + if tile.top_edge().is_compatible(tile.bottom_edge()) { + top.insert(Tile::Numbered(i)); + bottom.insert(Tile::Numbered(i)); + } + + // compatibility with previously defined tiles + for p in 0..i { + if tiles[p].left_edge().is_compatible(tile.right_edge()) { + rules[p].left.insert(Tile::Numbered(i)); + right.insert(Tile::Numbered(p)); + } + + if tiles[p].right_edge().is_compatible(tile.left_edge()) { + rules[p].right.insert(Tile::Numbered(i)); + left.insert(Tile::Numbered(p)); + } + + if tiles[p].top_edge().is_compatible(tile.bottom_edge()) { + rules[p].top.insert(Tile::Numbered(i)); + bottom.insert(Tile::Numbered(p)); + } + + if tiles[p].bottom_edge().is_compatible(tile.top_edge()) { + rules[p].bottom.insert(Tile::Numbered(i)); + top.insert(Tile::Numbered(p)); + } + } + + rules.push(CollapseRule { + tile: Tile::Numbered(i), + top, + right, + bottom, + left, + }); + } + + rules + } +} + +impl LandGenerator for WavefrontCollapseLandGenerator { + fn generate_land>( + &self, + parameters: &LandGenerationParameters, + random_numbers: &mut I, + ) -> land2d::Land2D { + let tiles = self.load_template(parameters); + let rules = self.build_rules(&tiles); + + let mut wfc = WavefrontCollapse::new(self.template.wrap); + wfc.set_rules(rules); + + let wfc_size = if let Some(first_tile) = tiles.first() { + let tile_size = first_tile.size(); + + Size::new( + self.template.size.width / tile_size.width, + self.template.size.height / tile_size.height, + ) + } else { + Size::new(1, 1) + }; + + wfc.generate_map(&wfc_size, |_| {}, random_numbers); + + // render tiles into resulting land array + let mut result = land2d::Land2D::new(&self.template.size, parameters.zero); + let offset_y = result.height() - result.play_height(); + let offset_x = (result.width() - result.play_width()) / 2; + + for row in 0..wfc_size.height { + for column in 0..wfc_size.width { + if let Some(Tile::Numbered(tile_index)) = wfc.grid().get(row, column) { + let tile = &tiles[*tile_index]; + + for tile_row in 0..tile.size().height { + for tile_column in 0..tile.size().width { + result.map( + (row * tile.size().height + tile_row + offset_y) as i32, + (column * tile.size().width + tile_column + offset_x) as i32, + |p| { + *p = + *tile.get(tile_row, tile_column).unwrap_or(¶meters.zero) + }, + ); + } + } + } + } + } + + result + } +} + +impl From<&EdgeDescription> for Edge { + fn from(val: &EdgeDescription) -> Self { + let edge = Edge::new(val.name.clone(), val.symmetrical.unwrap_or_default()); + + if val.reversed.unwrap_or_default() { + edge.reversed() + } else { + edge + } + } +} diff -r 8bb07b0f50ca -r 2146cb7be36f rust/landgen/src/wavefront_collapse/mod.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/landgen/src/wavefront_collapse/mod.rs Tue Aug 22 08:35:46 2023 +0200 @@ -0,0 +1,4 @@ +pub mod generator; +mod tile_image; +mod transform; +mod wavefront_collapse; diff -r 8bb07b0f50ca -r 2146cb7be36f rust/landgen/src/wavefront_collapse/tile_image.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/landgen/src/wavefront_collapse/tile_image.rs Tue Aug 22 08:35:46 2023 +0200 @@ -0,0 +1,242 @@ +use super::transform::Transform; +use integral_geometry::Size; +use std::rc::Rc; +use vec2d::Vec2D; + +#[derive(PartialEq, Clone, Debug)] +pub struct Edge { + id: I, + symmetrical: bool, + reverse: bool, +} + +impl Edge { + #[inline] + pub fn new(id: I, symmetrical: bool) -> Self { + Self { + id, + symmetrical, + reverse: false, + } + } + + #[inline] + pub fn reversed(&self) -> Self { + Self { + id: self.id.clone(), + symmetrical: self.symmetrical, + reverse: !self.symmetrical && !self.reverse, + } + } + + #[inline] + pub fn is_compatible(&self, other: &Self) -> bool { + self.id == other.id && ((self.reverse != other.reverse) || self.symmetrical) + } +} + +#[derive(Clone)] +pub struct TileImage { + image: Rc>, + pub transform: Transform, + top: Edge, + right: Edge, + bottom: Edge, + left: Edge, +} + +impl TileImage { + pub fn new( + image: Vec2D, + top: Edge, + right: Edge, + bottom: Edge, + left: Edge, + ) -> Self { + Self { + image: Rc::new(image), + transform: Transform::default(), + top, + right, + bottom, + left, + } + } + + pub fn mirrored(&self) -> Self { + Self { + image: self.image.clone(), + transform: self.transform.mirror(), + top: self.top.reversed(), + right: self.left.reversed(), + bottom: self.bottom.reversed(), + left: self.right.reversed(), + } + } + + pub fn flipped(&self) -> Self { + Self { + image: self.image.clone(), + transform: self.transform.flip(), + top: self.bottom.reversed(), + right: self.right.reversed(), + bottom: self.top.reversed(), + left: self.left.reversed(), + } + } + + pub fn rotated90(&self) -> Self { + Self { + image: self.image.clone(), + transform: self.transform.rotate90(), + top: self.left.clone(), + right: self.top.clone(), + bottom: self.right.clone(), + left: self.bottom.clone(), + } + } + + pub fn rotated180(&self) -> Self { + Self { + image: self.image.clone(), + transform: self.transform.rotate180(), + top: self.bottom.clone(), + right: self.left.clone(), + bottom: self.top.clone(), + left: self.right.clone(), + } + } + + pub fn rotated270(&self) -> Self { + Self { + image: self.image.clone(), + transform: self.transform.rotate270(), + top: self.right.clone(), + right: self.bottom.clone(), + bottom: self.left.clone(), + left: self.top.clone(), + } + } + + #[inline] + pub fn right_edge(&self) -> &Edge { + &self.right + } + + #[inline] + pub fn bottom_edge(&self) -> &Edge { + &self.bottom + } + + #[inline] + pub fn left_edge(&self) -> &Edge { + &self.left + } + + #[inline] + pub fn top_edge(&self) -> &Edge { + &self.top + } + + #[inline] + pub fn size(&self) -> Size { + match self.transform { + Transform::Rotate0(_) => self.image.size(), + Transform::Rotate90(_) => Size::new(self.image.size().height, self.image.size().width), + } + } + + #[inline] + pub fn get(&self, row: usize, column: usize) -> Option<&T> { + match self.transform { + Transform::Rotate0(_) => { + let image_row = if self.transform.is_flipped() { + self.image.height().wrapping_sub(1).wrapping_sub(row) + } else { + row + }; + + let image_column = if self.transform.is_mirrored() { + self.image.width().wrapping_sub(1).wrapping_sub(column) + } else { + column + }; + + self.image.get(image_row, image_column) + } + Transform::Rotate90(_) => { + let image_row = if self.transform.is_mirrored() { + column + } else { + self.image.height().wrapping_sub(1).wrapping_sub(column) + }; + + let image_column = if self.transform.is_flipped() { + self.image.width().wrapping_sub(1).wrapping_sub(row) + } else { + row + }; + + self.image.get(image_row, image_column) + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_edge_new() { + let edge = Edge::new(1, true); + assert_eq!(edge.id, 1); + assert_eq!(edge.symmetrical, true); + assert_eq!(edge.reverse, false); + } + + #[test] + fn test_edge_reversed() { + let edge = Edge::new(1, true); + let reversed = edge.reversed(); + assert_eq!(reversed.id, edge.id); + assert_eq!(reversed.symmetrical, edge.symmetrical); + assert_eq!(reversed.reverse, false); + + let edge = Edge::new(1, false); + let reversed = edge.reversed(); + assert_eq!(reversed.id, edge.id); + assert_eq!(reversed.symmetrical, edge.symmetrical); + assert_eq!(reversed.reverse, true); + } + + #[test] + fn test_edge_equality() { + let edge1 = Edge::new(1, true); + let edge2 = Edge::new(1, true); + assert_eq!(edge1, edge2); + + let edge1 = Edge::new(1, false); + let edge2 = Edge::new(1, false); + assert_eq!(edge1, edge2); + + let edge1 = Edge::new(1, false); + let edge2 = Edge::new(2, false); + assert_ne!(edge1, edge2); + } + + #[test] + fn test_edge_equality_with_reverse() { + let edge1 = Edge::new(1, true); + let edge2 = edge1.reversed(); + assert_eq!(edge1, edge2); + + let edge1 = Edge::new(1, false); + let edge2 = edge1.reversed(); + assert_ne!(edge1, edge2); + + let edge1 = Edge::new(1, true); + let edge2 = edge1.reversed().reversed(); + assert_eq!(edge1, edge2); + } +} diff -r 8bb07b0f50ca -r 2146cb7be36f rust/landgen/src/wavefront_collapse/transform.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/landgen/src/wavefront_collapse/transform.rs Tue Aug 22 08:35:46 2023 +0200 @@ -0,0 +1,214 @@ +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum SymmetryTransform { + Id, + Flip, + Mirror, + FlipMirror, +} + +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum Transform { + Rotate0(SymmetryTransform), + Rotate90(SymmetryTransform), +} + +impl Default for Transform { + fn default() -> Self { + Transform::Rotate0(SymmetryTransform::Id) + } +} + +impl SymmetryTransform { + pub fn mirror(&self) -> Self { + use SymmetryTransform::*; + match self { + Id => Mirror, + Flip => FlipMirror, + Mirror => Id, + FlipMirror => Flip, + } + } + + pub fn flip(&self) -> Self { + use SymmetryTransform::*; + match self { + Id => Flip, + Flip => Id, + Mirror => FlipMirror, + FlipMirror => Mirror, + } + } + + pub fn is_mirrored(&self) -> bool { + use SymmetryTransform::*; + match self { + Id => false, + Flip => false, + Mirror => true, + FlipMirror => true, + } + } + + pub fn is_flipped(&self) -> bool { + use SymmetryTransform::*; + match self { + Id => false, + Flip => true, + Mirror => false, + FlipMirror => true, + } + } +} + +impl Transform { + pub fn new() -> Self { + Self::default() + } + + pub fn mirror(self) -> Transform { + match self { + Transform::Rotate0(s) => Transform::Rotate0(s.mirror()), + Transform::Rotate90(s) => Transform::Rotate90(s.flip()), + } + } + + pub fn flip(self) -> Transform { + match self { + Transform::Rotate0(s) => Transform::Rotate0(s.flip()), + Transform::Rotate90(s) => Transform::Rotate90(s.mirror()), + } + } + + pub fn rotate90(self) -> Transform { + match self { + Transform::Rotate0(s) => Transform::Rotate90(s), + Transform::Rotate90(s) => Transform::Rotate0(s.flip().mirror()), + } + } + + pub fn rotate180(self) -> Transform { + match self { + Transform::Rotate0(s) => Transform::Rotate0(s.flip().mirror()), + Transform::Rotate90(s) => Transform::Rotate90(s.flip().mirror()), + } + } + + pub fn rotate270(self) -> Transform { + match self { + Transform::Rotate0(s) => Transform::Rotate90(s.flip().mirror()), + Transform::Rotate90(s) => Transform::Rotate0(s), + } + } + + pub fn is_mirrored(&self) -> bool { + match self { + Transform::Rotate0(s) => s.is_mirrored(), + Transform::Rotate90(s) => s.is_mirrored(), + } + } + + pub fn is_flipped(&self) -> bool { + match self { + Transform::Rotate0(s) => s.is_flipped(), + Transform::Rotate90(s) => s.is_flipped(), + } + } +} + +#[cfg(test)] +mod tests { + use super::{SymmetryTransform::*, Transform::*, *}; + + // I totally wrote all of this myself and didn't use ChatGPT + #[test] + fn test_default() { + let rt = Transform::new(); + assert_eq!(rt, Rotate0(Id)); + } + + #[test] + fn test_mirror() { + let rt = Rotate90(Flip); + let mirrored = rt.mirror(); + assert_eq!(mirrored, Rotate90(Id)); + } + + #[test] + fn test_flip() { + let rt = Transform::new().rotate180().mirror(); + let flipped = rt.flip(); + assert_eq!(flipped, Rotate0(Id)); + } + + #[test] + fn test_rotate90() { + let rt = Rotate0(Id); + let rotated = rt.rotate90(); + assert_eq!(rotated, Rotate90(Id)); + } + + #[test] + fn test_rotate180() { + let rt = Rotate90(Mirror); + let rotated = rt.rotate180(); + assert_eq!(rotated, Rotate90(Flip)); + } + + #[test] + fn test_rotate270() { + let rt = Transform::new().rotate180().flip(); + let rotated = rt.rotate270(); + assert_eq!(rotated, Rotate90(Flip)); + } + + #[test] + fn test_rotate180_2() { + let rt = Transform::new().rotate180(); + assert_eq!(rt, Rotate0(FlipMirror)); + } + + #[test] + fn test_rotation_chain() { + assert_eq!( + Transform::default(), + Transform::default() + .rotate90() + .rotate90() + .rotate90() + .rotate90() + ); + assert_eq!( + Transform::default().rotate90(), + Transform::default().rotate180().rotate90().rotate180() + ); + assert_eq!( + Transform::default().rotate180(), + Transform::default().rotate180().rotate270().rotate90() + ); + } + + #[test] + fn test_combinations_chain() { + assert_eq!( + Transform::default(), + Transform::default().flip().rotate180().flip().rotate180() + ); + assert_eq!( + Transform::default(), + Transform::default() + .mirror() + .rotate180() + .mirror() + .rotate180() + ); + assert_eq!( + Transform::default(), + Transform::default() + .rotate90() + .flip() + .rotate90() + .mirror() + .rotate180() + ); + } +} diff -r 8bb07b0f50ca -r 2146cb7be36f rust/landgen/src/wavefront_collapse/wavefront_collapse.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/landgen/src/wavefront_collapse/wavefront_collapse.rs Tue Aug 22 08:35:46 2023 +0200 @@ -0,0 +1,187 @@ +use integral_geometry::Size; +use std::collections::HashSet; +use vec2d::Vec2D; + +#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] +pub enum Tile { + Empty, + Outside, + Numbered(usize), +} + +impl Default for Tile { + fn default() -> Self { + Tile::Outside + } +} + +#[derive(Debug)] +pub struct CollapseRule { + pub tile: Tile, + pub right: HashSet, + pub bottom: HashSet, + pub left: HashSet, + pub top: HashSet, +} + +pub struct WavefrontCollapse { + rules: Vec, + grid: Vec2D, + wrap: bool, +} + +impl Default for WavefrontCollapse { + fn default() -> Self { + Self { + rules: Vec::new(), + grid: Vec2D::new(&Size::new(1, 1), Tile::Empty), + wrap: false, + } + } +} + +impl WavefrontCollapse { + pub fn new(wrap: bool) -> Self { + Self { + rules: Vec::new(), + grid: Vec2D::new(&Size::new(1, 1), Tile::Empty), + wrap, + } + } + + pub fn generate_map, F: FnOnce(&mut Vec2D)>( + &mut self, + map_size: &Size, + seed_fn: F, + random_numbers: &mut I, + ) { + self.grid = Vec2D::new(map_size, Tile::Empty); + + seed_fn(&mut self.grid); + + while self.collapse_step(random_numbers) {} + } + + pub fn set_rules(&mut self, rules: Vec) { + self.rules = rules; + } + + fn get_tile(&self, y: usize, x: usize) -> Tile { + let x = if self.wrap { + if x == usize::MAX { + self.grid.width() - 1 + } else if x == self.grid.width() { + 0 + } else { + x + } + } else { + x + }; + + self.grid.get(y, x).copied().unwrap_or_default() + } + + fn collapse_step>(&mut self, random_numbers: &mut I) -> bool { + let mut tiles_to_collapse = (usize::max_value(), Vec::new()); + + // Iterate through the tiles in the land + for x in 0..self.grid.width() { + for y in 0..self.grid.height() { + let current_tile = self.get_tile(y, x); + + if let Tile::Empty = current_tile { + // calc entropy + let right_tile = self.get_tile(y, x + 1); + let bottom_tile = self.get_tile(y + 1, x); + let left_tile = self.get_tile(y, x.wrapping_sub(1)); + let top_tile = self.get_tile(y.wrapping_sub(1), x); + + let possibilities: Vec = self + .rules + .iter() + .filter_map(|rule| { + if rule.right.contains(&right_tile) + && rule.bottom.contains(&bottom_tile) + && rule.left.contains(&left_tile) + && rule.top.contains(&top_tile) + { + Some(rule.tile) + } else { + None + } + }) + .collect(); + + let entropy = possibilities.len(); + if entropy > 0 { + if entropy <= tiles_to_collapse.0 { + let entry = ( + y, + x, + possibilities + [random_numbers.next().unwrap_or_default() as usize % entropy], + ); + + if entropy < tiles_to_collapse.0 { + tiles_to_collapse = (entropy, vec![entry]) + } else { + tiles_to_collapse.1.push(entry) + } + } + } else { + /*println!("We're here: {}, {}", x, y); + println!( + "Neighbour tiles are: {:?} {:?} {:?} {:?}", + right_tile, bottom_tile, left_tile, top_tile + ); + println!("Rules are: {:?}", self.rules);*/ + + //todo!("no collapse possible - what to do?") + } + } + } + } + + let tiles_to_collapse = tiles_to_collapse.1; + let possibilities_number = tiles_to_collapse.len(); + + if possibilities_number > 0 { + let (y, x, tile) = tiles_to_collapse + [random_numbers.next().unwrap_or_default() as usize % possibilities_number]; + + *self + .grid + .get_mut(y, x) + .expect("correct iteration over grid") = tile; + + true + } else { + false + } + } + + pub fn grid(&self) -> &Vec2D { + &self.grid + } +} + +#[cfg(test)] +mod tests { + use super::{Tile, WavefrontCollapse}; + use integral_geometry::Size; + use vec2d::Vec2D; + + #[test] + fn test_wavefront_collapse() { + let size = Size::new(4, 4); + let mut rnd = [0u32; 64].into_iter().cycle(); + let mut wfc = WavefrontCollapse::default(); + + wfc.generate_map(&size, |_| {}, &mut rnd); + + let empty_land = Vec2D::new(&size, Tile::Empty); + + assert_eq!(empty_land.as_slice(), wfc.grid().as_slice()); + } +} diff -r 8bb07b0f50ca -r 2146cb7be36f rust/lfprng/Cargo.toml --- a/rust/lfprng/Cargo.toml Thu Aug 10 20:48:54 2023 -0400 +++ b/rust/lfprng/Cargo.toml Tue Aug 22 08:35:46 2023 +0200 @@ -5,3 +5,4 @@ edition = "2018" [dependencies] +rand = "0.8" diff -r 8bb07b0f50ca -r 2146cb7be36f rust/lfprng/src/lib.rs --- a/rust/lfprng/src/lib.rs Thu Aug 10 20:48:54 2023 -0400 +++ b/rust/lfprng/src/lib.rs Tue Aug 22 08:35:46 2023 +0200 @@ -1,3 +1,5 @@ +use rand::{Error, RngCore, SeedableRng}; + pub struct LaggedFibonacciPRNG { circular_buffer: [u32; 64], index: usize, @@ -5,7 +7,7 @@ impl LaggedFibonacciPRNG { pub fn new(init_values: &[u8]) -> Self { - let mut buf = [0xa98765 + 68; 64]; + let mut buf = [0xa98765; 64]; for i in 0..std::cmp::min(init_values.len(), 54) { buf[i] = init_values[i] as u32; @@ -30,10 +32,17 @@ #[inline] fn get_next(&mut self) -> u32 { + const PRIME_NUM: u32 = 2147483629; + self.index = (self.index + 1) & 0x3f; - self.circular_buffer[self.index] = (self.circular_buffer[(self.index + 40) & 0x3f] - + self.circular_buffer[(self.index + 9) & 0x3f]) - & 0x7fffffff; + let next_value = self.circular_buffer[(self.index + 40) & 0x3f] + + self.circular_buffer[(self.index + 9) & 0x3f]; + + self.circular_buffer[self.index] = if next_value > PRIME_NUM { + next_value - PRIME_NUM + } else { + next_value + }; self.circular_buffer[self.index] } @@ -60,6 +69,32 @@ } } +impl RngCore for LaggedFibonacciPRNG { + fn next_u32(&mut self) -> u32 { + self.get_next().wrapping_add(self.get_next()) + } + + fn next_u64(&mut self) -> u64 { + ((self.next_u32() as u64) << 32) | self.next_u32() as u64 + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + dest.iter_mut().for_each(|x| *x = self.next_u32() as u8); + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } +} + +impl SeedableRng for LaggedFibonacciPRNG { + type Seed = [u8; 32]; + + fn from_seed(seed: Self::Seed) -> Self { + LaggedFibonacciPRNG::new(&seed) + } +} + #[cfg(test)] #[test] fn compatibility() { diff -r 8bb07b0f50ca -r 2146cb7be36f rust/lib-hedgewars-engine/src/instance.rs --- a/rust/lib-hedgewars-engine/src/instance.rs Thu Aug 10 20:48:54 2023 -0400 +++ b/rust/lib-hedgewars-engine/src/instance.rs Tue Aug 22 08:35:46 2023 +0200 @@ -5,7 +5,7 @@ use hedgewars_engine_messages::queue::*; use integral_geometry::{Point, Rect, Size}; -use landgen::outline_template::OutlineTemplate; +use landgen::outline_template_based::outline_template::OutlineTemplate; use std::path::Path; diff -r 8bb07b0f50ca -r 2146cb7be36f rust/lib-hedgewars-engine/src/lib.rs --- a/rust/lib-hedgewars-engine/src/lib.rs Thu Aug 10 20:48:54 2023 -0400 +++ b/rust/lib-hedgewars-engine/src/lib.rs Tue Aug 22 08:35:46 2023 +0200 @@ -5,7 +5,7 @@ mod world; use std::{ - ffi::{CString, CStr}, + ffi::{CStr, CString}, io::{Read, Write}, mem::replace, os::raw::{c_char, c_void}, diff -r 8bb07b0f50ca -r 2146cb7be36f rust/lib-hedgewars-engine/src/render/gear.rs --- a/rust/lib-hedgewars-engine/src/render/gear.rs Thu Aug 10 20:48:54 2023 -0400 +++ b/rust/lib-hedgewars-engine/src/render/gear.rs Tue Aug 22 08:35:46 2023 +0200 @@ -71,22 +71,10 @@ } const SPRITE_LOAD_LIST: &[(SpriteId, &str)] = &[ - ( - SpriteId::Mine, - "Graphics/MineOn.png", - ), - ( - SpriteId::Grenade, - "Graphics/Bomb.png", - ), - ( - SpriteId::Cheese, - "Graphics/cheese.png", - ), - ( - SpriteId::Cleaver, - "Graphics/cleaver.png", - ), + (SpriteId::Mine, "Graphics/MineOn.png"), + (SpriteId::Grenade, "Graphics/Bomb.png"), + (SpriteId::Cheese, "Graphics/cheese.png"), + (SpriteId::Cleaver, "Graphics/cleaver.png"), ]; const MAX_SPRITES: usize = SpriteId::MaxSprite as usize + 1; diff -r 8bb07b0f50ca -r 2146cb7be36f rust/lib-hedgewars-engine/src/world.rs --- a/rust/lib-hedgewars-engine/src/world.rs Thu Aug 10 20:48:54 2023 -0400 +++ b/rust/lib-hedgewars-engine/src/world.rs Tue Aug 22 08:35:46 2023 +0200 @@ -7,8 +7,9 @@ use integral_geometry::{Point, Rect, Size}; use land2d::Land2D; use landgen::{ - outline_template::OutlineTemplate, template_based::TemplatedLandGenerator, - LandGenerationParameters, LandGenerator, + outline_template_based::outline_template::OutlineTemplate, + outline_template_based::template_based::TemplatedLandGenerator, LandGenerationParameters, + LandGenerator, }; use lfprng::LaggedFibonacciPRNG; use std::path::{Path, PathBuf}; @@ -64,9 +65,14 @@ if let Some(ref state) = self.game_state { self.camera.position = state.land.play_box().center(); + let parameters = LandGenerationParameters::new(0u32, 0x8000u32, 0, false, false); let theme = Theme::load(self.data_path.join(Path::new("Themes/Cheese/")).as_path()).unwrap(); - let texture = MapGenerator::new().make_texture(&state.land, &theme); + let texture = MapGenerator::::new().make_texture( + &state.land, + ¶meters, + &theme, + ); if let Some(ref mut renderer) = self.map_renderer { renderer.init(&texture); } diff -r 8bb07b0f50ca -r 2146cb7be36f rust/lib-hwengine-future/Cargo.toml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/lib-hwengine-future/Cargo.toml Tue Aug 22 08:35:46 2023 +0200 @@ -0,0 +1,18 @@ +[package] +name = "lib-hwengine-future" +version = "0.1.0" +edition = "2021" +authors = ["Andrey Korotaev "] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +land2d = { path = "../land2d" } +integral-geometry = { path = "../integral-geometry" } +mapgen = { path = "../mapgen" } +landgen = { path = "../landgen" } +lfprng = { path = "../lfprng" } + +[lib] +name = "hwengine_future" +crate-type = ["dylib"] diff -r 8bb07b0f50ca -r 2146cb7be36f rust/lib-hwengine-future/src/lib.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/lib-hwengine-future/src/lib.rs Tue Aug 22 08:35:46 2023 +0200 @@ -0,0 +1,163 @@ +use integral_geometry::{Point, Size}; + +use landgen::{ + wavefront_collapse::generator::{ + TemplateDescription as WfcTemplate, + }, + LandGenerationParameters, LandGenerator, +}; +use lfprng::LaggedFibonacciPRNG; +use mapgen::{theme::Theme, MapGenerator}; +use std::fs; +use std::{ffi::CStr, path::Path}; + +#[repr(C)] +pub struct GameField { + collision: land2d::Land2D, + pixels: land2d::Land2D, + landgen_parameters: Option>, +} + +#[no_mangle] +pub extern "C" fn get_game_field_parameters( + game_field: &GameField, + width: *mut i32, + height: *mut i32, + play_width: *mut i32, + play_height: *mut i32, +) { + unsafe { + *width = game_field.collision.width() as i32; + *height = game_field.collision.height() as i32; + + *play_width = game_field.collision.play_width() as i32; + *play_height = game_field.collision.play_height() as i32; + } +} + +#[no_mangle] +pub extern "C" fn create_empty_game_field(width: u32, height: u32) -> *mut GameField { + let game_field = Box::new(GameField { + collision: land2d::Land2D::new(&Size::new(width as usize, height as usize), 0), + pixels: land2d::Land2D::new(&Size::new(width as usize, height as usize), 0), + landgen_parameters: None, + }); + + Box::leak(game_field) +} + +#[no_mangle] +pub extern "C" fn generate_templated_game_field( + feature_size: u32, + seed: *const i8, + template_type: *const i8, + data_path: *const i8, +) -> *mut GameField { + let data_path: &str = unsafe { CStr::from_ptr(data_path) }.to_str().unwrap(); + let data_path = Path::new(&data_path); + + let seed: &str = unsafe { CStr::from_ptr(seed) }.to_str().unwrap(); + let template_type: &str = unsafe { CStr::from_ptr(template_type) }.to_str().unwrap(); + + let mut random_numbers_gen = LaggedFibonacciPRNG::new(seed.as_bytes()); + + let yaml_templates = + fs::read_to_string(data_path.join(Path::new("wfc_templates.yaml")).as_path()) + .expect("Error reading map templates file"); + let mut map_gen = MapGenerator::::new(); + map_gen.import_yaml_templates(&yaml_templates); + + let distance_divisor = feature_size.pow(2) / 8 + 10; + let params = LandGenerationParameters::new(0u16, 0x8000u16, distance_divisor, false, false); + let template = map_gen + .get_template(template_type, &mut random_numbers_gen) + .expect("Error reading templates file") + .clone(); + let landgen = map_gen.build_generator(template); + let collision = landgen.generate_land(¶ms, &mut random_numbers_gen); + let size = collision.size().size(); + + let game_field = Box::new(GameField { + collision, + pixels: land2d::Land2D::new(&size, 0), + landgen_parameters: Some(params), + }); + + Box::leak(game_field) +} + +#[no_mangle] +pub extern "C" fn apply_theme( + game_field: &mut GameField, + data_path: *const i8, + theme_name: *const i8, +) { + let data_path: &str = unsafe { CStr::from_ptr(data_path) }.to_str().unwrap(); + let data_path = Path::new(&data_path); + + let theme_name: &str = unsafe { CStr::from_ptr(theme_name) }.to_str().unwrap(); + let map_gen = MapGenerator::<()>::new(); + + let theme = Theme::load( + data_path + .join(Path::new("Themes")) + .join(Path::new(theme_name)) + .as_path(), + ) + .unwrap(); + + let params = game_field + .landgen_parameters + .expect("Land generator parameters specified"); + let pixels = map_gen.make_texture(&game_field.collision, ¶ms, &theme); + + game_field.pixels = pixels.into(); +} + +#[no_mangle] +pub extern "C" fn land_get(game_field: &GameField, x: i32, y: i32) -> u16 { + game_field.collision.get(y, x) +} + +#[no_mangle] +pub extern "C" fn land_set(game_field: &mut GameField, x: i32, y: i32, value: u16) { + game_field.collision.map(y, x, |p| *p = value); +} + +#[no_mangle] +pub extern "C" fn land_row(game_field: &mut GameField, row: i32) -> *mut u16 { + game_field.collision[row as usize].as_mut_ptr() +} + +#[no_mangle] +pub extern "C" fn land_fill( + game_field: &mut GameField, + x: i32, + y: i32, + border_value: u16, + fill_value: u16, +) { + game_field + .collision + .fill(Point::new(x, y), border_value, fill_value) +} + +#[no_mangle] +pub extern "C" fn land_pixel_get(game_field: &GameField, x: i32, y: i32) -> u32 { + game_field.pixels.get(y, x) +} + +#[no_mangle] +pub extern "C" fn land_pixel_set(game_field: &mut GameField, x: i32, y: i32, value: u32) { + game_field.pixels.map(y, x, |p| *p = value); +} + +#[no_mangle] +pub extern "C" fn land_pixel_row(game_field: &mut GameField, row: i32) -> *mut u32 { + game_field.pixels[row as usize].as_mut_ptr() +} + +#[no_mangle] +pub extern "C" fn dispose_game_field(game_field: *mut GameField) { + unsafe { drop(Box::from_raw(game_field)) }; +} diff -r 8bb07b0f50ca -r 2146cb7be36f rust/mapgen/Cargo.toml --- a/rust/mapgen/Cargo.toml Thu Aug 10 20:48:54 2023 -0400 +++ b/rust/mapgen/Cargo.toml Tue Aug 22 08:35:46 2023 +0200 @@ -11,7 +11,7 @@ lfprng = { path = "../lfprng" } integral-geometry = { path = "../integral-geometry" } -rand = "0.5" +rand = "0.8" serde = "1.0" serde_yaml = "0.8" serde_derive = "1.0" diff -r 8bb07b0f50ca -r 2146cb7be36f rust/mapgen/src/lib.rs --- a/rust/mapgen/src/lib.rs Thu Aug 10 20:48:54 2023 -0400 +++ b/rust/mapgen/src/lib.rs Tue Aug 22 08:35:46 2023 +0200 @@ -1,79 +1,24 @@ +mod template; pub mod theme; use self::theme::Theme; -use integral_geometry::{Point, Rect, Size}; -use land2d::Land2D; -use landgen::outline_template::OutlineTemplate; -use rand::{thread_rng, Rng}; -use serde_derive::Deserialize; -use serde_yaml; -use std::{borrow::Borrow, collections::hash_map::HashMap, mem::replace}; -use vec2d::Vec2D; - -#[derive(Deserialize)] -struct PointDesc { - x: u32, - y: u32, -} - -#[derive(Deserialize)] -struct RectDesc { - x: u32, - y: u32, - w: u32, - h: u32, -} - -#[derive(Deserialize)] -struct TemplateDesc { - width: usize, - height: usize, - can_flip: bool, - can_invert: bool, - can_mirror: bool, - is_negative: bool, - put_girders: bool, - max_hedgehogs: u8, - outline_points: Vec>, - fill_points: Vec, -} +use crate::template::outline::TemplateCollectionDesc as OutlineTemplateCollectionDesc; +use crate::template::wavefront_collapse::TemplateCollectionDesc as WfcTemplateCollectionDesc; -#[derive(Deserialize)] -struct TemplateCollectionDesc { - templates: Vec, - template_types: HashMap>, -} +use land2d::Land2D; +use landgen::{ + outline_template_based::{ + outline_template::OutlineTemplate, template_based::TemplatedLandGenerator, + }, + wavefront_collapse::generator::{ + TemplateDescription as WfcTemplate, WavefrontCollapseLandGenerator, + }, + LandGenerationParameters, LandGenerator, +}; +use rand::{seq::SliceRandom, Rng}; -impl From<&TemplateDesc> for OutlineTemplate { - fn from(desc: &TemplateDesc) -> Self { - OutlineTemplate { - islands: desc - .outline_points - .iter() - .map(|v| { - v.iter() - .map(|r| { - Rect::from_size( - Point::new(r.x as i32, r.y as i32), - Size::new(r.w as usize, r.h as usize), - ) - }) - .collect() - }) - .collect(), - fill_points: desc - .fill_points - .iter() - .map(|p| Point::new(p.x as i32, p.y as i32)) - .collect(), - size: Size::new(desc.width, desc.height), - can_flip: desc.can_flip, - can_invert: desc.can_invert, - can_mirror: desc.can_mirror, - is_negative: desc.is_negative, - } - } -} +use std::{borrow::Borrow, collections::hash_map::HashMap}; +use vec2d::Vec2D; #[derive(PartialEq, Eq, Hash, Clone, Debug)] struct TemplateType(String); @@ -85,43 +30,33 @@ } #[derive(Debug)] -pub struct MapGenerator { - pub(crate) templates: HashMap>, +pub struct MapGenerator { + pub(crate) templates: HashMap>, } -impl MapGenerator { +impl MapGenerator { pub fn new() -> Self { Self { templates: HashMap::new(), } } - pub fn import_yaml_templates(&mut self, text: &str) { - let mut desc: TemplateCollectionDesc = serde_yaml::from_str(text).unwrap(); - let templates = replace(&mut desc.templates, vec![]); - self.templates = desc - .template_types - .into_iter() - .map(|(size, indices)| { - ( - TemplateType(size), - indices.iter().map(|i| (&templates[*i]).into()).collect(), - ) - }) - .collect(); + pub fn get_template(&self, template_type: &str, rng: &mut R) -> Option<&T> { + self.templates + .get(template_type) + .and_then(|t| t.as_slice().choose(rng)) } - pub fn get_template(&self, template_type: &str) -> Option<&OutlineTemplate> { - self.templates - .get(template_type) - .and_then(|t| thread_rng().choose(t)) - } - - pub fn make_texture(&self, land: &Land2D, theme: &Theme) -> Vec2D + pub fn make_texture( + &self, + land: &Land2D, + parameters: &LandGenerationParameters, + theme: &Theme, + ) -> Vec2D where LandT: Copy + Default + PartialEq, { - let mut texture = Vec2D::new(land.size().size(), 0); + let mut texture = Vec2D::new(&land.size().size(), 0); if let Some(land_sprite) = theme.land_texture() { for (row_index, (land_row, tex_row)) in land.rows().zip(texture.rows_mut()).enumerate() @@ -131,6 +66,7 @@ while sprite_row.len() < land.width() - x_offset { let copy_range = x_offset..x_offset + sprite_row.len(); tex_row_copy( + parameters.basic(), &land_row[copy_range.clone()], &mut tex_row[copy_range], sprite_row, @@ -142,6 +78,7 @@ if x_offset < land.width() { let final_range = x_offset..land.width(); tex_row_copy( + parameters.basic(), &land_row[final_range.clone()], &mut tex_row[final_range], &sprite_row[..land.width() - x_offset], @@ -158,6 +95,7 @@ let mut offsets = vec![255u8; land.width()]; land_border_pass( + parameters.basic(), land.rows().rev().zip(texture.rows_mut().rev()), &mut offsets, border_width, @@ -170,6 +108,7 @@ offsets.iter_mut().for_each(|v| *v = 255); land_border_pass( + parameters.basic(), land.rows().zip(texture.rows_mut()), &mut offsets, border_width, @@ -181,13 +120,55 @@ } } +impl MapGenerator { + pub fn import_yaml_templates(&mut self, text: &str) { + let mut desc: OutlineTemplateCollectionDesc = serde_yaml::from_str(text).unwrap(); + let templates = std::mem::take(&mut desc.templates); + self.templates = desc + .template_types + .into_iter() + .map(|(size, indices)| { + ( + TemplateType(size), + indices.iter().map(|i| (&templates[*i]).into()).collect(), + ) + }) + .collect(); + } + + pub fn build_generator(&self, template: OutlineTemplate) -> impl LandGenerator { + TemplatedLandGenerator::new(template) + } +} + +impl MapGenerator { + pub fn import_yaml_templates(&mut self, text: &str) { + let mut desc: WfcTemplateCollectionDesc = serde_yaml::from_str(text).unwrap(); + let templates = std::mem::take(&mut desc.templates); + self.templates = desc + .template_types + .into_iter() + .map(|(size, indices)| { + ( + TemplateType(size), + indices.iter().map(|i| (&templates[*i]).into()).collect(), + ) + }) + .collect(); + } + + pub fn build_generator(&self, template: WfcTemplate) -> impl LandGenerator { + WavefrontCollapseLandGenerator::new(template) + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct Color(u32); impl Color { #[inline] fn red(self) -> u8 { - (self.0 >> 0 & 0xFF) as u8 + (self.0 & 0xFF) as u8 } #[inline] @@ -219,11 +200,16 @@ let red = lerp(target.red(), source.red(), source.alpha()); let green = lerp(target.green(), source.green(), source.alpha()); let blue = lerp(target.blue(), source.blue(), source.alpha()); - (red as u32) << 0 | (green as u32) << 8 | (blue as u32) << 16 | (alpha as u32) << 24 + (red as u32) | (green as u32) << 8 | (blue as u32) << 16 | (alpha as u32) << 24 } -fn land_border_pass<'a, LandT, T, F>(rows: T, offsets: &mut [u8], border_width: u8, pixel_getter: F) -where +fn land_border_pass<'a, LandT, T, F>( + basic_value: LandT, + rows: T, + offsets: &mut [u8], + border_width: u8, + pixel_getter: F, +) where LandT: Default + PartialEq + 'a, T: Iterator, F: (Fn(usize, usize) -> u32), @@ -235,7 +221,7 @@ .zip(offsets.iter_mut()) .enumerate() { - *offset_v = if *land_v == LandT::default() { + *offset_v = if *land_v == basic_value { if *offset_v < border_width { *tex_v = blend(pixel_getter(x, *offset_v as usize), *tex_v) } @@ -247,22 +233,23 @@ } } -fn tex_row_copy(land_row: &[LandT], tex_row: &mut [u32], sprite_row: &[u32]) -where +fn tex_row_copy( + basic_value: LandT, + land_row: &[LandT], + tex_row: &mut [u32], + sprite_row: &[u32], +) where LandT: Default + PartialEq, { for ((land_v, tex_v), sprite_v) in land_row.iter().zip(tex_row.iter_mut()).zip(sprite_row) { - *tex_v = if *land_v == LandT::default() { - *sprite_v - } else { - 0 - } + *tex_v = if *land_v == basic_value { *sprite_v } else { 0 } } } #[cfg(test)] mod tests { - use crate::{MapGenerator, TemplateType}; + use crate::{MapGenerator, OutlineTemplate, TemplateType}; + use rand::thread_rng; #[test] fn simple_load() { @@ -296,14 +283,14 @@ test: [0] "#; - let mut generator = MapGenerator::new(); + let mut generator = MapGenerator::::new(); generator.import_yaml_templates(&text); assert!(generator .templates .contains_key(&TemplateType("test".to_string()))); - let template = generator.get_template("test").unwrap(); + let template = generator.get_template("test", &mut thread_rng()).unwrap(); assert_eq!(template.islands[0].len(), 7); } diff -r 8bb07b0f50ca -r 2146cb7be36f rust/mapgen/src/template/mod.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/mapgen/src/template/mod.rs Tue Aug 22 08:35:46 2023 +0200 @@ -0,0 +1,2 @@ +pub mod outline; +pub mod wavefront_collapse; diff -r 8bb07b0f50ca -r 2146cb7be36f rust/mapgen/src/template/outline.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/mapgen/src/template/outline.rs Tue Aug 22 08:35:46 2023 +0200 @@ -0,0 +1,71 @@ +use integral_geometry::{Point, Rect, Size}; + +use landgen::outline_template_based::outline_template::OutlineTemplate; +use serde_derive::Deserialize; + +use std::collections::hash_map::HashMap; + +#[derive(Deserialize)] +pub struct PointDesc { + x: u32, + y: u32, +} + +#[derive(Deserialize)] +pub struct RectDesc { + x: u32, + y: u32, + w: u32, + h: u32, +} + +#[derive(Deserialize)] +pub struct TemplateDesc { + width: usize, + height: usize, + can_flip: bool, + can_invert: bool, + can_mirror: bool, + is_negative: bool, + put_girders: bool, + max_hedgehogs: u8, + outline_points: Vec>, + fill_points: Vec, +} + +#[derive(Deserialize)] +pub struct TemplateCollectionDesc { + pub templates: Vec, + pub template_types: HashMap>, +} + +impl From<&TemplateDesc> for OutlineTemplate { + fn from(desc: &TemplateDesc) -> Self { + OutlineTemplate { + islands: desc + .outline_points + .iter() + .map(|v| { + v.iter() + .map(|r| { + Rect::from_size( + Point::new(r.x as i32, r.y as i32), + Size::new(r.w as usize, r.h as usize), + ) + }) + .collect() + }) + .collect(), + fill_points: desc + .fill_points + .iter() + .map(|p| Point::new(p.x as i32, p.y as i32)) + .collect(), + size: Size::new(desc.width, desc.height), + can_flip: desc.can_flip, + can_invert: desc.can_invert, + can_mirror: desc.can_mirror, + is_negative: desc.is_negative, + } + } +} diff -r 8bb07b0f50ca -r 2146cb7be36f rust/mapgen/src/template/wavefront_collapse.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/mapgen/src/template/wavefront_collapse.rs Tue Aug 22 08:35:46 2023 +0200 @@ -0,0 +1,105 @@ +use integral_geometry::Size; + +use landgen::wavefront_collapse::generator::*; +use serde_derive::Deserialize; + +use std::collections::hash_map::HashMap; + +#[derive(Deserialize)] +#[serde(remote = "EdgeDescription")] +pub struct EdgeDesc { + pub name: String, + pub reversed: Option, + pub symmetrical: Option, +} + +#[derive(Deserialize)] +#[serde(remote = "EdgesDescription")] +pub struct EdgesDesc { + #[serde(with = "EdgeDesc")] + pub top: EdgeDescription, + #[serde(with = "EdgeDesc")] + pub right: EdgeDescription, + #[serde(with = "EdgeDesc")] + pub bottom: EdgeDescription, + #[serde(with = "EdgeDesc")] + pub left: EdgeDescription, +} + +#[derive(Deserialize)] +#[serde(remote = "TileDescription")] +pub struct TileDesc { + pub name: String, + #[serde(with = "EdgesDesc")] + pub edges: EdgesDescription, + pub is_negative: Option, + pub can_flip: Option, + pub can_mirror: Option, + pub can_rotate90: Option, + pub can_rotate180: Option, + pub can_rotate270: Option, +} + +#[derive(Deserialize)] +pub struct TileDescriptionHelper(#[serde(with = "TileDesc")] TileDescription); +#[derive(Deserialize)] +pub struct EdgeDescriptionHelper(#[serde(with = "EdgeDesc")] EdgeDescription); + +#[derive(Deserialize)] +pub struct NonStrictEdgesDesc { + pub top: Option, + pub right: Option, + pub bottom: Option, + pub left: Option, +} + +#[derive(Deserialize)] +pub struct TemplateDesc { + pub width: usize, + pub height: usize, + pub can_invert: bool, + pub is_negative: bool, + pub put_girders: bool, + pub max_hedgehogs: u8, + pub wrap: bool, + pub edges: Option, + pub tiles: Vec, +} + +#[derive(Deserialize)] +pub struct TemplateCollectionDesc { + pub templates: Vec, + pub template_types: HashMap>, +} + +impl From<&TemplateDesc> for TemplateDescription { + fn from(desc: &TemplateDesc) -> Self { + let [top, right, bottom, left] = if let Some(edges) = &desc.edges { + [ + edges.top.as_ref(), + edges.right.as_ref(), + edges.bottom.as_ref(), + edges.left.as_ref(), + ] + .map(|e| e.map(|EdgeDescriptionHelper(e)| e.clone())) + } else { + [None, None, None, None] + }; + + Self { + size: Size::new(desc.width, desc.height), + tiles: desc + .tiles + .iter() + .map(|TileDescriptionHelper(t)| t.clone()) + .collect(), + wrap: desc.wrap, + edges: NonStrictEdgesDescription { + top, + right, + bottom, + left, + }, + } + } +} diff -r 8bb07b0f50ca -r 2146cb7be36f rust/mapgen/src/theme.rs --- a/rust/mapgen/src/theme.rs Thu Aug 10 20:48:54 2023 -0400 +++ b/rust/mapgen/src/theme.rs Tue Aug 22 08:35:46 2023 +0200 @@ -48,7 +48,7 @@ pub fn to_transposed(&self) -> ThemeSprite { let size = self.size().transpose(); - let mut pixels = Vec2D::new(size, 0u32); + let mut pixels = Vec2D::new(&size, 0u32); for (y, row) in self.pixels.rows().enumerate() { for (x, v) in row.iter().enumerate() { pixels[x][y] = *v; @@ -238,7 +238,7 @@ } let size = Size::new(info.width as usize, info.height as usize); - let mut pixels: Vec2D = Vec2D::new(size, 0); + let mut pixels: Vec2D = Vec2D::new(&size, 0); reader.next_frame(slice_u32_to_u8_mut(pixels.as_mut_slice()))?; Ok(ThemeSprite { pixels }) diff -r 8bb07b0f50ca -r 2146cb7be36f rust/vec2d/src/lib.rs --- a/rust/vec2d/src/lib.rs Thu Aug 10 20:48:54 2023 -0400 +++ b/rust/vec2d/src/lib.rs Tue Aug 22 08:35:46 2023 +0200 @@ -1,9 +1,10 @@ +use integral_geometry::Size; use std::{ ops::{Index, IndexMut}, - slice::SliceIndex + slice::SliceIndex, }; -use integral_geometry::Size; +#[derive(Debug)] pub struct Vec2D { data: Vec, size: Size, @@ -33,7 +34,7 @@ } } -impl Vec2D { +impl Vec2D { #[inline] pub fn width(&self) -> usize { self.size.width @@ -51,8 +52,11 @@ } impl Vec2D { - pub fn new(size: Size, value: T) -> Self { - Self { size, data: vec![value; size.area()] } + pub fn new(size: &Size, value: T) -> Self { + Self { + size: *size, + data: vec![value; size.area()], + } } #[inline] @@ -67,21 +71,41 @@ #[inline] pub fn get(&self, row: usize, column: usize) -> Option<&>::Output> { - self.data.get(row * self.width() + column) + if row < self.height() && column < self.width() { + Some(unsafe { self.data.get_unchecked(row * self.width() + column) }) + } else { + None + } } #[inline] - pub fn get_mut(&mut self, row: usize, column: usize) -> Option<&mut >::Output> { - self.data.get_mut(row * self.size.width + column) + pub fn get_mut( + &mut self, + row: usize, + column: usize, + ) -> Option<&mut >::Output> { + if row < self.height() && column < self.width() { + Some(unsafe { self.data.get_unchecked_mut(row * self.size.width + column) }) + } else { + None + } } #[inline] - pub unsafe fn get_unchecked(&self, row: usize, column: usize) -> &>::Output { + pub unsafe fn get_unchecked( + &self, + row: usize, + column: usize, + ) -> &>::Output { self.data.get_unchecked(row * self.width() + column) } #[inline] - pub unsafe fn get_unchecked_mut(&mut self, row: usize, column: usize) -> &mut >::Output { + pub unsafe fn get_unchecked_mut( + &mut self, + row: usize, + column: usize, + ) -> &mut >::Output { self.data.get_unchecked_mut(row * self.size.width + column) } @@ -98,11 +122,8 @@ #[inline] pub unsafe fn as_bytes(&self) -> &[u8] { - use std::{ - slice, - mem - }; - + use std::{mem, slice}; + slice::from_raw_parts( self.data.as_ptr() as *const u8, self.data.len() * mem::size_of::(), @@ -122,6 +143,17 @@ } } +impl Vec2D { + pub fn from_iter>(iter: I, size: &Size) -> Option> { + let data: Vec = iter.into_iter().collect(); + if size.width * size.height == data.len() { + Some(Vec2D { data, size: *size }) + } else { + None + } + } +} + #[cfg(test)] mod tests { use super::*; diff -r 8bb07b0f50ca -r 2146cb7be36f share/hedgewars/Data/Tiles/120_bar.png Binary file share/hedgewars/Data/Tiles/120_bar.png has changed diff -r 8bb07b0f50ca -r 2146cb7be36f share/hedgewars/Data/Tiles/120_corner.png Binary file share/hedgewars/Data/Tiles/120_corner.png has changed diff -r 8bb07b0f50ca -r 2146cb7be36f share/hedgewars/Data/Tiles/120_filled.png Binary file share/hedgewars/Data/Tiles/120_filled.png has changed diff -r 8bb07b0f50ca -r 2146cb7be36f share/hedgewars/Data/Tiles/120_two_corners.png Binary file share/hedgewars/Data/Tiles/120_two_corners.png has changed diff -r 8bb07b0f50ca -r 2146cb7be36f share/hedgewars/Data/map_templates.yaml --- a/share/hedgewars/Data/map_templates.yaml Thu Aug 10 20:48:54 2023 -0400 +++ b/share/hedgewars/Data/map_templates.yaml Tue Aug 22 08:35:46 2023 +0200 @@ -2053,7 +2053,7 @@ - {x: 3925, y: 2098, w: 75, h: 50} - {x: 4050, y: 2173, w: 50, h: 75} fill_points: - - {x: 4095, y: 0} + - {x: 4094, y: 0} @@ -2086,9 +2086,9 @@ fill_points: - {x: 1, y: 90} - {x: 1, y: 500} - - {x: 4095, y: 500} + - {x: 4094, y: 500} - {x: 1, y: 1200} - - {x: 4095, y: 1200} + - {x: 4094, y: 1200} - {x: 1, y: 2010} diff -r 8bb07b0f50ca -r 2146cb7be36f share/hedgewars/Data/wfc_templates.yaml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/hedgewars/Data/wfc_templates.yaml Tue Aug 22 08:35:46 2023 +0200 @@ -0,0 +1,196 @@ +--- +# Templates for wavefront collapse map generator in hedgewars + +templates: + - &template_00 + width: 3960 + height: 1920 + can_invert: false + is_negative: false + put_girders: true + max_hedgehogs: 40 + wrap: true + edges: + bottom: + name: "ff" + symmetrical: true + tiles: &template_00_tiles + - name: "120_bar.png" + edges: + top: + name: "ff" + symmetrical: true + right: + name: "fe" + bottom: + name: "ee" + symmetrical: true + left: + name: "fe" + reversed: true + is_negative: true + can_mirror: false + can_flip: false + can_rotate90: true + can_rotate180: true + can_rotate270: true + - name: "120_corner.png" + edges: + top: + name: "fe" + right: + name: "ee" + symmetrical: true + bottom: + name: "ee" + symmetrical: true + left: + name: "fe" + reversed: true + is_negative: true + can_mirror: false + can_flip: false + can_rotate90: true + can_rotate180: true + can_rotate270: true + - name: "120_corner.png" + edges: + top: + name: "fe" + reversed: true + right: + name: "ff" + symmetrical: true + bottom: + name: "ff" + symmetrical: true + left: + name: "fe" + is_negative: false + can_mirror: false + can_flip: false + can_rotate90: true + can_rotate180: true + can_rotate270: true + - name: "120_filled.png" + edges: + top: + name: "ff" + symmetrical: true + right: + name: "ff" + symmetrical: true + bottom: + name: "ff" + symmetrical: true + left: + name: "ff" + symmetrical: true + is_negative: true + can_mirror: false + can_flip: false + can_rotate90: false + can_rotate180: false + can_rotate270: false + - name: "120_filled.png" + edges: + top: + name: "ee" + symmetrical: true + right: + name: "ee" + symmetrical: true + bottom: + name: "ee" + symmetrical: true + left: + name: "ee" + symmetrical: true + is_negative: false + can_mirror: false + can_flip: false + can_rotate90: false + can_rotate180: false + can_rotate270: false + - name: "120_two_corners.png" + edges: + top: + name: "fe" + right: + name: "fe" + reversed: true + bottom: + name: "fe" + left: + name: "fe" + reversed: true + is_negative: true + can_mirror: true + can_flip: false + can_rotate90: false + can_rotate180: false + can_rotate270: false + + - &template_01 + width: 3960 + height: 1920 + can_invert: false + is_negative: false + put_girders: true + max_hedgehogs: 40 + wrap: false + edges: &open_edges + top: + name: "ee" + symmetrical: true + right: + name: "ee" + symmetrical: true + bottom: + name: "ff" + symmetrical: true + left: + name: "ee" + symmetrical: true + tiles: *template_00_tiles + + - &template_02 + width: 1200 + height: 600 + can_invert: false + is_negative: false + put_girders: true + max_hedgehogs: 24 + wrap: false + edges: *open_edges + tiles: *template_00_tiles + + - &template_03 + width: 720 + height: 7920 + can_invert: false + is_negative: false + put_girders: true + max_hedgehogs: 64 + wrap: false + edges: *open_edges + tiles: *template_00_tiles + + + - &template_04 + width: 2200 + height: 960 + can_invert: false + is_negative: false + put_girders: true + max_hedgehogs: 24 + wrap: false + edges: *open_edges + tiles: *template_00_tiles + +template_types: + small: [2] + medium: [4] + large: [1] + cavern: [0] + wacky: [3]