# HG changeset patch # User Stepan777 # Date 1343325407 -14400 # Node ID 9bb6abdb567541ca0c6381aeef28c44f593b90c9 # Parent bc3306c59a0892991c61ef429ddf65db52c33b59# Parent a46ce1812419c724b6b9fd049ca727443cbfb36e merge diff -r bc3306c59a08 -r 9bb6abdb5675 CMakeLists.txt --- a/CMakeLists.txt Fri Jul 13 16:39:20 2012 +0400 +++ b/CMakeLists.txt Thu Jul 26 21:56:47 2012 +0400 @@ -159,10 +159,19 @@ set(CMAKE_CXX_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE}) set(CMAKE_CXX_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG}) -separate_arguments(fpflags_full UNIX_COMMAND ${FPFLAGS}) +#parse additional parameters +if(FPFLAGS OR GHFLAGS) + math(EXPR cmake_version "${CMAKE_MAJOR_VERSION}*10000 + ${CMAKE_MINOR_VERSION}*100 + ${CMAKE_PATCH_VERSION}") + if(cmake_version LESS "020800") + message(STATUS "FPFLAGS and GHFLAGS are available only from Cmake 2.8, ignoring...") + else() + separate_arguments(fpflags_full UNIX_COMMAND ${FPFLAGS}) + separate_arguments(ghflags_full UNIX_COMMAND ${GHFLAGS}) + endif() +endif() + set(pascal_flags ${fpflags_full} "-B" "-FE../bin" "-Cs2000000" "-vewn" "-dDEBUGFILE" ${pascal_flags}) -separate_arguments(ghflags_full UNIX_COMMAND ${GHFLAGS}) -set(haskell_flags "-O2" ${haskell_flags} ${ghflags_full}) +set(haskell_flags "-O2" ${ghflags_full} ${haskell_flags}) if(Optz) # set(pascal_flags "-O3" "-OpPENTIUM4" "-CfSSE3" "-Xs" "-Si" ${pascal_flags}) diff -r bc3306c59a08 -r 9bb6abdb5675 QTfrontend/binds.cpp --- a/QTfrontend/binds.cpp Fri Jul 13 16:39:20 2012 +0400 +++ b/QTfrontend/binds.cpp Thu Jul 26 21:56:47 2012 +0400 @@ -62,6 +62,7 @@ {"confirm", "y", QT_TRANSLATE_NOOP("binds", "confirmation"), NULL, NULL}, {"+voldown", "9", QT_TRANSLATE_NOOP("binds", "volume down"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Modify the game's volume while playing:")}, {"+volup", "0", QT_TRANSLATE_NOOP("binds", "volume up"), NULL, NULL}, + {"mute", "8", QT_TRANSLATE_NOOP("binds", "mute audio"), NULL, NULL}, {"fullscr", "f12", QT_TRANSLATE_NOOP("binds", "change mode"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Toggle fullscreen mode:")}, {"capture", "c", QT_TRANSLATE_NOOP("binds", "capture"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Take a screenshot:")}, {"rotmask", "delete", QT_TRANSLATE_NOOP("binds", "hedgehogs\ninfo"), NULL, QT_TRANSLATE_NOOP("binds (descriptions)", "Toggle labels above hedgehogs:")}, diff -r bc3306c59a08 -r 9bb6abdb5675 QTfrontend/model/ammoSchemeModel.h --- a/QTfrontend/model/ammoSchemeModel.h Fri Jul 13 16:39:20 2012 +0400 +++ b/QTfrontend/model/ammoSchemeModel.h Thu Jul 26 21:56:47 2012 +0400 @@ -47,8 +47,8 @@ public slots: void Save(); - signals: - void dataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight); +// signals: +// void dataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight); protected: QList< QList > schemes; diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/GSHandlers.inc --- a/hedgewars/GSHandlers.inc Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/GSHandlers.inc Thu Jul 26 21:56:47 2012 +0400 @@ -116,12 +116,12 @@ if lastGearByUID = HH^.Gear then lastGearByUID := nil; - - RemoveGearFromList(HH^.Gear); + + HH^.Gear^.Message:= HH^.Gear^.Message or gmRemoveFromList; with HH^.Gear^ do begin Z := cHHZ; - Active := false; + HH^.Gear^.Active:= false; State:= State and (not (gstHHDriven or gstAttacking or gstAttacked)); Message := Message and (not gmAttack); end; @@ -733,7 +733,14 @@ //////////////////////////////////////////////////////////////////////////////// procedure doStepGrave(Gear: PGear); begin + if (Gear^.Message and gmDestroy) <> 0 then + begin + DeleteGear(Gear); + exit + end; + AllInactive := false; + if Gear^.dY.isNegative then if TestCollisionY(Gear, -1) then Gear^.dY := _0; @@ -2080,6 +2087,7 @@ dX, dY: HWFloat; hog: PHedgehog; sparkles: PVisualGear; + gi: PGear; begin k := Gear^.Kind; exBoom := false; @@ -2114,6 +2122,23 @@ end else begin + if (Gear^.Pos <> posCaseHealth) and (GameTicks and $3FF = 0) then // stir it up every second or so + begin + gi := GearsList; + while gi <> nil do + begin + if gi^.Kind = gtGenericFaller then + begin + gi^.Active:= true; + gi^.X:= int2hwFloat(GetRandom(rightX-leftX)+leftX); + gi^.Y:= int2hwFloat(GetRandom(LAND_HEIGHT-topY)+topY); + gi^.dX:= _90-(GetRandomf*_360); + gi^.dY:= _90-(GetRandomf*_360) + end; + gi := gi^.NextGear + end + end; + if Gear^.Timer = 500 then begin (* Can't make sparkles team coloured without working out what the next team is going to be. This should be solved, really, since it also screws up @@ -2381,7 +2406,7 @@ //DrawExplosion(gX, gY, 4); if ((GameTicks and $7) = 0) and (Random(2) = 0) then - for i:= 1 to Random(2)+1 do + for i:= Random(2) downto 0 do AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke); if Gear^.Health > 0 then @@ -2395,7 +2420,7 @@ begin DrawExplosion(gX, gY, 4); - for i:= 0 to Random(3) do + for i:= Random(3) downto 0 do AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke); end; @@ -2413,20 +2438,12 @@ if not sticky then begin if ((GameTicks and $3) = 0) and (Random(1) = 0) then - begin - for i:= 1 to Random(2)+1 do - begin + for i:= Random(2) downto 0 do AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke); - end; - end; end else - begin - for i:= 0 to Random(3) do - begin + for i:= Random(3) downto 0 do AddVisualGear(gX - 3 + Random(6), gY - 2, vgtSmoke); - end; - end; DeleteGear(Gear) end; @@ -2775,10 +2792,9 @@ Gear^.Message := Gear^.Message and (not gmSwitch); State := HHGear^.State; HHGear^.State := 0; + HHGear^.Z := cHHZ; HHGear^.Active := false; - HHGear^.Z := cHHZ; - RemoveGearFromList(HHGear); - InsertGearToList(HHGear); + HHGear^.Message:= HHGear^.Message or gmRemoveFromList or gmAddToList; PlaySound(sndSwitchHog); @@ -2794,8 +2810,7 @@ HHGear^.Active := true; FollowGear := HHGear; HHGear^.Z := cCurrHHZ; - RemoveGearFromList(HHGear); - InsertGearToList(HHGear); + HHGear^.Message:= HHGear^.Message or gmRemoveFromList or gmAddToList; Gear^.X := HHGear^.X; Gear^.Y := HHGear^.Y end; @@ -2940,7 +2955,7 @@ end end; AfterAttack; - DeleteGear(HHGear); + HHGear^.Message:= HHGear^.Message or gmDestroy; DeleteGear(Gear); end else @@ -2984,7 +2999,6 @@ //////////////////////////////////////////////////////////////////////////////// const cakeh = 27; - cakeDmg = 75; var CakePoints: array[0..Pred(cakeh)] of record x, y: hwFloat; @@ -3068,6 +3082,19 @@ if Gear^.Tag < 7 then exit; + dec(Gear^.Health); + Gear^.Timer := Gear^.Health*10; + if Gear^.Health mod 100 = 0 then + Gear^.PortalCounter:= 0; + // This is not seconds, but at least it is *some* feedback + if (Gear^.Health = 0) or ((Gear^.Message and gmAttack) <> 0) then + begin + FollowGear := Gear; + Gear^.RenderTimer := false; + Gear^.doStep := @doStepCakeDown; + exit + end; + cakeStep(Gear); if Gear^.Tag = 0 then @@ -3079,18 +3106,6 @@ CakePoints[CakeI].y := Gear^.Y; Gear^.DirAngle := DxDy2Angle(tdx, tdy); end; - - dec(Gear^.Health); - Gear^.Timer := Gear^.Health*10; - if Gear^.Health mod 100 = 0 then - Gear^.PortalCounter:= 0; - // This is not seconds, but at least it is *some* feedback - if (Gear^.Health = 0) or ((Gear^.Message and gmAttack) <> 0) then - begin - FollowGear := Gear; - Gear^.RenderTimer := false; - Gear^.doStep := @doStepCakeDown - end end; procedure doStepCakeUp(Gear: PGear); @@ -4296,7 +4311,7 @@ and (CurAmmoGear^.Kind =gtRope) then CurAmmoGear^.PortalCounter:= 1; - if not isbullet + if not isbullet and (iterator^.State and gstInvisible = 0) and (iterator^.Kind <> gtFlake) then FollowGear := iterator; @@ -4375,7 +4390,7 @@ Gear^.State := Gear^.State and (not gstMoving); if (Land[y, x] and lfBouncy <> 0) - or not CalcSlopeTangent(Gear, x, y, tx, ty, 255) + or (not CalcSlopeTangent(Gear, x, y, tx, ty, 255)) or (DistanceI(tx,ty) < _12) then // reject shots at too irregular terrain begin loadNewPortalBall(Gear, true); @@ -4655,11 +4670,13 @@ // add some fire to the tunnel if getRandom(6) = 0 then - AddGear(x - Gear^.Radius + LongInt(getRandom(2 * Gear^.Radius)), y - - getRandom(Gear^.Radius + 1), gtFlame, gsttmpFlag, _0, _0, 0); + begin + tmp:= GetRandom(2 * Gear^.Radius); + AddGear(x - Gear^.Radius + tmp, y - GetRandom(Gear^.Radius + 1), gtFlame, gsttmpFlag, _0, _0, 0) + end end; - if getRandom(100) = 0 then + if random(100) = 0 then AddVisualGear(x, y, vgtSmokeTrace); end else dec(Gear^.Health, 5); // if underwater get additional damage @@ -5069,6 +5086,7 @@ if (hh^.Gear^.Health = 0) and (hh^.Gear^.Damage = 0) then hh^.Gear^.Damage:= 1; RenderHealth(hh^); + RecountTeamHealth(hh^.Team); inc(graves.ar^[Gear^.Tag]^.Health); inc(Gear^.Tag) {-for i:= 0 to High(graves) do begin @@ -5088,12 +5106,13 @@ resgear^.Hedgehog := graves.ar^[i]^.Hedgehog; resgear^.Health := graves.ar^[i]^.Health; PHedgehog(graves.ar^[i]^.Hedgehog)^.Gear := resgear; - DeleteGear(graves.ar^[i]); + graves.ar^[i]^.Message:= graves.ar^[i]^.Message or gmDestroy; + graves.ar^[i]^.Active:= true; RenderHealth(resgear^.Hedgehog^); RecountTeamHealth(resgear^.Hedgehog^.Team); resgear^.Hedgehog^.Effects[heResurrected]:= 1; // only make hat-less hedgehogs look like zombies, preserve existing hats - + if resgear^.Hedgehog^.Hat = 'NoHat' then LoadHedgehogHat(resgear, 'Reserved/Zombie'); end; @@ -5532,3 +5551,41 @@ end end; end; + +procedure doStepAddAmmo(Gear: PGear); +var a: TAmmoType; + gi: PGear; +begin +if Gear^.Timer > 0 then dec(Gear^.Timer) +else + begin + if Gear^.Pos = posCaseUtility then + a:= GetUtility(Gear^.Hedgehog) + else + a:= GetAmmo(Gear^.Hedgehog); + CheckSum:= CheckSum xor GameTicks; + gi := GearsList; + while gi <> nil do + begin + with gi^ do CheckSum:= CheckSum xor X.round xor X.frac xor dX.round xor dX.frac xor Y.round xor Y.frac xor dY.round xor dY.frac; + AddRandomness(CheckSum); + gi := gi^.NextGear + end; + AddPickup(Gear^.Hedgehog^, a, Gear^.Power, hwRound(Gear^.X), hwRound(Gear^.Y)); + DeleteGear(Gear) + end; +end; + +procedure doStepGenericFaller(Gear: PGear); +begin +if Gear^.Timer < $FFFFFFFF then + if Gear^.Timer > 0 then + dec(Gear^.Timer) + else + begin + DeleteGear(Gear); + exit + end; + +doStepFallingGear(Gear); +end; diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/hwengine.pas --- a/hedgewars/hwengine.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/hwengine.pas Thu Jul 26 21:56:47 2012 +0400 @@ -32,8 +32,6 @@ uses SDLh, uMisc, uConsole, uGame, uConsts, uLand, uAmmos, uVisualGears, uGears, uStore, uWorld, uInputHandler, uSound, uScript, uTeams, uStats, uIO, uLocale, uChat, uAI, uAIMisc, uRandom, uLandTexture, uCollisions, SysUtils, uTypes, uVariables, uCommands, uUtils, uCaptions, uDebug, uCommandHandlers, uLandPainted - {$IFDEF USE_VIDEO_RECORDING}, uVideoRec {$ENDIF} - {$IFDEF SDL13}, uTouch{$ENDIF}{$IFDEF ANDROID}, GLUnit{$ENDIF}; {$IFDEF HWLIBRARY} procedure initEverything(complete:boolean); @@ -461,6 +459,7 @@ uAI.initModule; //uAIActions does not need initialization //uAIAmmoTests does not need initialization + uAILandMarks.initModule; uAIMisc.initModule; uAmmos.initModule; uChat.initModule; @@ -492,6 +491,7 @@ begin WriteLnToConsole('Freeing resources...'); uAI.freeModule; + uAILandMarks.freeModule; uAIMisc.freeModule; //stub uCaptions.freeModule; uWorld.freeModule; diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uAI.pas --- a/hedgewars/uAI.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uAI.pas Thu Jul 26 21:56:47 2012 +0400 @@ -31,7 +31,7 @@ implementation uses uConsts, SDLh, uAIMisc, uAIAmmoTests, uAIActions, uAmmos, SysUtils{$IFNDEF USE_SDLTHREADS} {$IFDEF UNIX}, cthreads{$ENDIF} {$ENDIF}, uTypes, - uVariables, uCommands, uUtils, uDebug; + uVariables, uCommands, uUtils, uDebug, uAILandMarks; var BestActions: TActions; CanUseAmmo: array [TAmmoType] of boolean; @@ -191,7 +191,14 @@ AddAction(BestActions, aia_attack, aim_push, 650 + random(300), 0, 0); AddAction(BestActions, aia_attack, aim_release, ap.Power, 0, 0); end; - + + if (Ammoz[a].Ammo.Propz and ammoprop_Track) <> 0 then + begin + AddAction(BestActions, aia_waitAmmoXY, 0, 12, ap.ExplX, ap.ExplY); + AddAction(BestActions, aia_attack, aim_push, 1, 0, 0); + AddAction(BestActions, aia_attack, aim_release, 7, 0, 0); + end; + if ap.ExplR > 0 then AddAction(BestActions, aia_AwareExpl, ap.ExplR, 10, ap.ExplX, ap.ExplY); end @@ -205,7 +212,7 @@ end; procedure Walk(Me: PGear; var Actions: TActions); -const FallPixForBranching = cHHRadius * 2 + 8; +const FallPixForBranching = cHHRadius; var ticks, maxticks, steps, tmp: Longword; BaseRate, BestRate, Rate: integer; @@ -268,6 +275,7 @@ if (BotLevel < 5) and (GoInfo.JumpType = jmpHJump) then // hjump support if Push(ticks, Actions, AltMe, Me^.Message) then + begin with Stack.States[Pred(Stack.Count)] do begin if Me^.dX.isNegative then @@ -283,11 +291,21 @@ else AddAction(MadeActions, aia_LookRight, 0, 200, 0, 0); end; + + // check if we could go backwards and maybe ljump over a gap after this hjump + Push(ticks, Stack.States[Pred(Stack.Count)].MadeActions, AltMe, Me^.Message xor 3) + end; if (BotLevel < 3) and (GoInfo.JumpType = jmpLJump) then // ljump support begin - // push current position so we proceed from it after checking jump opportunities + // at final check where we go after jump walking backward + if Push(ticks, Actions, AltMe, Me^.Message xor 3) then + with Stack.States[Pred(Stack.Count)] do + AddAction(MadeActions, aia_LJump, 0, 305 + random(50), 0, 0); + + // push current position so we proceed from it after checking jump+forward walk opportunities if CanGo then Push(ticks, Actions, Me^, Me^.Message); - // first check where we go after jump + + // first check where we go after jump walking forward if Push(ticks, Actions, AltMe, Me^.Message) then with Stack.States[Pred(Stack.Count)] do AddAction(MadeActions, aia_LJump, 0, 305 + random(50), 0, 0); @@ -310,8 +328,16 @@ end else if Rate < BestRate then break; + if ((Me^.State and gstAttacked) = 0) and ((steps mod 4) = 0) then + begin + if (steps > 4) and checkMark(hwRound(Me^.X), hwRound(Me^.Y), markWasHere) then + break; + addMark(hwRound(Me^.X), hwRound(Me^.Y), markWasHere); + TestAmmos(Actions, Me, true); + end; + if GoInfo.FallPix >= FallPixForBranching then Push(ticks, Actions, Me^, Me^.Message xor 3); // aia_Left xor 3 = aia_Right end {while}; @@ -408,7 +434,7 @@ end end; -PGear(Me)^.State:= PGear(Me)^.State and not gstHHThinking; +PGear(Me)^.State:= PGear(Me)^.State and (not gstHHThinking); Think:= 0; InterlockedDecrement(hasThread) end; @@ -419,7 +445,9 @@ or isInMultiShoot then exit; -//DeleteCI(Me); // this might break demo +//DeleteCI(Me); // this will break demo/netplay +clearAllMarks; + Me^.State:= Me^.State or gstHHThinking; Me^.Message:= 0; @@ -476,12 +504,11 @@ end else begin - (* - if not scoreShown then + {if not scoreShown then begin if BestActions.Score > 0 then ParseCommand('/say Expected score = ' + inttostr(BestActions.Score div 1024), true); scoreShown:= true - end;*) + end;} ProcessAction(BestActions, Gear) end else if ((GameTicks - StartTicks) > cMaxAIThinkTime) diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uAIActions.pas --- a/hedgewars/uAIActions.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uAIActions.pas Thu Jul 26 21:56:47 2012 +0400 @@ -44,6 +44,7 @@ aia_Wait = $8009; aia_Put = $800A; aia_waitAngle = $800B; + aia_waitAmmoXY = $800C; aim_push = $8000; aim_release = $8001; @@ -115,19 +116,19 @@ procedure AddAction(var Actions: TActions; Action: Longword; Param: LongInt; TimeDelta: Longword; X, Y: LongInt); begin -with Actions do - begin - actions[Count].Action:= Action; - actions[Count].Param:= Param; - actions[Count].X:= X; - actions[Count].Y:= Y; - if Count > 0 then - actions[Count].Time:= TimeDelta - else - actions[Count].Time:= GameTicks + TimeDelta; - inc(Count); - TryDo(Count < MAXACTIONS, 'AI: actions overflow', true); - end +if Actions.Count < MAXACTIONS then + with Actions do + begin + actions[Count].Action:= Action; + actions[Count].Param:= Param; + actions[Count].X:= X; + actions[Count].Y:= Y; + if Count > 0 then + actions[Count].Time:= TimeDelta + else + actions[Count].Time:= GameTicks + TimeDelta; + inc(Count); + end end; procedure CheckHang(Me: PGear); @@ -234,6 +235,10 @@ aia_waitAngle: if Me^.Angle <> Abs(Param) then exit; + + aia_waitAmmoXY: + if (CurAmmoGear <> nil) and ((hwRound(CurAmmoGear^.X) <> X) or (hwRound(CurAmmoGear^.Y) <> Y)) then exit; + end else begin diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uAIAmmoTests.pas --- a/hedgewars/uAIAmmoTests.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uAIAmmoTests.pas Thu Jul 26 21:56:47 2012 +0400 @@ -50,6 +50,7 @@ function TestAirAttack(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt; function TestTeleport(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt; function TestHammer(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt; +function TestCake(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt; type TAmmoTestProc = function (Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt; TAmmoTest = record @@ -84,7 +85,7 @@ (proc: nil; flags: 0), // amSwitch (proc: @TestMortar; flags: 0), // amMortar (proc: nil; flags: 0), // amKamikaze - (proc: nil; flags: 0), // amCake + (proc: @TestCake; flags: amtest_OnTurn or amtest_NoTarget), // amCake (proc: nil; flags: 0), // amSeduction (proc: @TestWatermelon; flags: 0), // amWatermelon (proc: nil; flags: 0), // amHellishBomb @@ -121,7 +122,7 @@ const BadTurn = Low(LongInt) div 4; implementation -uses uAIMisc, uVariables, uUtils; +uses uAIMisc, uVariables, uUtils, uGearsHandlers, uCollisions; function Metric(x1, y1, x2, y2: LongInt): LongInt; inline; begin @@ -708,19 +709,19 @@ x:= hwRound(Me^.X); y:= hwRound(Me^.Y); - a:= 0; + a:= cMaxAngle div 2; valueResult:= 0; - while a <= cMaxAngle div 2 do + while a >= 0 do begin dx:= sin(a / cMaxAngle * pi) * 0.5; dy:= cos(a / cMaxAngle * pi) * 0.5; - v1:= RateShove(Me, x - 10, y - , 33, 30, 115 + v1:= RateShove(Me, x - 10, y + 2 + , 32, 30, 115 , -dx, -dy, trackFall); - v2:= RateShove(Me, x + 10, y - , 33, 30, 115 + v2:= RateShove(Me, x + 10, y + 2 + , 32, 30, 115 , dx, -dy, trackFall); if (v1 > valueResult) or (v2 > valueResult) then if (v2 > v1) @@ -735,7 +736,7 @@ valueResult:= v1 end; - a:= a + 15 + random(cMaxAngle div 16) + a:= a - 15 - random(cMaxAngle div 16) end; if valueResult <= 0 then @@ -755,17 +756,17 @@ ap.Time:= 0; ap.Power:= 1; x:= hwRound(Me^.X); - y:= hwRound(Me^.Y); + y:= hwRound(Me^.Y) + 4; v1:= 0; for i:= 0 to 8 do begin - v1:= v1 + RateShove(Me, x - 10, y - 10 * i - , 18, 30, 40 + v1:= v1 + RateShove(Me, x - 5, y - 10 * i + , 19, 30, 40 , -0.45, -0.9, trackFall or afSetSkip); end; - v1:= v1 + RateShove(Me, x - 10, y - 90 - , 18, 30, 40 + v1:= v1 + RateShove(Me, x - 5, y - 90 + , 19, 30, 40 , -0.45, -0.9, trackFall); @@ -773,12 +774,12 @@ v2:= 0; for i:= 0 to 8 do begin - v2:= v2 + RateShove(Me, x + 10, y - 10 * i - , 18, 30, 40 + v2:= v2 + RateShove(Me, x + 5, y - 10 * i + , 19, 30, 40 , 0.45, -0.9, trackFall or afSetSkip); end; - v2:= v2 + RateShove(Me, x + 10, y - 90 - , 18, 30, 40 + v2:= v2 + RateShove(Me, x + 5, y - 90 + , 19, 30, 40 , 0.45, -0.9, trackFall); if (v2 > v1) @@ -817,7 +818,7 @@ {first RateShove checks farthermost of two whip's AmmoShove attacks to encourage distant attacks (damaged hog is excluded from view of second RateShove call)} - v1:= RateShove(Me, x - 15, y + v1:= RateShove(Me, x - 13, y , 30, 30, 25 , -1, -0.8, trackFall or afSetSkip); v1:= v1 + @@ -825,7 +826,7 @@ , 30, 30, 25 , -1, -0.8, trackFall); // now try opposite direction - v2:= RateShove(Me, x + 15, y + v2:= RateShove(Me, x + 13, y , 30, 30, 25 , 1, -0.8, trackFall or afSetSkip); v2:= v2 + @@ -981,4 +982,74 @@ end; end; + +procedure checkCakeWalk(Me, Gear: PGear; var ap: TAttackParams); +var i: Longword; + v: LongInt; +begin +while (not TestColl(hwRound(Gear^.X), hwRound(Gear^.Y), 6)) and (Gear^.Y.Round < LAND_HEIGHT) do + Gear^.Y:= Gear^.Y + _1; + +for i:= 0 to 2040 do + begin + cakeStep(Gear); + v:= RateExplosion(Me, hwRound(Gear^.X), hwRound(Gear^.Y), cakeDmg * 2, afTrackFall); + if v > ap.Power then + begin + ap.ExplX:= hwRound(Gear^.X); + ap.ExplY:= hwRound(Gear^.Y); + ap.Power:= v + end + end; +end; + +function TestCake(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt; +var valueResult, v1, v2: LongInt; + x, y, trackFall: LongInt; + cake: TGear; +begin + Level:= Level; // avoid compiler hint + ap.ExplR:= 0; + ap.Time:= 0; + ap.Power:= BadTurn; // use it as max score value in checkCakeWalk + + FillChar(cake, sizeof(cake), 0); + cake.Radius:= 7; + cake.CollisionMask:= $FF7F; + + // check left direction + cake.Angle:= 3; + cake.dX.isNegative:= true; + cake.X:= Me^.X - _3; + cake.Y:= Me^.Y; + checkCakeWalk(Me, @cake, ap); + v1:= ap.Power; + + // now try opposite direction + cake.Angle:= 1; + cake.dX.isNegative:= false; + cake.X:= Me^.X + _3; + cake.Y:= Me^.Y; + checkCakeWalk(Me, @cake, ap); + v2:= ap.Power; + + ap.Power:= 1; + + if (v2 > v1) then + begin + ap.Angle:= 1; + valueResult:= v2 + end + else + begin + ap.Angle:= -1; + valueResult:= v1 + end; + + if valueResult <= 0 then + valueResult:= BadTurn; + + TestCake:= valueResult; +end; + end. diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uAILandMarks.pas --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hedgewars/uAILandMarks.pas Thu Jul 26 21:56:47 2012 +0400 @@ -0,0 +1,71 @@ +unit uAILandMarks; + +interface +const markWasHere = $01; + +procedure addMark(X, Y: LongInt; mark: byte); +function checkMark(X, Y: LongInt; mark: byte) : boolean; +procedure clearAllMarks; +procedure clearMarks(mark: byte); + +procedure initModule; +procedure freeModule; + +implementation +uses uVariables; + +const gr = 2; + +var marks: array of array of byte; + WIDTH, HEIGHT: Longword; + +procedure addMark(X, Y: LongInt; mark: byte); +begin + if((X and LAND_WIDTH_MASK) = 0) and ((Y and LAND_HEIGHT_MASK) = 0) then + begin + X:= X shr gr; + Y:= Y shr gr; + marks[Y, X]:= marks[Y, X] or mark + end +end; + +function checkMark(X, Y: LongInt; mark: byte) : boolean; +begin + checkMark:= ((X and LAND_WIDTH_MASK) = 0) + and ((Y and LAND_HEIGHT_MASK) = 0) + and ((marks[Y shr gr, X shr gr] and mark) <> 0) +end; + +procedure clearAllMarks; +var + Y, X: Longword; +begin + for Y:= 0 to Pred(HEIGHT) do + for X:= 0 to Pred(WIDTH) do + marks[Y, X]:= 0 +end; + +procedure clearMarks(mark: byte); +var + Y, X: Longword; +begin + for Y:= 0 to Pred(HEIGHT) do + for X:= 0 to Pred(WIDTH) do + marks[Y, X]:= marks[Y, X] and (not mark) +end; + + +procedure initModule; +begin + WIDTH:= LAND_WIDTH shr gr; + HEIGHT:= LAND_HEIGHT shr gr; + + SetLength(marks, HEIGHT, WIDTH); +end; + +procedure freeModule; +begin + SetLength(marks, 0, 0); +end; + +end. diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uAIMisc.pas --- a/hedgewars/uAIMisc.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uAIMisc.pas Thu Jul 26 21:56:47 2012 +0400 @@ -170,7 +170,7 @@ begin case Gear^.Kind of gtCase: - AddBonus(hwRound(Gear^.X), hwRound(Gear^.Y), 33, 25); + AddBonus(hwRound(Gear^.X), hwRound(Gear^.Y) + 3, 37, 25); gtFlame: if (Gear^.State and gsttmpFlag) <> 0 then AddBonus(hwRound(Gear^.X), hwRound(Gear^.Y), 20, -50); @@ -371,13 +371,13 @@ x:= x + dX; y:= y + dY; dY:= dY + cGravityf; -(* - if ((trunc(y) and LAND_HEIGHT_MASK) = 0) and ((trunc(x) and LAND_WIDTH_MASK) = 0) then + +{ if ((trunc(y) and LAND_HEIGHT_MASK) = 0) and ((trunc(x) and LAND_WIDTH_MASK) = 0) then begin LandPixels[trunc(y), trunc(x)]:= v; UpdateLandTexture(trunc(X), 1, trunc(Y), 1, true); - end; -*) + end;} + // consider adding dX/dY calc here for fall damage if TestCollExcludingObjects(trunc(x), trunc(y), cHHRadius) then @@ -439,21 +439,21 @@ end; if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI if Score > 0 then - inc(rate, KillScore + Score div 10) // Add a bit of a bonus for bigger hog drownings + inc(rate, (KillScore + Score div 10) * 1024) // Add a bit of a bonus for bigger hog drownings else - dec(rate, KillScore * friendlyfactor div 100 - Score div 10) // and more of a punishment for drowning bigger friendly hogs + dec(rate, (KillScore * friendlyfactor div 100 - Score div 10) * 1024) // and more of a punishment for drowning bigger friendly hogs else if (dmg+fallDmg) >= abs(Score) then if Score > 0 then - inc(rate, KillScore) + inc(rate, KillScore * 1024 + (dmg + fallDmg)) // tiny bonus for dealing more damage than needed to kill else - dec(rate, KillScore * friendlyfactor div 100) + dec(rate, KillScore * friendlyfactor div 100 * 1024) else if Score > 0 then - inc(rate, dmg+fallDmg) - else dec(rate, (dmg+fallDmg) * friendlyfactor div 100) + inc(rate, (dmg + fallDmg) * 1024) + else dec(rate, (dmg + fallDmg) * friendlyfactor div 100 * 1024) end; end; -RateExplosion:= rate * 1024; +RateExplosion:= rate; end; function RateShove(Me: PGear; x, y, r, power, kick: LongInt; gdX, gdY: real; Flags: LongWord): LongInt; @@ -624,6 +624,12 @@ end; 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; + UpdateLandTexture(hwRound(Gear^.X), 1, hwRound(Gear^.Y), 1, true); + end;} + if not (hwRound(Gear^.Y) + cHHRadius < cWaterLine) then exit(false); if (Gear^.State and gstMoving) <> 0 then @@ -645,7 +651,7 @@ Gear^.Y:= Gear^.Y + Gear^.dY; if (not Gear^.dY.isNegative) and (TestCollisionYwithGear(Gear, 1) <> 0) then begin - Gear^.State:= Gear^.State and not (gstMoving or gstHHJumping); + Gear^.State:= Gear^.State and (not (gstMoving or gstHHJumping)); Gear^.dY:= _0; case JumpType of jmpHJump: @@ -673,6 +679,7 @@ var pX, pY, tY: LongInt; begin HHGo:= false; +Gear^.CollisionMask:= $FF7F; AltGear^:= Gear^; GoInfo.Ticks:= 0; @@ -680,6 +687,12 @@ GoInfo.JumpType:= jmpNone; tY:= hwRound(Gear^.Y); 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; + UpdateLandTexture(hwRound(Gear^.X), 1, hwRound(Gear^.Y), 1, true); + end;} + pX:= hwRound(Gear^.X); pY:= hwRound(Gear^.Y); if pY + cHHRadius >= cWaterLine then @@ -696,7 +709,7 @@ Gear^.dY:= Gear^.dY + cGravity; if Gear^.dY > _0_4 then begin - Goinfo.FallPix:= 0; + GoInfo.FallPix:= 0; // try ljump instead of fall with damage HHJump(AltGear, jmpLJump, GoInfo); if AltGear^.Hedgehog^.BotLevel < 4 then @@ -709,7 +722,7 @@ if TestCollisionYwithGear(Gear, 1) <> 0 then begin inc(GoInfo.Ticks, 410); - Gear^.State:= Gear^.State and not (gstMoving or gstHHJumping); + Gear^.State:= Gear^.State and (not (gstMoving or gstHHJumping)); Gear^.dY:= _0; // try ljump instead of fall HHJump(AltGear, jmpLJump, GoInfo); diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uAmmos.pas --- a/hedgewars/uAmmos.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uAmmos.pas Thu Jul 26 21:56:47 2012 +0400 @@ -374,7 +374,7 @@ with CurWeapon^ do begin s:= trammo[Ammoz[AmmoType].NameId]; - if (Count <> AMMO_INFINITE) and not (Hedgehog.Team^.ExtDriven or (Hedgehog.BotLevel > 0)) then + if (Count <> AMMO_INFINITE) and (not (Hedgehog.Team^.ExtDriven or (Hedgehog.BotLevel > 0))) then s:= s + ' (' + IntToStr(Count) + ')'; if (Propz and ammoprop_Timerable) <> 0 then s:= s + ', ' + IntToStr(Timer div 1000) + ' ' + trammo[sidSeconds]; @@ -386,7 +386,7 @@ end else begin - if Gear <> nil then Gear^.State:= Gear^.State and not gstHHChooseTarget; + if Gear <> nil then Gear^.State:= Gear^.State and (not gstHHChooseTarget); isCursorVisible:= false end; end diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uCommandHandlers.pas --- a/hedgewars/uCommandHandlers.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uCommandHandlers.pas Thu Jul 26 21:56:47 2012 +0400 @@ -413,18 +413,19 @@ end; procedure chNextTurn(var s: shortstring); -var checksum: Longword; +var i: Longword; gi: PGear; begin s:= s; // avoid compiler hint TryDo(AllInactive, '/nextturn called when not all gears are inactive', true); - checksum:= GameTicks; + CheckSum:= CheckSum xor GameTicks; gi := GearsList; while gi <> nil do begin - with gi^ do checksum:= checksum xor X.round xor X.frac xor dX.round xor dX.frac xor Y.round xor Y.frac xor dY.round xor dY.frac; + with gi^ do CheckSum:= CheckSum xor X.round xor X.frac xor dX.round xor dX.frac xor Y.round xor Y.frac xor dY.round xor dY.frac; + AddRandomness(CheckSum); gi := gi^.NextGear end; @@ -432,11 +433,11 @@ begin s[0]:= #5; s[1]:= 'N'; - SDLNet_Write32(checksum, @s[2]); + SDLNet_Write32(CheckSum, @s[2]); SendIPC(s) end else - TryDo(checksum = lastTurnChecksum, 'Desync detected', true); + TryDo(CheckSum = lastTurnChecksum, 'Desync detected', true); AddFileLog('Next turn: time '+inttostr(GameTicks)); end; @@ -664,6 +665,7 @@ procedure chSpeedup_p(var s: shortstring); begin s:= s; // avoid compiler hint +SpeedStart:= RealTicks; isSpeed:= true end; @@ -776,7 +778,7 @@ procedure chGameFlags(var s: shortstring); begin GameFlags:= StrToInt(s); -if GameFlags and gfSharedAmmo <> 0 then GameFlags:= GameFlags and not gfPerHogAmmo +if GameFlags and gfSharedAmmo <> 0 then GameFlags:= GameFlags and (not gfPerHogAmmo) end; procedure chHedgehogTurnTime(var s: shortstring); @@ -797,21 +799,21 @@ procedure initModule; begin //////// Begin top sorted by freq analysis not including chatmsg - RegisterVariable('+right' , @chRight_p , false); - RegisterVariable('-right' , @chRight_m , false); - RegisterVariable('+up' , @chUp_p , false); - RegisterVariable('-up' , @chUp_m , false); - RegisterVariable('+left' , @chLeft_p , false); - RegisterVariable('-left' , @chLeft_m , false); + RegisterVariable('+right' , @chRight_p , false, true); + RegisterVariable('-right' , @chRight_m , false, true); + RegisterVariable('+up' , @chUp_p , false, true); + RegisterVariable('-up' , @chUp_m , false, true); + RegisterVariable('+left' , @chLeft_p , false, true); + RegisterVariable('-left' , @chLeft_m , false, true); RegisterVariable('+attack' , @chAttack_p , false); - RegisterVariable('+down' , @chDown_p , false); - RegisterVariable('-down' , @chDown_m , false); - RegisterVariable('hjump' , @chHJump , false); - RegisterVariable('ljump' , @chLJump , false); + RegisterVariable('+down' , @chDown_p , false, true); + RegisterVariable('-down' , @chDown_m , false, true); + RegisterVariable('hjump' , @chHJump , false, true); + RegisterVariable('ljump' , @chLJump , false, true); RegisterVariable('nextturn', @chNextTurn , false); RegisterVariable('-attack' , @chAttack_m , false); RegisterVariable('slot' , @chSlot , false); - RegisterVariable('setweap' , @chSetWeapon , false); + RegisterVariable('setweap' , @chSetWeapon , false, true); //////// End top by freq analysis RegisterVariable('gencmd' , @chGenCmd , false); RegisterVariable('flag' , @chFlag , false); @@ -857,10 +859,10 @@ RegisterVariable('zoomout' , @chZoomOut , true ); RegisterVariable('zoomreset',@chZoomReset , true ); RegisterVariable('ammomenu', @chAmmoMenu , true); - RegisterVariable('+precise', @chPrecise_p , false); - RegisterVariable('-precise', @chPrecise_m , false); + RegisterVariable('+precise', @chPrecise_p , false, true); + RegisterVariable('-precise', @chPrecise_m , false, true); RegisterVariable('switch' , @chSwitch , false); - RegisterVariable('timer' , @chTimer , false); + RegisterVariable('timer' , @chTimer , false, true); RegisterVariable('taunt' , @chTaunt , false); RegisterVariable('put' , @chPut , false); RegisterVariable('+volup' , @chVol_p , true ); diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uCommands.pas --- a/hedgewars/uCommands.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uCommands.pas Thu Jul 26 21:56:47 2012 +0400 @@ -27,26 +27,31 @@ procedure initModule; 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); procedure ParseTeamCommand(s: shortstring); procedure StopMessages(Message: Longword); implementation -uses uConsts, uVariables, uConsole, uUtils, uDebug; +uses uConsts, uVariables, uConsole, uUtils, uDebug, SDLh; type PVariable = ^TVariable; TVariable = record Next: PVariable; Name: string[15]; Handler: TCommandHandler; - Trusted: boolean; + Trusted, Rand: boolean; end; var Variables: PVariable; procedure RegisterVariable(Name: shortstring; p: TCommandHandler; Trusted: boolean); +begin +RegisterVariable(Name, p, Trusted, false); +end; +procedure RegisterVariable(Name: shortstring; p: TCommandHandler; Trusted: boolean; Rand: boolean); var value: PVariable; begin @@ -56,6 +61,7 @@ value^.Name:= Name; value^.Handler:= p; value^.Trusted:= Trusted; +value^.Rand:= Rand; if Variables = nil then Variables:= value @@ -81,13 +87,18 @@ s:= ''; SplitBySpace(CmdStr, s); AddFileLog('[Cmd] ' + CmdStr + ' (' + inttostr(length(s)) + ')'); + t:= Variables; while t <> nil do begin if t^.Name = CmdStr then begin if TrustedSource or t^.Trusted then + begin + if t^.Rand and (not CheckNoTeamOrHH) then + CheckSum:= CheckSum xor LongWord(SDLNet_Read32(@CmdStr)) xor LongWord(s[0]) xor GameTicks; t^.Handler(s); + end; exit end else diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uConsts.pas --- a/hedgewars/uConsts.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uConsts.pas Thu Jul 26 21:56:47 2012 +0400 @@ -147,6 +147,7 @@ cBarrelHealth = 60; cShotgunRadius = 22; cBlowTorchC = 6; + cakeDmg = 75; cKeyMaxIndex = 1023; cKbdMaxIndex = 65536;//need more room for the modifier keys @@ -228,20 +229,23 @@ gstHHGone = $00100000; gstInvisible = $00200000; - gmLeft = $00000001; - gmRight = $00000002; - gmUp = $00000004; - gmDown = $00000008; - gmSwitch = $00000010; - gmAttack = $00000020; - gmLJump = $00000040; - gmHJump = $00000080; - gmDestroy= $00000100; - gmSlot = $00000200; // with param - gmWeapon = $00000400; // with param - gmTimer = $00000800; // with param - gmAnimate= $00001000; // with param - gmPrecise= $00002000; + gmLeft = $00000001; + gmRight = $00000002; + gmUp = $00000004; + gmDown = $00000008; + gmSwitch = $00000010; + gmAttack = $00000020; + gmLJump = $00000040; + gmHJump = $00000080; + gmDestroy = $00000100; + gmSlot = $00000200; // with param + gmWeapon = $00000400; // with param + gmTimer = $00000800; // with param + gmAnimate = $00001000; // with param + gmPrecise = $00002000; + + gmRemoveFromList = $00004000; + gmAddToList = $00008000; gmAllStoppable = gmLeft or gmRight or gmUp or gmDown or gmAttack or gmPrecise; cMaxSlotIndex = 9; @@ -264,6 +268,7 @@ ammoprop_NeedUpDown = $00008000;//Used by TouchInterface to show or hide up/down widgets ammoprop_OscAim = $00010000; ammoprop_NoMoveAfter = $00020000; + ammoprop_Track = $00040000; ammoprop_NoRoundEnd = $10000000; AMMO_INFINITE = 100; diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uGame.pas --- a/hedgewars/uGame.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uGame.pas Thu Jul 26 21:56:47 2012 +0400 @@ -48,7 +48,14 @@ if (GameType = gmtDemo) then if isSpeed then - Lag:= Lag * 10 + Lag:= Lag * 10 + i:= RealTicks-SpeedStart; + if i < 2000 then Lag:= Lag*5 + else if i < 4000 then Lag:= Lag*10 + else if i < 6000 then Lag:= Lag*20 + else if i < 8000 then Lag:= Lag*40 + else Lag:= Lag*80; + end else if cOnlyStats then Lag:= High(LongInt); diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uGears.pas --- a/hedgewars/uGears.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uGears.pas Thu Jul 26 21:56:47 2012 +0400 @@ -182,7 +182,7 @@ end; procedure ProcessGears; -var Gear, t: PGear; +var t: PGear; i, AliveCount: LongInt; s: shortstring; begin @@ -203,21 +203,29 @@ t:= GearsList; while t <> nil do begin - Gear:= t; - t:= Gear^.NextGear; + curHandledGear:= t; + t:= curHandledGear^.NextGear; - if Gear^.Active then + if curHandledGear^.Message and gmRemoveFromList <> 0 then begin - if Gear^.RenderTimer and (Gear^.Timer > 500) and ((Gear^.Timer mod 1000) = 0) then + RemoveGearFromList(curHandledGear); + // since I can't think of any good reason this would ever be separate from a remove from list, going to keep it inside this block + if curHandledGear^.Message and gmAddToList <> 0 then InsertGearToList(curHandledGear); + curHandledGear^.Message:= curHandledGear^.Message and (not (gmRemoveFromList or gmAddToList)) + end; + if curHandledGear^.Active then + begin + if curHandledGear^.RenderTimer and (curHandledGear^.Timer > 500) and ((curHandledGear^.Timer mod 1000) = 0) then begin - FreeTexture(Gear^.Tex); - Gear^.Tex:= RenderStringTex(inttostr(Gear^.Timer div 1000), cWhiteColor, fntSmall); + FreeTexture(curHandledGear^.Tex); + curHandledGear^.Tex:= RenderStringTex(inttostr(curHandledGear^.Timer div 1000), cWhiteColor, fntSmall); end; - Gear^.doStep(Gear); + curHandledGear^.doStep(curHandledGear); // might be useful later //ScriptCall('onGearStep', Gear^.uid); end end; +curHandledGear:= nil; if AllInactive then case step of @@ -453,7 +461,7 @@ if (not CurrentTeam^.ExtDriven) or CurrentTeam^.hasGone then inc(hiTicks) // we do not recieve a message for this end; - +AddRandomness(CheckSum); ScriptCall('onGameTick'); if GameTicks mod 20 = 0 then ScriptCall('onGameTick20'); inc(GameTicks) @@ -580,7 +588,8 @@ end; procedure AddMiscGears; -var i: Longword; +var i,rx, ry: Longword; + rdx, rdy: hwFloat; Gear: PGear; begin AddGear(0, 0, gtATStartGame, 0, _0, _0, 2000); @@ -625,6 +634,13 @@ if (GameFlags and gfArtillery) <> 0 then cArtillery:= true; +for i:= GetRandom(10)+30 downto 0 do + begin rx:= GetRandom(rightX-leftX)+leftX; + ry:= GetRandom(LAND_HEIGHT-topY)+topY; + rdx:= _90-(GetRandomf*_360); + rdy:= _90-(GetRandomf*_360); + AddGear(rx, ry, gtGenericFaller, gstInvisible, rdx, rdy, $FFFFFFFF); + end; if not hasBorder and ((Theme = 'Snow') or (Theme = 'Christmas')) then for i:= 0 to Pred(vobCount*2) do @@ -1313,7 +1329,9 @@ @doStepStructure, @doStepLandGun, @doStepTardis, - @doStepIceGun); + @doStepIceGun, + @doStepAddAmmo, + @doStepGenericFaller); begin doStepHandlers:= handlers; @@ -1322,6 +1340,8 @@ CurAmmoGear:= nil; GearsList:= nil; + curHandledGear:= nil; + KilledHHs:= 0; SuddenDeath:= false; SuddenDeathDmg:= false; diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uGearsHandlers.pas --- a/hedgewars/uGearsHandlers.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uGearsHandlers.pas Thu Jul 26 21:56:47 2012 +0400 @@ -29,16 +29,18 @@ uses SDLh, uFloat, uCollisions; + + const dirs: array[0..3] of TPoint = ((X: 0; Y: -1), (X: 1; Y: 0),(X: 0; Y: 1),(X: -1; Y: 0)); procedure PrevAngle(Gear: PGear; dA: LongInt); inline; begin - Gear^.Angle := (LongInt(Gear^.Angle) + 4 - dA) mod 4 + Gear^.Angle := (Gear^.Angle - dA) and 3 end; procedure NextAngle(Gear: PGear; dA: LongInt); inline; begin - Gear^.Angle := (LongInt(Gear^.Angle) + 4 + dA) mod 4 + Gear^.Angle := (Gear^.Angle + dA) and 3 end; procedure cakeStep(Gear: PGear); @@ -50,8 +52,8 @@ dA := hwSign(Gear^.dX); xx := dirs[Gear^.Angle].x; yy := dirs[Gear^.Angle].y; - xxn := dirs[(LongInt(Gear^.Angle) + 4 + dA) mod 4].x; - yyn := dirs[(LongInt(Gear^.Angle) + 4 + dA) mod 4].y; + xxn := dirs[(Gear^.Angle + dA) and 3].x; + yyn := dirs[(Gear^.Angle + dA) and 3].y; if (xx = 0) then if TestCollisionYwithGear(Gear, yy) <> 0 then diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uGearsHedgehog.pas --- a/hedgewars/uGearsHedgehog.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uGearsHedgehog.pas Thu Jul 26 21:56:47 2012 +0400 @@ -28,6 +28,7 @@ procedure doStepHedgehogMoving(Gear: PGear); procedure HedgehogChAngle(HHGear: PGear); procedure PickUp(HH, Gear: PGear); +procedure AddPickup(HH: THedgehog; ammo: TAmmoType; cnt, X, Y: LongWord); implementation uses uConsts, uVariables, uFloat, uAmmos, uSound, uCaptions, @@ -565,15 +566,41 @@ end end; +procedure AddPickup(HH: THedgehog; ammo: TAmmoType; cnt, X, Y: LongWord); +var s: shortstring; + vga: PVisualGear; +begin + PlaySound(sndShotgunReload); + if cnt <> 0 then AddAmmo(HH, ammo, cnt) + else AddAmmo(HH, ammo); + + if (not (HH.Team^.ExtDriven + or (HH.BotLevel > 0))) + or (HH.Team^.Clan^.ClanIndex = LocalClan) + or (GameType = gmtDemo) then + begin + if cnt <> 0 then + s:= trammo[Ammoz[ammo].NameId] + ' (+' + IntToStr(cnt) + ')' + else + s:= trammo[Ammoz[ammo].NameId] + ' (+' + IntToStr(Ammoz[ammo].NumberInCase) + ')'; + AddCaption(s, HH.Team^.Clan^.Color, capgrpAmmoinfo); + + // show ammo icon + vga:= AddVisualGear(X, Y, vgtAmmo); + if vga <> nil then + vga^.Frame:= Longword(ammo); + end; +end; + //////////////////////////////////////////////////////////////////////////////// procedure PickUp(HH, Gear: PGear); var s: shortstring; a: TAmmoType; i: LongInt; vga: PVisualGear; + ag, gi: PGear; begin Gear^.Message:= gmDestroy; -PlaySound(sndShotgunReload); if (Gear^.Pos and posCaseExplode) <> 0 then if (Gear^.Pos and posCasePoison) <> 0 then doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 25, HH^.Hedgehog, EXPLAutoSound + EXPLPoisoned) @@ -585,39 +612,36 @@ case Gear^.Pos of posCaseUtility, posCaseAmmo: begin - if Gear^.AmmoType <> amNothing then a:= Gear^.AmmoType + if Gear^.AmmoType <> amNothing then + begin + AddPickup(HH^.Hedgehog^, Gear^.AmmoType, Gear^.Power, hwRound(Gear^.X), hwRound(Gear^.Y)); + end else + or (GameType = gmtDemo) then begin - for i:= 0 to GameTicks and $7F do - GetRandom(2); // Burn some random numbers - if Gear^.Pos = posCaseUtility then - a:= GetUtility(HH^.Hedgehog) - else - a:= GetAmmo(HH^.Hedgehog) +// Add spawning here... + AddRandomness(GameTicks); + + gi := GearsList; + while gi <> nil do + begin + if gi^.Kind = gtGenericFaller then + begin + gi^.Active:= true; + gi^.X:= int2hwFloat(GetRandom(rightX-leftX)+leftX); + gi^.Y:= int2hwFloat(GetRandom(LAND_HEIGHT-topY)+topY); + gi^.dX:= _90-(GetRandomf*_360); + gi^.dY:= _90-(GetRandomf*_360) + end; + gi := gi^.NextGear + end; + ag:= AddGear(hwRound(Gear^.X), hwRound(Gear^.Y), gtAddAmmo, gstInvisible, _0, _0, GetRandom(200)+100); + ag^.Pos:= Gear^.Pos; + ag^.Power:= Gear^.Power end; - if Gear^.Power <> 0 then AddAmmo(HH^.Hedgehog^, a, Gear^.Power) - else AddAmmo(HH^.Hedgehog^, a); -// Possibly needs to check shared clan ammo game flag once added. -// On the other hand, no obvious reason that clan members shouldn't know what ammo another clan member picked up - if (not (HH^.Hedgehog^.Team^.ExtDriven - or (HH^.Hedgehog^.BotLevel > 0))) - or (HH^.Hedgehog^.Team^.Clan^.ClanIndex = LocalClan) - or (GameType in [gmtDemo, gmtRecord]) then - begin - if Gear^.Power <> 0 then - s:= trammo[Ammoz[a].NameId] + ' (+' + IntToStr(Gear^.Power) + ')' - else - s:= trammo[Ammoz[a].NameId] + ' (+' + IntToStr(Ammoz[a].NumberInCase) + ')'; - AddCaption(s, HH^.Hedgehog^.Team^.Clan^.Color, capgrpAmmoinfo); - - // show ammo icon - vga:= AddVisualGear(hwRound(Gear^.X), hwRound(Gear^.Y), vgtAmmo); - if vga <> nil then - vga^.Frame:= Longword(a); - end; - end; posCaseHealth: begin + PlaySound(sndShotgunReload); inc(HH^.Health, Gear^.Health); HH^.Hedgehog^.Effects[hePoisoned] := 0; str(Gear^.Health, s); @@ -830,7 +854,7 @@ Gear^.State:= Gear^.State and (not gstMoving); exit end; -isFalling:= (Gear^.dY.isNegative) or not TestCollisionYKick(Gear, 1); +isFalling:= (Gear^.dY.isNegative) or (not TestCollisionYKick(Gear, 1)); if isFalling then begin if (Gear^.dY.isNegative) and TestCollisionYKick(Gear, -1) then @@ -960,7 +984,7 @@ begin Gear^.State:= Gear^.State and (not gstWinner); Gear^.State:= Gear^.State and (not gstMoving); - while (TestCollisionYWithGear(Gear,1) = 0) and not CheckGearDrowning(Gear) do + while (TestCollisionYWithGear(Gear,1) = 0) and (not CheckGearDrowning(Gear)) do Gear^.Y:= Gear^.Y+_1; SetLittle(Gear^.dX); Gear^.dY:= _0 @@ -1224,6 +1248,7 @@ land: Word; *) var slope: hwFloat; begin +CheckSum:= CheckSum xor Gear^.Hedgehog^.BotLevel; if (Gear^.Message and gmDestroy) <> 0 then begin DeleteGear(Gear); diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uGearsList.pas --- a/hedgewars/uGearsList.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uGearsList.pas Thu Jul 26 21:56:47 2012 +0400 @@ -27,11 +27,13 @@ procedure InsertGearToList(Gear: PGear); procedure RemoveGearFromList(Gear: PGear); +var curHandledGear: PGear; + implementation uses uRandom, uUtils, uConsts, uVariables, uAmmos, uTeams, uStats, uTextures, uScript, uRenderUtils, uAI, uCollisions, - uGearsRender, uGearsUtils; + uGearsRender, uGearsUtils, uDebug; var GCounter: LongWord = 0; // this does not get re-initialized, but should be harmless @@ -63,8 +65,11 @@ end; end; + procedure RemoveGearFromList(Gear: PGear); begin +TryDo((curHandledGear = nil) or (Gear = curHandledGear), 'You''re doing it wrong', true); + if Gear^.NextGear <> nil then Gear^.NextGear^.PrevGear:= Gear^.PrevGear; if Gear^.PrevGear <> nil then @@ -72,7 +77,8 @@ else GearsList:= Gear^.NextGear end; - + + function AddGear(X, Y: LongInt; Kind: TGearType; State: Longword; dX, dY: hwFloat; Timer: LongWord): PGear; var gear: PGear; begin @@ -92,16 +98,13 @@ gear^.doStep:= doStepHandlers[Kind]; gear^.CollisionIndex:= -1; gear^.Timer:= Timer; -gear^.FlightTime:= 0; gear^.uid:= GCounter; gear^.SoundChannel:= -1; gear^.ImpactSound:= sndNone; -gear^.nImpactSounds:= 0; gear^.Density:= _1; // Define ammo association, if any. gear^.AmmoType:= GearKindAmmoTypeMap[Kind]; gear^.CollisionMask:= $FFFF; -gear^.Power:= 0; if CurrentHedgehog <> nil then gear^.Hedgehog:= CurrentHedgehog; @@ -460,6 +463,13 @@ gear^.Pos:= 1; end; gtIceGun: gear^.Health:= 1000; +gtGenericFaller:begin + gear^.AdvBounce:= 1; + gear^.Radius:= 1; + gear^.Elasticity:= _0_9; + gear^.Friction:= _0_995; + gear^.Density:= _1; + end; end; InsertGearToList(gear); @@ -557,8 +567,10 @@ end end; with Gear^ do + begin AddFileLog('Delete: #' + inttostr(uid) + ' (' + inttostr(hwRound(x)) + ',' + inttostr(hwRound(y)) + '), d(' + floattostr(dX) + ',' + floattostr(dY) + ') type = ' + EnumToStr(Kind)); - + AddRandomness(X.round xor X.frac xor dX.round xor dX.frac xor Y.round xor Y.frac xor dY.round xor dY.frac) + end; if CurAmmoGear = Gear then CurAmmoGear:= nil; if FollowGear = Gear then diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uGearsRender.pas --- a/hedgewars/uGearsRender.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uGearsRender.pas Thu Jul 26 21:56:47 2012 +0400 @@ -21,7 +21,7 @@ unit uGearsRender; interface -uses uTypes, uConsts, GLunit, uFloat, SDLh; +uses uTypes, uConsts, GLunit, uFloat, SDLh, uRandom; procedure RenderGear(Gear: PGear; x, y: LongInt); @@ -1213,9 +1213,8 @@ else DrawLine(hwRound(HHGear^.X), hwRound(HHGear^.Y), hwRound(Gear^.X), hwRound(Gear^.Y), 4.0, i, i, $FF, $40); end end - end - - + end; + gtGenericFaller: DrawCircle(x, y, 3, 3, $FF, $00, $00, $FF); // debug end; if Gear^.RenderTimer and (Gear^.Tex <> nil) then DrawTextureCentered(x + 8, y + 8, Gear^.Tex); diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uGearsUtils.pas --- a/hedgewars/uGearsUtils.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uGearsUtils.pas Thu Jul 26 21:56:47 2012 +0400 @@ -343,6 +343,18 @@ Y:= hwRound(Gear^.Y); if cWaterLine < Y + Gear^.Radius then begin + if Gear^.State and gstInvisible <> 0 then + begin + if Gear^.Kind = gtGenericFaller then + begin + Gear^.X:= int2hwFloat(GetRandom(rightX-leftX)+leftX); + Gear^.Y:= int2hwFloat(GetRandom(LAND_HEIGHT-topY)+topY); + Gear^.dX:= _90-(GetRandomf*_360); + Gear^.dY:= _90-(GetRandomf*_360) + end + else DeleteGear(Gear); + exit + end; isSubmersible:= (Gear = CurrentHedgehog^.Gear) and (CurAmmoGear <> nil) and (CurAmmoGear^.AmmoType = amJetpack); skipSpeed := _0_25; skipAngle := _1_9; @@ -408,10 +420,9 @@ Scale:= hwFloat2Float(Gear^.Density / _3 * Gear^.dY); if Scale > 1 then Scale:= power(Scale,0.3333) else Scale:= Scale + ((1-Scale) / 2); - if Scale > 1 then Timer:= round(max(Scale,3)) + if Scale > 1 then Timer:= round(min(Scale*0.0005/cGravityf,4)) else Timer:= 1; // Low Gravity - Timer:=round(0.0005/cGravityf); FrameTicks:= FrameTicks*Timer; end; diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uIO.pas --- a/hedgewars/uIO.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uIO.pas Thu Jul 26 21:56:47 2012 +0400 @@ -403,7 +403,7 @@ TargetPoint.Y:= putY end; AddFileLog('put: ' + inttostr(TargetPoint.X) + ', ' + inttostr(TargetPoint.Y)); - State:= State and not gstHHChooseTarget; + State:= State and (not gstHHChooseTarget); if (Ammoz[CurAmmoType].Ammo.Propz and ammoprop_AttackingPut) <> 0 then Message:= Message or (gmAttack and InputMask); end diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uInputHandler.pas --- a/hedgewars/uInputHandler.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uInputHandler.pas Thu Jul 26 21:56:47 2012 +0400 @@ -25,8 +25,9 @@ procedure initModule; procedure freeModule; -function KeyNameToCode(name: shortstring; Modifier: shortstring = ''): LongInt; -procedure MaskModifier(var code: LongInt; modifier: LongWord); +function KeyNameToCode(name: shortstring): LongInt; inline; +function KeyNameToCode(name: shortstring; Modifier: shortstring): LongInt; +//procedure MaskModifier(var code: LongInt; modifier: LongWord); procedure MaskModifier(Modifier: shortstring; var code: LongInt); procedure ProcessMouse(event: TSDL_MouseButtonEvent; ButtonDown: boolean); procedure ProcessKey(event: TSDL_KeyboardEvent); inline; @@ -60,6 +61,11 @@ KeyNames: array [0..cKeyMaxIndex] of string[15]; CurrentBinds: TBinds; +function KeyNameToCode(name: shortstring): LongInt; inline; +begin + KeyNameToCode:= KeyNameToCode(name, ''); +end; + function KeyNameToCode(name: shortstring; Modifier: shortstring): LongInt; var code: LongInt; begin @@ -70,7 +76,7 @@ MaskModifier(Modifier, code); KeyNameToCode:= code; end; - +(* procedure MaskModifier(var code: LongInt; Modifier: LongWord); begin if(Modifier and KMOD_LSHIFT) <> 0 then code:= code or LSHIFT; @@ -80,7 +86,7 @@ if(Modifier and KMOD_LCTRL) <> 0 then code:= code or LCTRL; if(Modifier and KMOD_RCTRL) <> 0 then code:= code or LCTRL; end; - +*) procedure MaskModifier(Modifier: shortstring; var code: LongInt); var mod_ : shortstring; ModifierCount, i: LongInt; @@ -133,7 +139,7 @@ if CurrentBinds[code][0] <> #0 then begin - if (code > 3) and KeyDown and not ((CurrentBinds[code] = 'put') or (CurrentBinds[code] = 'ammomenu') or (CurrentBinds[code] = '+cur_u') or (CurrentBinds[code] = '+cur_d') or (CurrentBinds[code] = '+cur_l') or (CurrentBinds[code] = '+cur_r')) then hideAmmoMenu:= true; + if (code > 3) and KeyDown and (not ((CurrentBinds[code] = 'put')) or (CurrentBinds[code] = 'ammomenu') or (CurrentBinds[code] = '+cur_u') or (CurrentBinds[code] = '+cur_d') or (CurrentBinds[code] = '+cur_l') or (CurrentBinds[code] = '+cur_r')) then hideAmmoMenu:= true; if KeyDown then begin @@ -248,6 +254,7 @@ DefaultBinds[KeyNameToCode(_S'0')]:= '+volup'; DefaultBinds[KeyNameToCode(_S'9')]:= '+voldown'; +DefaultBinds[KeyNameToCode(_S'8')]:= 'mute'; DefaultBinds[KeyNameToCode(_S'c')]:= 'capture'; DefaultBinds[KeyNameToCode(_S'r')]:= 'record'; DefaultBinds[KeyNameToCode(_S'h')]:= 'findhh'; diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uRandom.pas --- a/hedgewars/uRandom.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uRandom.pas Thu Jul 26 21:56:47 2012 +0400 @@ -35,15 +35,23 @@ procedure SetRandomSeed(Seed: shortstring); // Sets the seed that should be used for generating pseudo-random values. function GetRandomf: hwFloat; overload; // Returns a pseudo-random hwFloat. -function GetRandom(m: LongWord): LongWord; overload; // Returns a positive pseudo-random integer smaller than m. +function GetRandom(m: LongWord): LongWord; overload; inline; // Returns a positive pseudo-random integer smaller than m. +procedure AddRandomness(r: LongWord); inline; function rndSign(num: hwFloat): hwFloat; // Returns num with a random chance of having a inverted sign. + implementation var cirbuf: array[0..63] of Longword; n: byte; -function GetNext: Longword; +procedure AddRandomness(r: LongWord); inline; +begin +n:= (n + 1) and $3F; +cirbuf[n]:= cirbuf[n] xor r +end; + +function GetNext: Longword; inline; begin n:= (n + 1) and $3F; cirbuf[n]:= @@ -79,7 +87,7 @@ GetRandomf.QWordValue:= GetNext end; -function GetRandom(m: LongWord): LongWord; +function GetRandom(m: LongWord): LongWord; inline; begin GetNext; GetRandom:= GetNext mod m diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uScript.pas --- a/hedgewars/uScript.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uScript.pas Thu Jul 26 21:56:47 2012 +0400 @@ -981,10 +981,9 @@ begin prevgear := CurrentHedgehog^.Gear; prevgear^.Active := false; - prevgear^.State:= prevgear^.State and not gstHHDriven; + prevgear^.State:= prevgear^.State and (not gstHHDriven); prevgear^.Z := cHHZ; - RemoveGearFromList(prevgear); - InsertGearToList(prevgear); + prevgear^.Message:= prevgear^.Message or gmRemoveFromList or gmAddToList; SwitchCurrentHedgehog(gear^.Hedgehog); CurrentTeam:= CurrentHedgehog^.Team; @@ -992,8 +991,7 @@ gear^.State:= gear^.State or gstHHDriven; gear^.Active := true; gear^.Z := cCurrHHZ; - RemoveGearFromList(gear); - InsertGearToList(gear); + gear^.Message:= gear^.Message or gmRemoveFromList or gmAddToList; end end; lc_switchhog:= 0 diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uSound.pas --- a/hedgewars/uSound.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uSound.pas Thu Jul 26 21:56:47 2012 +0400 @@ -47,7 +47,7 @@ // Obvious music commands for music track procedure SetMusic(enabled: boolean); // Enable/disable music. -procedure SetMusicName(musicname: shortstring); // Enable/disable music and set name of musicfile to play. +procedure SetMusicName(musicname: shortstring); // Enable/disable music and set name of the file to play. procedure PlayMusic; // Play music from the start. procedure PauseMusic; // Pause music. procedure ResumeMusic; // Resume music from pause point. @@ -82,6 +82,16 @@ procedure PlayNextVoice; +// GLOBAL FUNCTIONS + +// Drastically lower the volume when we lose focus (and restore the previous value). +procedure DampenAudio; +procedure UndampenAudio; + +// Mute/Unmute audio +procedure MuteAudio; + + // MISC // Set the initial volume @@ -93,25 +103,22 @@ // Returns a pointer to the voicepack with the given name. function AskForVoicepack(name: shortstring): Pointer; -// Drastically lower the volume when we lose focus (and restore the previous value). -procedure DampenAudio; -procedure UndampenAudio; implementation uses uVariables, uConsole, uUtils, uCommands, uDebug; const chanTPU = 32; var Volume: LongInt; + cInitVolume: LongInt; + previousVolume: LongInt; // cached volume value lastChan: array [TSound] of LongInt; voicepacks: array[0..cMaxTeams] of TVoicepack; defVoicepack: PVoicepack; - Mus: PMixMusic = nil; + Mus: PMixMusic = nil; // music pointer MusicFN: shortstring; // music file name - previousVolume: LongInt; // cached volume value isMusicEnabled: boolean; isSoundEnabled: boolean; isSEBackup: boolean; - cInitVolume: LongInt; function AskForVoicepack(name: shortstring): Pointer; @@ -180,7 +187,7 @@ WriteLnToConsole(msgOK); Mix_AllocateChannels(Succ(chanTPU)); - ChangeVolume(cInitVolume); + ChangeVolume(cInitVolume); end; procedure ResetSound; @@ -446,7 +453,7 @@ function ChangeVolume(voldelta: LongInt): LongInt; begin ChangeVolume:= 0; - if not isSoundEnabled then + if (not isSoundEnabled) or (voldelta = 0) then exit; inc(Volume, voldelta); @@ -458,20 +465,52 @@ Volume:= Mix_Volume(-1, -1); if isMusicEnabled then Mix_VolumeMusic(Volume * 4 div 8); - ChangeVolume:= Volume * 100 div MIX_MAX_VOLUME + ChangeVolume:= Volume * 100 div MIX_MAX_VOLUME; + + if (isMusicEnabled) then + if (Volume = 0) then + PauseMusic + else + ResumeMusic; + + isAudioMuted:= (Volume = 0); end; procedure DampenAudio; begin + if (isAudioMuted) then + exit; previousVolume:= Volume; ChangeVolume(-Volume * 7 div 9); end; procedure UndampenAudio; begin + if (isAudioMuted) then + exit; ChangeVolume(previousVolume - Volume); end; +procedure MuteAudio; +begin + if (not isSoundEnabled) then + exit; + + if (isAudioMuted) then + begin + ResumeMusic; + ChangeVolume(previousVolume); + end + else + begin + PauseMusic; + previousVolume:= Volume; + ChangeVolume(-Volume); + end; + + // isAudioMuted is updated in ChangeVolume +end; + procedure SetMusic(enabled: boolean); begin isMusicEnabled:= enabled; @@ -534,17 +573,22 @@ CurrentTeam^.voicepack:= AskForVoicepack(s) end; +procedure chMute(var s: shortstring); +begin + s:= s; // avoid compiler hint + MuteAudio; +end; + procedure initModule; var t: LongInt; i: TSound; begin RegisterVariable('voicepack', @chVoicepack, false); + RegisterVariable('mute' , @chMute , true ); MusicFN:=''; - isMusicEnabled:= true; - isSoundEnabled:= true; + isAudioMuted:= false; isSEBackup:= isSoundEnabled; - cInitVolume:= 100; Volume:= 0; defVoicepack:= AskForVoicepack('Default'); @@ -568,6 +612,11 @@ begin if isSoundEnabled then ReleaseSound(true); + // koda still needs to fix this properly. when he rearranged things, he made these variables get + // reset after argparsers picks them up + isMusicEnabled:= true; + isSoundEnabled:= true; + cInitVolume:= 100; end; end. diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uTeams.pas --- a/hedgewars/uTeams.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uTeams.pas Thu Jul 26 21:56:47 2012 +0400 @@ -473,7 +473,7 @@ begin Gear^.Invulnerable:= false; Gear^.Damage:= Gear^.Health; - Gear^.State:= (Gear^.State or gstHHGone) and not gstHHDriven + Gear^.State:= (Gear^.State or gstHHGone) and (not gstHHDriven) end end end; diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uTypes.pas --- a/hedgewars/uTypes.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uTypes.pas Thu Jul 26 21:56:47 2012 +0400 @@ -102,7 +102,7 @@ gtSniperRifleShot, gtJetpack, gtMolotov, gtBirdy, // 44 gtEgg, gtPortal, gtPiano, gtGasBomb, gtSineGunShot, gtFlamethrower, // 50 gtSMine, gtPoisonCloud, gtHammer, gtHammerHit, gtResurrector, // 55 - gtNapalmBomb, gtSnowball, gtFlake, gtStructure, gtLandGun, gtTardis, gtIceGun); // 62 + gtNapalmBomb, gtSnowball, gtFlake, gtStructure, gtLandGun, gtTardis, gtIceGun, gtAddAmmo, gtGenericFaller); // 62 // Gears that are _only_ of visual nature (e.g. background stuff, visual effects, speechbubbles, etc.) TVisualGearType = (vgtFlake, vgtCloud, vgtExplPart, vgtExplPart2, vgtFire, @@ -340,6 +340,8 @@ HatTex: PTexture; Ammo: PHHAmmo; CurAmmoType: TAmmoType; + PickUpType: LongWord; + PickUpDelay: LongInt; AmmoStore: Longword; Team: PTeam; MultiShootAttacks: Longword; @@ -404,24 +406,27 @@ sidHellishBomb, sidDrill, sidBallgun, sidNapalm, sidRCPlane, sidLowGravity, sidExtraDamage, sidInvulnerable, sidExtraTime, sidLaserSight, sidVampiric, sidSniperRifle, sidJetpack, - sidMolotov, sidBirdy, sidPortalGun, sidPiano, sidGasBomb, sidSineGun, sidFlamethrower, - sidSMine, sidHammer, sidResurrector, sidDrillStrike, sidSnowball, sidNothing, sidTardis, - sidStructure, sidLandGun, sidIceGun); + sidMolotov, sidBirdy, sidPortalGun, sidPiano, sidGasBomb, + sidSineGun, sidFlamethrower,sidSMine, sidHammer, sidResurrector, + sidDrillStrike, sidSnowball, sidNothing, sidTardis, + sidStructure, sidLandGun, sidIceGun); TMsgStrId = (sidStartFight, sidDraw, sidWinner, sidVolume, sidPaused, sidConfirm, sidSuddenDeath, sidRemaining, sidFuel, sidSync, sidNoEndTurn, sidNotYetAvailable, sidRoundSD, sidRoundsSD, sidReady, - sidBounce1, sidBounce2, sidBounce3, sidBounce4, sidBounce5, sidBounce); + sidBounce1, sidBounce2, sidBounce3, sidBounce4, sidBounce5, sidBounce, + sidMute); // Events that are important for the course of the game or at least interesting for other reasons TEventId = (eidDied, eidDrowned, eidRoundStart, eidRoundWin, eidRoundDraw, - eidNewHealthPack, eidNewAmmoPack, eidNewUtilityPack, eidTurnSkipped, eidHurtSelf, - eidHomerun, eidGone); + eidNewHealthPack, eidNewAmmoPack, eidNewUtilityPack, eidTurnSkipped, + eidHurtSelf, eidHomerun, eidGone); TGoalStrId = (gidCaption, gidSubCaption, gidForts, gidLowGravity, gidInvulnerable, gidVampiric, gidKarma, gidKing, gidPlaceHog, gidArtillery, - gidSolidLand, gidSharedAmmo, gidMineTimer, gidNoMineTimer, gidRandomMineTimer, - gidDamageModifier, gidResetHealth, gidAISurvival, gidInfAttack, gidResetWeps, gidPerHogAmmo, gidTagTeam); + gidSolidLand, gidSharedAmmo, gidMineTimer, gidNoMineTimer, + gidRandomMineTimer, gidDamageModifier, gidResetHealth, gidAISurvival, + gidInfAttack, gidResetWeps, gidPerHogAmmo, gidTagTeam); TLandArray = packed array of array of LongWord; TCollisionArray = packed array of array of Word; diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uVariables.pas --- a/hedgewars/uVariables.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uVariables.pas Thu Jul 26 21:56:47 2012 +0400 @@ -69,11 +69,13 @@ isPaused : boolean; isInMultiShoot : boolean; isSpeed : boolean; + SpeedStart : LongWord; fastUntilLag : boolean; fastScrolling : boolean; autoCameraOn : boolean; + CheckSum : LongWord; GameTicks : LongWord; GameState : TGameState; GameType : TGameType; @@ -108,6 +110,7 @@ cWaterLine : Word; cGearScrEdgesDist: LongInt; + isAudioMuted : boolean; // originally typed consts ExplosionBorderColor: LongWord; @@ -1453,7 +1456,8 @@ NumberInCase: 1; Ammo: (Propz: ammoprop_ForwMsgs or ammoprop_NoCrosshair or - ammoprop_DontHold; + ammoprop_DontHold or + ammoprop_Track; Count: 1; NumPerTurn: 0; Timer: 0; @@ -2378,6 +2382,8 @@ (* gtLandGun *) , amLandGun (* gtTardis *) , amTardis (* gtIceGun *) , amIceGun +(* gtAddAmmo *) , amNothing +(* gtGenericFaller *) , amNothing ); var @@ -2544,6 +2550,7 @@ CursorMovementX := 0; CursorMovementY := 0; GameTicks := 0; + CheckSum := 0; cWaterLine := LAND_HEIGHT; cGearScrEdgesDist := 240; @@ -2592,6 +2599,7 @@ isPaused := false; isInMultiShoot := false; isSpeed := false; + SpeedStart := 0; fastUntilLag := false; fastScrolling := false; autoCameraOn := true; diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uVisualGears.pas --- a/hedgewars/uVisualGears.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uVisualGears.pas Thu Jul 26 21:56:47 2012 +0400 @@ -295,6 +295,8 @@ dy:= 0; FrameTicks:= 740; Frame:= 19; + Scale:= 0.75; + Timer:= 1; end; vgtDroplet: begin diff -r bc3306c59a08 -r 9bb6abdb5675 hedgewars/uWorld.pas --- a/hedgewars/uWorld.pas Fri Jul 13 16:39:20 2012 +0400 +++ b/hedgewars/uWorld.pas Thu Jul 26 21:56:47 2012 +0400 @@ -1333,7 +1333,7 @@ r.w:= 3; DrawTextureFromRect(TeamHealthBarWidth + 16, cScreenHeight + DrawHealthY + smallScreenOffset, @r, HealthTex); - if not highlight and not hasGone and (TeamHealth > 1) then + if not highlight and (not hasGone) and (TeamHealth > 1) then for i:= 0 to cMaxHHIndex do if Hedgehogs[i].Gear <> nil then begin @@ -1530,14 +1530,16 @@ end; if SoundTimerTicks >= 50 then - begin - SoundTimerTicks:= 0; - if cVolumeDelta <> 0 then - begin - str(ChangeVolume(cVolumeDelta), s); - AddCaption(Format(trmsg[sidVolume], s), cWhiteColor, capgrpVolume) - end - end; +begin + SoundTimerTicks:= 0; + if cVolumeDelta <> 0 then + begin + str(ChangeVolume(cVolumeDelta), s); + AddCaption(Format(trmsg[sidVolume], s), cWhiteColor, capgrpVolume); + end; + if isAudioMuted then + AddCaption(trmsg[sidMute], cWhiteColor, capgrpVolume) +end; if GameState = gsConfirm then DrawTextureCentered(0, (cScreenHeight shr 1), ConfirmTexture); diff -r bc3306c59a08 -r 9bb6abdb5675 share/hedgewars/Data/Locale/en.txt --- a/share/hedgewars/Data/Locale/en.txt Fri Jul 13 16:39:20 2012 +0400 +++ b/share/hedgewars/Data/Locale/en.txt Thu Jul 26 21:56:47 2012 +0400 @@ -79,6 +79,7 @@ 01:18=High 01:19=Extreme 01:20=%1 Bounce +01:21=Audio Muted ; Event messages ; Hog (%1) died diff -r bc3306c59a08 -r 9bb6abdb5675 tools/PascalParser.hs --- a/tools/PascalParser.hs Fri Jul 13 16:39:20 2012 +0400 +++ b/tools/PascalParser.hs Thu Jul 26 21:56:47 2012 +0400 @@ -19,7 +19,7 @@ pascalUnit = do comments - u <- choice [program, unit, systemUnit] + u <- choice [program, unit, systemUnit, redoUnit] comments return u @@ -348,36 +348,46 @@ comments return $ Implementation u (TypesAndVars tv) -expression = buildExpressionParser table term "expression" +expression = do + buildExpressionParser table term "expression" where term = comments >> choice [ builtInFunction expression >>= \(n, e) -> return $ BuiltInFunCall e (SimpleReference (Identifier n BTUnknown)) , try (parens pas $ expression >>= \e -> notFollowedBy (comments >> char '.') >> return e) , brackets pas (commaSep pas iD) >>= return . SetExpression - , try $ natural pas >>= \i -> notFollowedBy (char '.') >> (return . NumberLiteral . show) i + , try $ integer pas >>= \i -> notFollowedBy (char '.') >> (return . NumberLiteral . show) i , float pas >>= return . FloatLiteral . show - , natural pas >>= return . NumberLiteral . show + , try $ integer pas >>= return . NumberLiteral . show , try (string "_S" >> stringLiteral pas) >>= return . StringLiteral , try (string "_P" >> stringLiteral pas) >>= return . PCharLiteral , stringLiteral pas >>= return . strOrChar , try (string "#$") >> many hexDigit >>= \c -> comments >> return (HexCharCode c) , char '#' >> many digit >>= \c -> comments >> return (CharCode c) , char '$' >> many hexDigit >>= \h -> comments >> return (HexNumber h) - , char '-' >> expression >>= return . PrefixOp "-" + --, char '-' >> expression >>= return . PrefixOp "-" + , char '-' >> reference >>= return . PrefixOp "-" . Reference + , try $ string "not" >> error "unexpected not in term" , try $ string "nil" >> return Null - , try $ string "not" >> expression >>= return . PrefixOp "not" , reference >>= return . Reference ] "simple expression" - table = [ + table = [ + [ Prefix (try (string "not") >> return (PrefixOp "not")) + , Prefix (try (char '-') >> return (PrefixOp "-"))] + , [ Infix (char '*' >> return (BinOp "*")) AssocLeft , Infix (char '/' >> return (BinOp "/")) AssocLeft , Infix (try (string "div") >> return (BinOp "div")) AssocLeft , Infix (try (string "mod") >> return (BinOp "mod")) AssocLeft , Infix (try (string "in") >> return (BinOp "in")) AssocNone + , Infix (try $ string "and" >> return (BinOp "and")) AssocLeft + , Infix (try $ string "shl" >> return (BinOp "shl")) AssocLeft + , Infix (try $ string "shr" >> return (BinOp "shr")) AssocLeft ] , [ Infix (char '+' >> return (BinOp "+")) AssocLeft , Infix (char '-' >> return (BinOp "-")) AssocLeft + , Infix (try $ string "or" >> return (BinOp "or")) AssocLeft + , Infix (try $ string "xor" >> return (BinOp "xor")) AssocLeft ] , [ Infix (try (string "<>") >> return (BinOp "<>")) AssocNone , Infix (try (string "<=") >> return (BinOp "<=")) AssocNone @@ -385,13 +395,13 @@ , Infix (char '<' >> return (BinOp "<")) AssocNone , Infix (char '>' >> return (BinOp ">")) AssocNone ] - , [ Infix (try $ string "shl" >> return (BinOp "shl")) AssocNone - , Infix (try $ string "shr" >> return (BinOp "shr")) AssocNone + {-, [ Infix (try $ string "shl" >> return (BinOp "shl")) AssocNone + , Infix (try $ string "shr" >> return (BinOp "shr")) AssocNone ] - , [ Infix (try $ string "and" >> return (BinOp "and")) AssocLeft - , Infix (try $ string "or" >> return (BinOp "or")) AssocLeft + , [ + Infix (try $ string "or" >> return (BinOp "or")) AssocLeft , Infix (try $ string "xor" >> return (BinOp "xor")) AssocLeft - ] + ]-} , [ Infix (char '=' >> return (BinOp "=")) AssocNone ] @@ -415,7 +425,7 @@ , switchCase , withBlock , forCycle - , (try $ reference >>= \r -> string ":=" >> return r) >>= \r -> expression >>= return . Assignment r + , (try $ reference >>= \r -> string ":=" >> return r) >>= \r -> comments >> expression >>= return . Assignment r , builtInFunction expression >>= \(n, e) -> return $ BuiltInFunctionCall e (SimpleReference (Identifier n BTUnknown)) , procCall , char ';' >> comments >> return NOP @@ -480,7 +490,12 @@ comments e1 <- expression comments - choice [string "to", string "downto"] + up <- liftM (== Just "to") $ + optionMaybe $ choice [ + try $ string "to" + , try $ string "downto" + ] + --choice [string "to", string "downto"] comments e2 <- expression comments @@ -488,7 +503,7 @@ comments p <- phrase comments - return $ ForCycle i e1 e2 p + return $ ForCycle i e1 e2 p up switchCase = do try $ string "case" @@ -573,14 +588,20 @@ table = [ [ Prefix (char '-' >> return (InitPrefixOp "-")) + ,Prefix (try (string "not") >> return (InitPrefixOp "not")) ] , [ Infix (char '*' >> return (InitBinOp "*")) AssocLeft , Infix (char '/' >> return (InitBinOp "/")) AssocLeft , Infix (try (string "div") >> return (InitBinOp "div")) AssocLeft , Infix (try (string "mod") >> return (InitBinOp "mod")) AssocLeft + , Infix (try $ string "and" >> return (InitBinOp "and")) AssocLeft + , Infix (try $ string "shl" >> return (InitBinOp "shl")) AssocNone + , Infix (try $ string "shr" >> return (InitBinOp "shr")) AssocNone ] , [ Infix (char '+' >> return (InitBinOp "+")) AssocLeft , Infix (char '-' >> return (InitBinOp "-")) AssocLeft + , Infix (try $ string "or" >> return (InitBinOp "or")) AssocLeft + , Infix (try $ string "xor" >> return (InitBinOp "xor")) AssocLeft ] , [ Infix (try (string "<>") >> return (InitBinOp "<>")) AssocNone , Infix (try (string "<=") >> return (InitBinOp "<=")) AssocNone @@ -589,14 +610,14 @@ , Infix (char '>' >> return (InitBinOp ">")) AssocNone , Infix (char '=' >> return (InitBinOp "=")) AssocNone ] - , [ Infix (try $ string "and" >> return (InitBinOp "and")) AssocLeft + {--, [ Infix (try $ string "and" >> return (InitBinOp "and")) AssocLeft , Infix (try $ string "or" >> return (InitBinOp "or")) AssocLeft , Infix (try $ string "xor" >> return (InitBinOp "xor")) AssocLeft ] , [ Infix (try $ string "shl" >> return (InitBinOp "shl")) AssocNone , Infix (try $ string "shr" >> return (InitBinOp "shr")) AssocNone - ] - , [Prefix (try (string "not") >> return (InitPrefixOp "not"))] + ]--} + --, [Prefix (try (string "not") >> return (InitPrefixOp "not"))] ] itypeCast = do @@ -621,3 +642,14 @@ string "var" v <- varsDecl True return $ System (t ++ v) + +redoUnit = do + string "redo;" + comments + string "type" + comments + t <- typesDecl + string "var" + v <- varsDecl True + return $ Redo (t ++ v) + diff -r bc3306c59a08 -r 9bb6abdb5675 tools/PascalPreprocessor.hs --- a/tools/PascalPreprocessor.hs Fri Jul 13 16:39:20 2012 +0400 +++ b/tools/PascalPreprocessor.hs Thu Jul 26 21:56:47 2012 +0400 @@ -18,6 +18,8 @@ initDefines = Map.fromList [ ("FPC", "") , ("PAS2C", "") + , ("ENDIAN_LITTLE", "") + , ("S3D_DISABLED", "") ] preprocess :: String -> IO String diff -r bc3306c59a08 -r 9bb6abdb5675 tools/PascalUnitSyntaxTree.hs --- a/tools/PascalUnitSyntaxTree.hs Fri Jul 13 16:39:20 2012 +0400 +++ b/tools/PascalUnitSyntaxTree.hs Thu Jul 26 21:56:47 2012 +0400 @@ -7,6 +7,7 @@ Program Identifier Implementation Phrase | Unit Identifier Interface Implementation (Maybe Initialize) (Maybe Finalize) | System [TypeVarDeclaration] + | Redo [TypeVarDeclaration] deriving Show data Interface = Interface Uses TypesAndVars deriving Show @@ -48,7 +49,7 @@ | IfThenElse Expression Phrase (Maybe Phrase) | WhileCycle Expression Phrase | RepeatCycle Expression [Phrase] - | ForCycle Identifier Expression Expression Phrase + | ForCycle Identifier Expression Expression Phrase Bool -- The last Boolean indicates wether it's up or down counting | WithBlock Reference Phrase | Phrases [Phrase] | SwitchCase Expression [([InitExpression], Phrase)] (Maybe [Phrase]) diff -r bc3306c59a08 -r 9bb6abdb5675 tools/pas2c.hs --- a/tools/pas2c.hs Fri Jul 13 16:39:20 2012 +0400 +++ b/tools/pas2c.hs Thu Jul 26 21:56:47 2012 +0400 @@ -71,13 +71,14 @@ escapeChar :: Char -> ShowS escapeChar '"' s = "\\\"" ++ s +escapeChar '\\' s = "\\\\" ++ s escapeChar a s = a : s strInit :: String -> Doc strInit a = text "STRINIT" <> parens (doubleQuotes (text $ escapeStr a)) renderStringConsts :: State RenderState Doc -renderStringConsts = liftM (vcat . map (\(a, b) -> text "const string255" <+> (text a) <+> text "=" <+> strInit b <> semi)) +renderStringConsts = liftM (vcat . map (\(a, b) -> text "static const string255" <+> (text a) <+> text "=" <+> strInit b <> semi)) $ gets stringConsts docToLower :: Doc -> Doc @@ -132,10 +133,16 @@ where f = do checkDuplicateFunDecls tvs - mapM_ (tvar2C True) tvs + mapM_ (tvar2C True False True False) tvs + toNamespace nss (Redo tvs) = -- functions that are re-implemented, add prefix to all of them + currentScope $ execState f (emptyState nss){currentUnit = "fpcrtl_"} + where + f = do + checkDuplicateFunDecls tvs + mapM_ (tvar2C True False True False) tvs toNamespace _ (Program {}) = Map.empty toNamespace nss (Unit (Identifier i _) interface _ _ _) = - currentScope $ execState (interface2C interface) (emptyState nss){currentUnit = map toLower i ++ "_"} + currentScope $ execState (interface2C interface True) (emptyState nss){currentUnit = map toLower i ++ "_"} withState' :: (RenderState -> RenderState) -> State RenderState a -> State RenderState a @@ -149,7 +156,6 @@ }) return a -withLastIdNamespace :: State RenderState Doc -> State RenderState Doc withLastIdNamespace f = do li <- gets lastIdentifier nss <- gets namespaces @@ -165,49 +171,57 @@ toCFiles :: Map.Map String Records -> (String, PascalUnit) -> IO () toCFiles _ (_, System _) = return () +toCFiles _ (_, Redo _) = return () toCFiles ns p@(fn, pu) = do hPutStrLn stdout $ "Rendering '" ++ fn ++ "'..." toCFiles' p where - toCFiles' (fn, p@(Program {})) = writeFile (fn ++ ".c") $ (render2C initialState . pascal2C) p + toCFiles' (fn, p@(Program {})) = writeFile (fn ++ ".c") $ "#include \"fpcrtl.h\"\n" ++ (render2C initialState . pascal2C) p toCFiles' (fn, (Unit unitId@(Identifier i _) interface implementation _ _)) = do - let (a, s) = runState (id2C IOInsert (setBaseType BTUnit unitId) >> interface2C interface) initialState{currentUnit = map toLower i ++ "_"} + let (a, s) = runState (id2C IOInsert (setBaseType BTUnit unitId) >> interface2C interface True) initialState{currentUnit = map toLower i ++ "_"} + (a', s') = runState (id2C IOInsert (setBaseType BTUnit unitId) >> interface2C interface False) initialState{currentUnit = map toLower i ++ "_"} writeFile (fn ++ ".h") $ "#pragma once\n\n#include \"pas2c.h\"\n\n" ++ (render (a $+$ text "")) - writeFile (fn ++ ".c") $ "#include \"" ++ fn ++ ".h\"\n" ++ (render2C s . implementation2C) implementation + writeFile (fn ++ ".c") $ "#include \"fpcrtl.h\"\n\n#include \"" ++ fn ++ ".h\"\n" ++ render (a' $+$ text "") ++ (render2C s . implementation2C) implementation initialState = emptyState ns render2C :: RenderState -> State RenderState Doc -> String render2C a = render . ($+$ empty) . flip evalState a + usesFiles :: PascalUnit -> [String] -usesFiles (Program _ (Implementation uses _) _) = "pas2cSystem" : uses2List uses -usesFiles (Unit _ (Interface uses1 _) (Implementation uses2 _) _ _) = "pas2cSystem" : uses2List uses1 ++ uses2List uses2 +usesFiles (Program _ (Implementation uses _) _) = ["pas2cSystem", "pas2cRedo"] ++ uses2List uses +usesFiles (Unit _ (Interface uses1 _) (Implementation uses2 _) _ _) = ["pas2cSystem", "pas2cRedo"] ++ uses2List uses1 ++ uses2List uses2 usesFiles (System {}) = [] - +usesFiles (Redo {}) = [] pascal2C :: PascalUnit -> State RenderState Doc pascal2C (Unit _ interface implementation init fin) = - liftM2 ($+$) (interface2C interface) (implementation2C implementation) + liftM2 ($+$) (interface2C interface True) (implementation2C implementation) pascal2C (Program _ implementation mainFunction) = do impl <- implementation2C implementation - [main] <- tvar2C True - (FunctionDeclaration (Identifier "main" BTInt) (SimpleType $ Identifier "int" BTInt) [] (Just (TypesAndVars [], mainFunction))) + [main] <- tvar2C True False True True (FunctionDeclaration (Identifier "main" BTInt) (SimpleType $ Identifier "int" BTInt) [VarDeclaration False False ([Identifier "argc" BTInt], SimpleType (Identifier "Integer" BTInt)) Nothing, VarDeclaration False False ([Identifier "argv" BTUnknown], SimpleType (Identifier "PPChar" BTUnknown)) Nothing] (Just (TypesAndVars [], mainFunction))) return $ impl $+$ main - -interface2C :: Interface -> State RenderState Doc -interface2C (Interface uses tvars) = do +-- the second bool indicates whether do normal interface translation or generate variable declarations +-- that will be inserted into implementation files +interface2C :: Interface -> Bool -> State RenderState Doc +interface2C (Interface uses tvars) True = do u <- uses2C uses - tv <- typesAndVars2C True tvars + tv <- typesAndVars2C True True True tvars r <- renderStringConsts return (u $+$ r $+$ tv) +interface2C (Interface uses tvars) False = do + u <- uses2C uses + tv <- typesAndVars2C True False False tvars + r <- renderStringConsts + return tv implementation2C :: Implementation -> State RenderState Doc implementation2C (Implementation uses tvars) = do u <- uses2C uses - tv <- typesAndVars2C True tvars + tv <- typesAndVars2C True False True tvars r <- renderStringConsts return (u $+$ r $+$ tv) @@ -220,17 +234,22 @@ ins (FunctionDeclaration (Identifier i _) _ _ _) m = Map.insertWith (+) (map toLower i) 1 m ins _ m = m -typesAndVars2C :: Bool -> TypesAndVars -> State RenderState Doc -typesAndVars2C b (TypesAndVars ts) = do +-- the second bool indicates whether declare variable as extern or not +-- the third bool indicates whether include types or not + +typesAndVars2C :: Bool -> Bool -> Bool -> TypesAndVars -> State RenderState Doc +typesAndVars2C b externVar includeType(TypesAndVars ts) = do checkDuplicateFunDecls ts - liftM (vcat . map (<> semi) . concat) $ mapM (tvar2C b) ts + liftM (vcat . map (<> semi) . concat) $ mapM (tvar2C b externVar includeType False) ts setBaseType :: BaseType -> Identifier -> Identifier setBaseType bt (Identifier i _) = Identifier i bt uses2C :: Uses -> State RenderState Doc uses2C uses@(Uses unitIds) = do + mapM_ injectNamespace (Identifier "pas2cSystem" undefined : unitIds) + mapM_ injectNamespace (Identifier "pas2cRedo" undefined : unitIds) mapM_ (id2C IOInsert . setBaseType BTUnit) unitIds return $ vcat . map (\i -> text $ "#include \"" ++ i ++ ".h\"") $ uses2List uses where @@ -256,6 +275,7 @@ return $ text i' where n = map toLower i + id2C IOLookup i = id2CLookup head i id2C IOLookupLast i = id2CLookup last i id2C (IOLookupFunction params) (Identifier i t) = do @@ -279,7 +299,7 @@ let vv = head $ fromJust v in modify (\s -> s{lastType = snd vv, lastIdentifier = fst vv}) >> (return . text . fst $ vv) id2CLookup :: ([Record] -> Record) -> Identifier -> State RenderState Doc -id2CLookup f (Identifier i _) = do +id2CLookup f (Identifier i t) = do let i' = map toLower i v <- gets $ Map.lookup i' . currentScope lt <- gets lastType @@ -363,7 +383,7 @@ error $ "Dereferencing from non-pointer type " ++ show t ++ "\n" ++ s -functionParams2C params = liftM (hcat . punctuate comma . concat) $ mapM (tvar2C False) params +functionParams2C params = liftM (hcat . punctuate comma . concat) $ mapM (tvar2C False False True True) params numberOfDeclarations :: [TypeVarDeclaration] -> Int numberOfDeclarations = sum . map cnt @@ -421,12 +441,15 @@ (p, ph) <- withState' (\st -> st{currentScope = Map.insertWith un (map toLower rv) [(render res, t')] $ currentScope st , currentFunctionResult = if isVoid then [] else render res}) $ do p <- functionParams2C params - ph <- liftM2 ($+$) (typesAndVars2C False tvars) (phrase2C' phrase) + ph <- liftM2 ($+$) (typesAndVars2C False False True tvars) (phrase2C' phrase) return (p, ph) let phrasesBlock = if isVoid then ph else t empty <+> res <> semi $+$ ph $+$ text "return" <+> res <> semi - - return [(if notDeclared && hasVars then funWithVarsToDefine n params else empty) $+$ + let define = if hasVars then text "#ifndef" <+> text n $+$ funWithVarsToDefine n params $+$ text "#endif" else empty + return [ + define + $+$ + --(if notDeclared && hasVars then funWithVarsToDefine n params else empty) $+$ t empty <+> text (if hasVars then n ++ "__vars" else n) <> parens p $+$ text "{" @@ -443,37 +466,69 @@ fun2C False _ (FunctionDeclaration (Identifier name _) _ _ _) = error $ "nested functions not allowed: " ++ name fun2C _ tv _ = error $ "fun2C: I don't render " ++ show tv -tvar2C :: Bool -> TypeVarDeclaration -> State RenderState [Doc] -tvar2C b f@(FunctionDeclaration (Identifier name _) _ _ _) = - fun2C b name f -tvar2C _ td@(TypeDeclaration i' t) = do +-- the second bool indicates whether declare variable as extern or not +-- the third bool indicates whether include types or not +-- the fourth bool indicates whether ignore initialization or not (basically for dynamic arrays since we cannot do initialization in function params) +tvar2C :: Bool -> Bool -> Bool -> Bool -> TypeVarDeclaration -> State RenderState [Doc] +tvar2C b _ includeType _ f@(FunctionDeclaration (Identifier name _) _ _ _) = do + t <- fun2C b name f + if includeType then return t else return [] +tvar2C _ _ includeType _ td@(TypeDeclaration i' t) = do i <- id2CTyped t i' tp <- type2C t - return [text "typedef" <+> tp i] + return $ if includeType then [text "typedef" <+> tp i] else [] -tvar2C _ (VarDeclaration True _ (ids, t) Nothing) = do +tvar2C _ _ _ _ (VarDeclaration True _ (ids, t) Nothing) = do t' <- liftM ((empty <+>) . ) $ type2C t liftM (map(\i -> t' i)) $ mapM (id2CTyped (VarParamType t)) ids -tvar2C _ (VarDeclaration _ isConst (ids, t) mInitExpr) = do - t' <- liftM (((if isConst then text "const" else empty) <+>) . ) $ type2C t +tvar2C _ externVar includeType ignoreInit (VarDeclaration _ isConst (ids, t) mInitExpr) = do + t' <- liftM (((if isConst then text "static const" else if externVar + then text "extern" + else empty) + <+>) . ) $ type2C t ie <- initExpr mInitExpr lt <- gets lastType case (isConst, lt, ids, mInitExpr) of (True, BTInt, [i], Just _) -> do i' <- id2CTyped t i - return [text "enum" <> braces (i' <+> ie)] + return $ if includeType then [text "enum" <> braces (i' <+> ie)] else [] (True, BTFloat, [i], Just e) -> do i' <- id2CTyped t i ie <- initExpr2C e - return [text "#define" <+> i' <+> parens ie <> text "\n"] + return $ if includeType then [text "#define" <+> i' <+> parens ie <> text "\n"] else [] (_, BTFunction{}, _, Nothing) -> liftM (map(\i -> t' i)) $ mapM (id2CTyped t) ids - _ -> liftM (map(\i -> t' i <+> ie)) $ mapM (id2CTyped t) ids + (_, BTArray r _ _, [i], _) -> do + i' <- id2CTyped t i + ie' <- return $ case (r, mInitExpr, ignoreInit) of + (RangeInfinite, Nothing, False) -> text "= NULL" -- force dynamic array to be initialized as NULL if not initialized at all + (_, _, _) -> ie + result <- liftM (map(\i -> varDeclDecision isConst includeType (t' i) ie')) $ mapM (id2CTyped t) ids + case (r, ignoreInit) of + (RangeInfinite, False) -> + -- if the array is dynamic, add dimension info to it + return $ [dimDecl] ++ result + where + arrayDimStr = show $ arrayDimension t + arrayDimInitExp = text ("={" ++ ".dim = " ++ arrayDimStr ++ ", .a = {0, 0, 0, 0}}") + dimDecl = varDeclDecision isConst includeType (text "fpcrtl_dimension_t" <+> i' <> text "_dimension_info") arrayDimInitExp + + (_, _) -> return result + + _ -> liftM (map(\i -> varDeclDecision isConst includeType (t' i) ie)) $ mapM (id2CTyped t) ids where initExpr Nothing = return $ empty initExpr (Just e) = liftM (text "=" <+>) (initExpr2C e) + varDeclDecision True True varStr expStr = varStr <+> expStr + varDeclDecision False True varStr expStr = if externVar then varStr else varStr <+> expStr + varDeclDecision False False varStr expStr = varStr <+> expStr + varDeclDecision True False varStr expStr = empty + arrayDimension a = case a of + ArrayDecl Nothing t -> let a = arrayDimension t in if a > 3 then error "Dynamic array with dimension > 4 is not supported." else 1 + arrayDimension t + ArrayDecl _ _ -> error "Mixed dynamic array and static array are not supported." + _ -> 0 -tvar2C f (OperatorDeclaration op (Identifier i _) ret params body) = do +tvar2C f _ _ _ (OperatorDeclaration op (Identifier i _) ret params body) = do r <- op2CTyped op (extractTypes params) fun2C f i (FunctionDeclaration r ret params body) @@ -489,6 +544,7 @@ "-" -> "sub" "*" -> "mul" "/" -> "div" + "/(float)" -> "div" "=" -> "eq" "<" -> "lt" ">" -> "gt" @@ -591,7 +647,7 @@ _ -> return $ \a -> i' <+> text "*" <+> a type2C' (PointerTo t) = liftM (\t a -> t (parens $ text "*" <> a)) $ type2C t type2C' (RecordType tvs union) = do - t <- withState' f $ mapM (tvar2C False) tvs + t <- withState' f $ mapM (tvar2C False False True False) tvs u <- unions return $ \i -> text "struct __" <> i <+> lbrace $+$ nest 4 ((vcat . map (<> semi) . concat $ t) $$ u) $+$ rbrace <+> i where @@ -602,7 +658,7 @@ structs <- mapM struct2C a return $ text "union" $+$ braces (nest 4 $ vcat structs) <> semi struct2C tvs = do - t <- withState' f $ mapM (tvar2C False) tvs + t <- withState' f $ mapM (tvar2C False False True False) tvs return $ text "struct" $+$ braces (nest 4 (vcat . map (<> semi) . concat $ t)) <> semi type2C' (RangeType r) = return (text "int" <+>) type2C' (Sequence ids) = do @@ -615,7 +671,7 @@ t' <- type2C t lt <- gets lastType ft <- case lt of - BTFunction {} -> type2C (PointerTo t) + -- BTFunction {} -> type2C (PointerTo t) _ -> return t' r' <- initExpr2C (InitRange r) return $ \i -> ft i <> brackets r' @@ -675,15 +731,26 @@ e <- expr2C expr return $ r <+> text "=" <+> e <> semi _ -> error $ "Assignment to string from " ++ show lt - (BTArray _ _ _, _) -> phrase2C $ - ProcCall (FunCall - [ - Reference $ Address ref - , Reference $ Address $ RefExpression expr - , Reference $ FunCall [expr] (SimpleReference (Identifier "sizeof" BTUnknown)) - ] - (SimpleReference (Identifier "memcpy" BTUnknown)) - ) [] + (BTArray _ _ _, _) -> do + case expr of + Reference er -> do + exprRef <- ref2C er + exprT <- gets lastType + case exprT of + BTArray RangeInfinite _ _ -> + return $ text "FIXME: assign a dynamic array to an array" + BTArray _ _ _ -> phrase2C $ + ProcCall (FunCall + [ + Reference $ ref + , Reference $ RefExpression expr + , Reference $ FunCall [expr] (SimpleReference (Identifier "sizeof" BTUnknown)) + ] + (SimpleReference (Identifier "memcpy" BTUnknown)) + ) [] + _ -> return $ text "FIXME: assign a non-specific value to an array" + + _ -> return $ text "FIXME: dynamic array assignment 2" _ -> do e <- expr2C expr return $ r <+> text "=" <+> e <> semi @@ -704,7 +771,7 @@ ph <- phrase2C p return $ vcat (map (\i -> text "case" <+> i <> colon) . concat $ ies) <> nest 4 (ph $+$ text "break;") - dflt | isNothing mphrase = return [] + dflt | isNothing mphrase = return [text "default: break;"] -- avoid compiler warning | otherwise = do ph <- mapM phrase2C $ fromJust mphrase return [text "default:" <+> nest 4 (vcat ph)] @@ -716,13 +783,15 @@ (BTRecord _ rs) -> withRecordNamespace (render r ++ ".") rs $ phrase2C $ wrapPhrase p a -> do error $ "'with' block referencing non-record type " ++ show a ++ "\n" ++ show wb -phrase2C (ForCycle i' e1' e2' p) = do +phrase2C (ForCycle i' e1' e2' p up) = do i <- id2C IOLookup i' e1 <- expr2C e1' e2 <- expr2C e2' ph <- phrase2C (wrapPhrase p) + cmp <- return $ if up == True then "<=" else ">=" + inc <- return $ if up == True then "++" else "--" return $ - text "for" <> (parens . hsep . punctuate (char ';') $ [i <+> text "=" <+> e1, i <+> text "<=" <+> e2, text "++" <> i]) + text "for" <> (parens . hsep . punctuate (char ';') $ [i <+> text "=" <+> parens e1, i <+> text cmp <+> parens e2, text inc <> i]) $$ ph phrase2C (RepeatCycle e' p') = do @@ -777,12 +846,23 @@ case expr2 of SetExpression set -> do ids <- mapM (id2C IOLookup) set + modify(\s -> s{lastType = BTBool}) return . parens . hcat . punctuate (text " || ") . map (\i -> parens $ e1 <+> text "==" <+> i) $ ids _ -> error "'in' against not set expression" (o, _, _) | o `elem` boolOps -> do modify(\s -> s{lastType = BTBool}) return $ parens e1 <+> text o <+> parens e2 - | otherwise -> return $ parens e1 <+> text o <+> parens e2 + | otherwise -> do + o' <- return $ case o of + "/(float)" -> text "/(float)" -- pascal returns real value + _ -> text o + e1' <- return $ case (o, t1, t2) of + ("-", BTInt, BTInt) -> parens $ text "(int64_t)" <+> parens e1 + _ -> parens e1 + e2' <- return $ case (o, t1, t2) of + ("-", BTInt, BTInt) -> parens $ text "(int64_t)" <+> parens e2 + _ -> parens e2 + return $ e1' <+> o' <+> e2' where boolOps = ["==", "!=", "<", ">", "<=", ">="] expr2C (NumberLiteral s) = do @@ -806,7 +886,12 @@ BTRecord t _ -> do i <- op2CTyped op [SimpleType (Identifier t undefined)] ref2C $ FunCall [expr] (SimpleReference i) - _ -> return $ text (op2C op) <> e + BTBool -> do + o <- return $ case op of + "not" -> text "!" + _ -> text (op2C op) + return $ o <> parens e + _ -> return $ text (op2C op) <> parens e expr2C Null = return $ text "NULL" expr2C (CharCode a) = do modify(\s -> s{lastType = BTChar}) @@ -835,13 +920,13 @@ _ -> error $ "BuiltInFunCall 'high' from " ++ show e ++ "\ntype: " ++ show lt expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "ord" _))) = liftM parens $ expr2C e expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "succ" _))) = liftM (<> text " + 1") $ expr2C e -expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "pred" _))) = liftM (<> text " - 1") $ expr2C e +expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "pred" _))) = liftM (<> text " - (int64_t)1") $ expr2C e expr2C (BuiltInFunCall [e] (SimpleReference (Identifier "length" _))) = do e' <- expr2C e lt <- gets lastType modify (\s -> s{lastType = BTInt}) case lt of - BTString -> return $ text "Length" <> parens e' + BTString -> return $ text "fpcrtl_Length" <> parens e' BTArray RangeInfinite _ _ -> error $ "length() called on variable size array " ++ show e' BTArray (RangeFromTo _ n) _ _ -> initExpr2C (BuiltInFunction "succ" [n]) _ -> error $ "length() called on " ++ show lt @@ -864,7 +949,7 @@ case t of BTFunction _ _ rt -> do modify(\s -> s{lastType = rt}) - return $ i <> parens empty + return $ i <> parens empty --xymeng: removed parens _ -> return $ i ref2CF r@(RecordField (SimpleReference _) (SimpleReference _)) = do i <- ref2C r @@ -962,7 +1047,7 @@ op2C :: String -> String op2C "or" = "|" op2C "and" = "&" -op2C "not" = "!" +op2C "not" = "~" op2C "xor" = "^" op2C "div" = "/" op2C "mod" = "%" @@ -970,5 +1055,6 @@ op2C "shr" = ">>" op2C "<>" = "!=" op2C "=" = "==" +op2C "/" = "/(float)" op2C a = a