# HG changeset patch # User Medo # Date 1343293856 -7200 # Node ID 0a494f951dcfe10c4855aec652b410f591e041b4 # Parent 57a50888405278ab301975ac40feb15ad95441af# Parent a46ce1812419c724b6b9fd049ca727443cbfb36e Merge diff -r 57a508884052 -r 0a494f951dcf CMakeLists.txt --- a/CMakeLists.txt Thu Jul 26 11:01:32 2012 +0200 +++ b/CMakeLists.txt Thu Jul 26 11:10:56 2012 +0200 @@ -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 57a508884052 -r 0a494f951dcf QTfrontend/binds.cpp --- a/QTfrontend/binds.cpp Thu Jul 26 11:01:32 2012 +0200 +++ b/QTfrontend/binds.cpp Thu Jul 26 11:10:56 2012 +0200 @@ -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 57a508884052 -r 0a494f951dcf QTfrontend/binds.h --- a/QTfrontend/binds.h Thu Jul 26 11:01:32 2012 +0200 +++ b/QTfrontend/binds.h Thu Jul 26 11:10:56 2012 +0200 @@ -21,7 +21,7 @@ #include -#define BINDS_NUMBER 44 +#define BINDS_NUMBER 45 struct BindAction { diff -r 57a508884052 -r 0a494f951dcf QTfrontend/drawmapscene.cpp --- a/QTfrontend/drawmapscene.cpp Thu Jul 26 11:01:32 2012 +0200 +++ b/QTfrontend/drawmapscene.cpp Thu Jul 26 11:10:56 2012 +0200 @@ -136,7 +136,6 @@ void DrawMapScene::showCursor() { - qDebug() << "show cursor"; if(!m_isCursorShown) addItem(m_cursor); @@ -145,7 +144,6 @@ void DrawMapScene::hideCursor() { - qDebug() << "hide cursor"; if(m_isCursorShown) removeItem(m_cursor); diff -r 57a508884052 -r 0a494f951dcf QTfrontend/gameuiconfig.cpp --- a/QTfrontend/gameuiconfig.cpp Thu Jul 26 11:01:32 2012 +0200 +++ b/QTfrontend/gameuiconfig.cpp Thu Jul 26 11:10:56 2012 +0200 @@ -333,7 +333,7 @@ QByteArray GameUIConfig::netPasswordHash() { - return QCryptographicHash::hash(Form->ui.pageOptions->editNetPassword->text().toLatin1(), QCryptographicHash::Md5).toHex(); + return QCryptographicHash::hash(Form->ui.pageOptions->editNetPassword->text().toUtf8(), QCryptographicHash::Md5).toHex(); } int GameUIConfig::netPasswordLength() diff -r 57a508884052 -r 0a494f951dcf QTfrontend/hwform.cpp --- a/QTfrontend/hwform.cpp Thu Jul 26 11:01:32 2012 +0200 +++ b/QTfrontend/hwform.cpp Thu Jul 26 11:10:56 2012 +0200 @@ -128,7 +128,7 @@ #endif gameSettings = new QSettings(cfgdir->absolutePath() + "/hedgewars.ini", QSettings::IniFormat); frontendEffects = gameSettings->value("frontend/effects", true).toBool(); - playerHash = QString(QCryptographicHash::hash(gameSettings->value("net/nick","").toString().toLatin1(), QCryptographicHash::Md5).toHex()); + playerHash = QString(QCryptographicHash::hash(gameSettings->value("net/nick","").toString().toUtf8(), QCryptographicHash::Md5).toHex()); this->setStyleSheet(styleSheet); ui.setupUi(this); @@ -968,7 +968,7 @@ } QString password = hpd->lePassword->text(); - hash = QCryptographicHash::hash(password.toLatin1(), QCryptographicHash::Md5).toHex(); + hash = QCryptographicHash::hash(password.toUtf8(), QCryptographicHash::Md5).toHex(); bool save = hpd->cbSave->isChecked(); config->setValue("net/savepassword", save); diff -r 57a508884052 -r 0a494f951dcf QTfrontend/model/ammoSchemeModel.h --- a/QTfrontend/model/ammoSchemeModel.h Thu Jul 26 11:01:32 2012 +0200 +++ b/QTfrontend/model/ammoSchemeModel.h Thu Jul 26 11:10:56 2012 +0200 @@ -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 57a508884052 -r 0a494f951dcf QTfrontend/team.cpp --- a/QTfrontend/team.cpp Thu Jul 26 11:01:32 2012 +0200 +++ b/QTfrontend/team.cpp Thu Jul 26 11:10:56 2012 +0200 @@ -259,7 +259,7 @@ QStringList sl; if (m_isNetTeam) { - sl.push_back(QString("eaddteam %3 %1 %2").arg(qcolor().rgb() & 0xffffff).arg(m_name).arg(QString(QCryptographicHash::hash(m_owner.toLatin1(), QCryptographicHash::Md5).toHex()))); + sl.push_back(QString("eaddteam %3 %1 %2").arg(qcolor().rgb() & 0xffffff).arg(m_name).arg(QString(QCryptographicHash::hash(m_owner.toUtf8(), QCryptographicHash::Md5).toHex()))); sl.push_back("erdriven"); } else sl.push_back(QString("eaddteam %3 %1 %2").arg(qcolor().rgb() & 0xffffff).arg(m_name).arg(playerHash)); diff -r 57a508884052 -r 0a494f951dcf QTfrontend/ui/page/pageplayrecord.cpp --- a/QTfrontend/ui/page/pageplayrecord.cpp Thu Jul 26 11:01:32 2012 +0200 +++ b/QTfrontend/ui/page/pageplayrecord.cpp Thu Jul 26 11:10:56 2012 +0200 @@ -169,7 +169,11 @@ if(!ok) QMessageBox::critical(this, tr("Error"), tr("Cannot delete file")); else - FillFromDir(recType); + { + int i = DemosList->row(curritem); + delete curritem; + DemosList->setCurrentRow(i < DemosList->count() ? i : DemosList->count() - 1); + } } bool PagePlayDemo::isSave() diff -r 57a508884052 -r 0a494f951dcf gameServer/Actions.hs --- a/gameServer/Actions.hs Thu Jul 26 11:01:32 2012 +0200 +++ b/gameServer/Actions.hs Thu Jul 26 11:10:56 2012 +0200 @@ -160,7 +160,7 @@ s <- get put $! s{removedClients = ci `Set.delete` removedClients s} - + sp <- gets (shutdownPending . serverInfo) cls <- allClientsS io $ when (sp && null cls) $ throwIO ShutdownException @@ -210,7 +210,6 @@ ri <- clientRoomA rnc <- gets roomsClients (gameProgress, playersNum) <- io $ room'sM rnc ((isJust . gameInfo) &&& playersIn) ri - ready <- client's isReady master <- client's isMaster -- client <- client's id clNick <- client's nick @@ -218,13 +217,14 @@ if master then if gameProgress && playersNum > 1 then - mapM_ processAction [ChangeMaster, AnswerClients chans ["LEFT", clNick, msg], NoticeMessage AdminLeft, RemoveClientTeams ci] + mapM_ processAction [ChangeMaster, NoticeMessage AdminLeft, RemoveClientTeams ci, AnswerClients chans ["LEFT", clNick, msg]] else processAction RemoveRoom else - mapM_ processAction [AnswerClients chans ["LEFT", clNick, msg], RemoveClientTeams ci] + mapM_ processAction [RemoveClientTeams ci, AnswerClients chans ["LEFT", clNick, msg]] -- when not removing room + ready <- client's isReady when (not master || (gameProgress && playersNum > 1)) . io $ do modifyRoom rnc (\r -> r{ playersIn = playersIn r - 1, @@ -251,7 +251,7 @@ chans <- liftM (map sendChan) $! sameProtoClientsS proto processAction $ AnswerClients chans ("ROOM" : "UPD" : oldRoomName : roomInfo (nick newMaster) newRoom) - + processAction (AddRoom roomName roomPassword) = do Just clId <- gets clientIndex rnc <- gets roomsClients @@ -306,16 +306,16 @@ where notReadyMessage p nicks = if p < 38 then "NOT_READY" : nicks else "CLIENT_FLAGS" : "-r" : nicks - + processAction FinishGame = do rnc <- gets roomsClients ri <- clientRoomA thisRoomChans <- liftM (map sendChan) $ roomClientsS ri clNick <- client's nick - answerRemovedTeams <- io $ + answerRemovedTeams <- io $ room'sM rnc (map (\t -> AnswerClients thisRoomChans ["REMOVE_TEAM", t]) . leftTeams . fromJust . gameInfo) ri - - mapM_ processAction $ + + mapM_ processAction $ SaveReplay : ModifyRoom (\r -> r{ @@ -326,7 +326,7 @@ : UnreadyRoomClients : answerRemovedTeams - + processAction (SendTeamRemovalMessage teamName) = do chans <- othersChans mapM_ processAction [ @@ -338,22 +338,22 @@ }) $ gameInfo r }) ] - + rnc <- gets roomsClients ri <- clientRoomA gi <- io $ room'sM rnc gameInfo ri when (isJust gi && 0 == teamsInGameNumber (fromJust gi)) $ - processAction FinishGame + processAction FinishGame where rmTeamMsg = toEngineMsg $ 'F' `B.cons` teamName - - + + processAction (RemoveTeam teamName) = do rnc <- gets roomsClients ri <- clientRoomA inGame <- io $ room'sM rnc (isJust . gameInfo) ri chans <- othersChans - mapM_ processAction $ + mapM_ processAction $ ModifyRoom (\r -> r{ teams = Prelude.filter (\t -> teamName /= teamname t) $ teams r , gameInfo = liftM (\g -> g{leftTeams = teamName : leftTeams g}) $ gameInfo r @@ -456,7 +456,7 @@ bans <- gets (bans . serverInfo) processAction $ AnswerClients [ch] ["BANLIST", B.pack $ show bans] - + processAction (KickRoomClient kickId) = do @@ -536,7 +536,7 @@ where st irnc = (length $ allRooms irnc, length $ allClients irnc) -processAction RestartServer = do +processAction RestartServer = do sp <- gets (shutdownPending . serverInfo) when (not sp) $ do sock <- gets (fromJust . serverSocket . serverInfo) diff -r 57a508884052 -r 0a494f951dcf gameServer/ClientIO.hs --- a/gameServer/ClientIO.hs Thu Jul 26 11:01:32 2012 +0200 +++ b/gameServer/ClientIO.hs Thu Jul 26 11:10:56 2012 +0200 @@ -43,16 +43,18 @@ clientRecvLoop :: Socket -> Chan CoreMessage -> Chan [B.ByteString] -> ClientIndex -> (forall a. IO a -> IO a) -> IO () clientRecvLoop s chan clChan ci restore = - myThreadId >>= + (myThreadId >>= \t -> (restore $ forkIO (clientSendLoop s t clChan ci) >> listenLoop s chan ci >> return "Connection closed") + `Exception.catch` (\(e :: ShutdownThreadException) -> return . B.pack . show $ e) `Exception.catch` (\(e :: Exception.IOException) -> return . B.pack . show $ e) - `Exception.catch` (\(e :: ShutdownThreadException) -> return . B.pack . show $ e) `Exception.catch` (\(e :: Exception.SomeException) -> return . B.pack . show $ e) - >>= clientOff >> remove + >>= clientOff) `Exception.finally` remove where clientOff msg = writeChan chan $ ClientMessage (ci, ["QUIT", msg]) - remove = writeChan chan $ Remove ci + remove = do + clientOff "Client is in some weird state" + writeChan chan $ Remove ci @@ -64,12 +66,11 @@ killReciever . B.unpack $ quitMessage answer Exception.handle - (\(e :: Exception.IOException) -> unless (isQuit answer) . killReciever $ show e) $ + (\(e :: Exception.SomeException) -> unless (isQuit answer) . killReciever $ show e) $ sendAll s $ B.unlines answer `B.snoc` '\n' if isQuit answer then - do - Exception.handle (\(_ :: Exception.IOException) -> putStrLn "error on sClose") $ sClose s + sClose s else clientSendLoop s tId chan ci diff -r 57a508884052 -r 0a494f951dcf gameServer/CoreTypes.hs --- a/gameServer/CoreTypes.hs Thu Jul 26 11:01:32 2012 +0200 +++ b/gameServer/CoreTypes.hs Thu Jul 26 11:10:56 2012 +0200 @@ -62,7 +62,7 @@ hedgehogs :: [HedgehogInfo] } deriving (Show, Read) - + data GameInfo = GameInfo { @@ -74,9 +74,9 @@ giMapParams :: Map.Map B.ByteString B.ByteString, giParams :: Map.Map B.ByteString [B.ByteString] } deriving (Show, Read) - ---newGameInfo :: -> GameInfo -newGameInfo = + +--newGameInfo :: -> GameInfo +newGameInfo = GameInfo Data.Sequence.empty [] diff -r 57a508884052 -r 0a494f951dcf gameServer/HWProtoInRoomState.hs --- a/gameServer/HWProtoInRoomState.hs Thu Jul 26 11:01:32 2012 +0200 +++ b/gameServer/HWProtoInRoomState.hs Thu Jul 26 11:10:56 2012 +0200 @@ -79,10 +79,10 @@ hhsList [_] = error "Hedgehogs list with odd elements number" hhsList (n:h:hhs) = HedgehogInfo n h : hhsList hhs newTeamHHNum r = min 4 (canAddNumber r) - maxTeams r + maxTeams r | roomProto r < 38 = 6 | otherwise = 8 - + handleCmd_inRoom ["REMOVE_TEAM", tName] = do (ci, _) <- ask @@ -171,7 +171,7 @@ cl <- thisClient rm <- thisRoom chans <- roomClientsChans - + let allPlayersRegistered = all ((<) 0 . B.length . webPassword . client rnc . teamownerId) $ teams rm if isMaster cl && playersIn rm == readyPlayers rm && not (isJust $ gameInfo rm) then @@ -247,7 +247,7 @@ rs <- allRoomInfos rm <- thisRoom chans <- sameProtoChans - + return $ if not $ isMaster cl then [ProtocolError "Not room master"] diff -r 57a508884052 -r 0a494f951dcf gameServer/HWProtoLobbyState.hs --- a/gameServer/HWProtoLobbyState.hs Thu Jul 26 11:01:32 2012 +0200 +++ b/gameServer/HWProtoLobbyState.hs Thu Jul 26 11:10:56 2012 +0200 @@ -71,7 +71,7 @@ let nicks = map nick jRoomClients let chans = map sendChan (cl : jRoomClients) return $ - if isNothing maybeRI || not sameProto then + if isNothing maybeRI || not sameProto then [Warning "No such room"] else if isRestrictedJoins jRoom then [Warning "Joining restricted"] @@ -147,12 +147,12 @@ cl <- thisClient banId <- clientByNick banNick return [BanClient 60 reason (fromJust banId) | isAdministrator cl && isJust banId && fromJust banId /= ci] - + handleCmd_lobby ["BANIP", ip, reason, duration] = do (ci, _) <- ask cl <- thisClient return [BanIP ip (readInt_ duration) reason | isAdministrator cl] - + handleCmd_lobby ["BANLIST"] = do (ci, _) <- ask cl <- thisClient @@ -172,7 +172,7 @@ return [ModifyServerInfo (\si -> si{latestReleaseVersion = readNum}) | isAdministrator cl && readNum > 0] where readNum = readInt_ protoNum - + handleCmd_lobby ["GET_SERVER_VAR"] = do cl <- thisClient return [SendServerVars | isAdministrator cl] diff -r 57a508884052 -r 0a494f951dcf gameServer/OfficialServer/DBInteraction.hs --- a/gameServer/OfficialServer/DBInteraction.hs Thu Jul 26 11:01:32 2012 +0200 +++ b/gameServer/OfficialServer/DBInteraction.hs Thu Jul 26 11:10:56 2012 +0200 @@ -60,7 +60,7 @@ CheckAccount clId clUid clNick _ -> do let cacheEntry = clNick `Map.lookup` accountsCache currentTime <- getCurrentTime - if (isNothing cacheEntry) || (currentTime `diffUTCTime` (fst . fromJust) cacheEntry > 2 * 24 * 60 * 60) then + if (isNothing cacheEntry) || (currentTime `diffUTCTime` (fst . fromJust) cacheEntry > 10 * 60) then do SIO.hPutStrLn hIn $ show q hFlush hIn diff -r 57a508884052 -r 0a494f951dcf hedgewars/CMakeLists.txt --- a/hedgewars/CMakeLists.txt Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/CMakeLists.txt Thu Jul 26 11:10:56 2012 +0200 @@ -32,6 +32,7 @@ uFloat.pas uGame.pas uGears.pas + uGearsHandlers.pas uGearsRender.pas uIO.pas uInputHandler.pas diff -r 57a508884052 -r 0a494f951dcf hedgewars/GSHandlers.inc --- a/hedgewars/GSHandlers.inc Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/GSHandlers.inc Thu Jul 26 11:10:56 2012 +0200 @@ -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,21 +2122,37 @@ 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 voices. Reinforcements voices is heard for active team, not team-to-be. Either that or change crate spawn from end of turn to start, although that has its own complexities. *) // Abuse a couple of gear values to track origin - Gear^.Angle:= hwRound(Gear^.X); - Gear^.Power:= hwRound(Gear^.Y); + Gear^.Angle:= hwRound(Gear^.Y); Gear^.Tag:= random(2); inc(Gear^.Timer) end; if Gear^.Timer < 1833 then inc(Gear^.Timer); if Gear^.Timer = 1000 then begin - sparkles:= AddVisualGear(Gear^.Angle, Gear^.Power, vgtDust, 1); + sparkles:= AddVisualGear(hwRound(Gear^.X), Gear^.Angle, vgtDust, 1); if sparkles <> nil then begin sparkles^.dX:= 0; @@ -2382,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 @@ -2396,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; @@ -2414,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; @@ -2751,16 +2767,17 @@ procedure doStepSwitcherWork(Gear: PGear); var HHGear: PGear; + hedgehog: PHedgehog; State: Longword; begin AllInactive := false; if ((Gear^.Message and (not gmSwitch)) <> 0) or (TurnTimeLeft = 0) then begin - HHGear := Gear^.Hedgehog^.Gear; + hedgehog := Gear^.Hedgehog; //Msg := Gear^.Message and (not gmSwitch); DeleteGear(Gear); - ApplyAmmoChanges(HHGear^.Hedgehog^); + ApplyAmmoChanges(hedgehog^); HHGear := CurrentHedgehog^.Gear; ApplyAmmoChanges(HHGear^.Hedgehog^); @@ -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; @@ -3054,20 +3068,10 @@ end; -procedure PrevAngle(Gear: PGear; dA: LongInt); -begin - Gear^.Angle := (LongInt(Gear^.Angle) + 4 - dA) mod 4 -end; - -procedure NextAngle(Gear: PGear; dA: LongInt); -begin - Gear^.Angle := (LongInt(Gear^.Angle) + 4 + dA) mod 4 -end; - procedure doStepCakeWork(Gear: PGear); const dirs: array[0..3] of TPoint = ((X: 0; Y: -1), (X: 1; Y: 0),(X: 0; Y: 1),(X: -1; Y: 0)); -var +var xx, yy, xxn, yyn: LongInt; dA: LongInt; tdx, tdy: hwFloat; @@ -3078,39 +3082,20 @@ if Gear^.Tag < 7 then exit; - 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; - - if (xx = 0) then - if TestCollisionYwithGear(Gear, yy) <> 0 then - PrevAngle(Gear, dA) - else - begin - Gear^.Tag := 0; - Gear^.Y := Gear^.Y + int2hwFloat(yy); - if not TestCollisionXwithGear(Gear, xxn) then - begin - Gear^.X := Gear^.X + int2hwFloat(xxn); - NextAngle(Gear, dA) - 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; + exit end; - if (yy = 0) then - if TestCollisionXwithGear(Gear, xx) then - PrevAngle(Gear, dA) - else - begin - Gear^.Tag := 0; - Gear^.X := Gear^.X + int2hwFloat(xx); - if TestCollisionYwithGear(Gear, yyn) = 0 then - begin - Gear^.Y := Gear^.Y + int2hwFloat(yyn); - NextAngle(Gear, dA) - end; - end; + cakeStep(Gear); if Gear^.Tag = 0 then begin @@ -3121,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); @@ -3193,23 +3166,22 @@ //////////////////////////////////////////////////////////////////////////////// procedure doStepSeductionWork(Gear: PGear); var i: LongInt; - hogs: TPGearArray; + hogs: PGearArrayS; begin AllInactive := false; hogs := GearsNear(Gear^.X, Gear^.Y, gtHedgehog, Gear^.Radius); - if Length(hogs) > 0 then - begin - for i:= 0 to Length(hogs) - 1 do - begin - if hogs[i] <> CurrentHedgehog^.Gear then + if hogs.size > 0 then + begin + for i:= 0 to hogs.size - 1 do + with hogs.ar^[i]^ do begin - //d:= Distance(Gear^.X - hogs[i]^.X, Gear^.Y - hogs[i]^.Y); - hogs[i]^.dX:= _50 * cGravity * (Gear^.X - hogs[i]^.X) / _25; - //if Gear^.X < hogs[i]^.X then hogs[i]^.dX.isNegative:= true; - hogs[i]^.dY:= -_450 * cGravity; - hogs[i]^.Active:= true; - end - end; + if hogs.ar^[i] <> CurrentHedgehog^.Gear then + begin + dX:= _50 * cGravity * (Gear^.X - X) / _25; + dY:= -_450 * cGravity; + Active:= true; + end + end; end ; AfterAttack; DeleteGear(Gear); @@ -3331,10 +3303,10 @@ if (Gear^.Timer mod 30) = 0 then AddVisualGear(hwRound(Gear^.X + _20 * Gear^.dX), hwRound(Gear^.Y + _20 * Gear^.dY), vgtDust); if (CheckGearDrowning(Gear)) then - begin + begin StopSoundChan(Gear^.SoundChannel); exit - end + end end; if GameTicks > Gear^.FlightTime then @@ -3425,8 +3397,9 @@ end else if ((Gear^.State and gsttmpFlag) <> 0) and (Gear^.Tag <> 0) then begin - if Gear^.Timer > 0 then dec(Gear^.Timer); - if Gear^.Timer = 0 then + if Gear^.Timer > 0 then + dec(Gear^.Timer) + else begin doMakeExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), 30, Gear^.Hedgehog, EXPLAutoSound); DeleteGear(Gear); @@ -4338,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; @@ -4417,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); @@ -4697,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 @@ -5061,7 +5036,7 @@ //////////////////////////////////////////////////////////////////////////////// procedure doStepResurrectorWork(Gear: PGear); var - graves: TPGearArray; + graves: PGearArrayS; resgear: PGear; hh: PHedgehog; i: LongInt; @@ -5096,7 +5071,7 @@ graves := GearsNear(Gear^.X, Gear^.Y, gtGrave, Gear^.Radius); - if Length(graves) = 0 then + if graves.size = 0 then begin StopSoundChan(Gear^.SoundChannel); Gear^.Timer := 250; @@ -5106,12 +5081,13 @@ if ((Gear^.Message and gmAttack) <> 0) and (hh^.Gear^.Health > 0) and (TurnTimeLeft > 0) then begin - if Length(graves) <= Gear^.Tag then Gear^.Tag:= 0; + if graves.size <= Gear^.Tag then Gear^.Tag:= 0; dec(hh^.Gear^.Health); if (hh^.Gear^.Health = 0) and (hh^.Gear^.Damage = 0) then hh^.Gear^.Damage:= 1; RenderHealth(hh^); - inc(graves[Gear^.Tag]^.Health); + RecountTeamHealth(hh^.Team); + inc(graves.ar^[Gear^.Tag]^.Health); inc(Gear^.Tag) {-for i:= 0 to High(graves) do begin if hh^.Gear^.Health > 0 then begin @@ -5123,19 +5099,20 @@ else begin // now really resurrect the hogs with the hp saved in the graves - for i:= 0 to Length(graves) - 1 do - if graves[i]^.Health > 0 then + for i:= 0 to graves.size - 1 do + if graves.ar^[i]^.Health > 0 then begin - resgear := AddGear(hwRound(graves[i]^.X), hwRound(graves[i]^.Y), gtHedgehog, gstWait, _0, _0, 0); - resgear^.Hedgehog := graves[i]^.Hedgehog; - resgear^.Health := graves[i]^.Health; - PHedgehog(graves[i]^.Hedgehog)^.Gear := resgear; - DeleteGear(graves[i]); + resgear := AddGear(hwRound(graves.ar^[i]^.X), hwRound(graves.ar^[i]^.Y), gtHedgehog, gstWait, _0, _0, 0); + resgear^.Hedgehog := graves.ar^[i]^.Hedgehog; + resgear^.Health := graves.ar^[i]^.Health; + PHedgehog(graves.ar^[i]^.Hedgehog)^.Gear := resgear; + 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; @@ -5152,18 +5129,18 @@ procedure doStepResurrector(Gear: PGear); var - graves: TPGearArray; + graves: PGearArrayS; i: LongInt; begin AllInactive := false; graves := GearsNear(Gear^.X, Gear^.Y, gtGrave, Gear^.Radius); - if Length(graves) > 0 then - begin - for i:= 0 to Length(graves) - 1 do + if graves.size > 0 then + begin + for i:= 0 to graves.size - 1 do begin - PHedgehog(graves[i]^.Hedgehog)^.Gear := nil; - graves[i]^.Health := 0; + PHedgehog(graves.ar^[i]^.Hedgehog)^.Gear := nil; + graves.ar^[i]^.Health := 0; end; Gear^.doStep := @doStepResurrectorWork; end @@ -5482,7 +5459,7 @@ HHGear, iter: PGear; ndX, ndY: hwFloat; i, t, gX, gY: LongInt; - hogs: TPGearArray; + hogs: PGearArrayS; begin HHGear := Gear^.Hedgehog^.Gear; if (Gear^.Health = 0) or (HHGear = nil) or (HHGear^.Damage <> 0) then @@ -5546,9 +5523,9 @@ // freeze nearby hogs if GameTicks mod 10 = 0 then dec(Gear^.Health); hogs := GearsNear(Gear^.X, Gear^.Y, gtHedgehog, Gear^.Radius); - if Length(hogs) > 0 then - for i:= 0 to Length(hogs) - 1 do - if hogs[i] <> HHGear then + if hogs.size > 0 then + for i:= 0 to hogs.size - 1 do + if hogs.ar^[i] <> HHGear then begin //if Gear^.Hedgehog^.Effects[heFrozen]:= 0; end; @@ -5574,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 57a508884052 -r 0a494f951dcf hedgewars/VGSHandlers.inc --- a/hedgewars/VGSHandlers.inc Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/VGSHandlers.inc Thu Jul 26 11:10:56 2012 +0200 @@ -27,6 +27,7 @@ procedure doStepFlake(Gear: PVisualGear; Steps: Longword); var sign: real; + moved: boolean; begin if vobCount = 0 then exit; @@ -84,21 +85,37 @@ end else begin + moved:= false; if round(X) < cLeftScreenBorder then - X:= X + cScreenSpace + begin + X:= X + cScreenSpace; + moved:= true + end else if round(X) > cRightScreenBorder then + begin X:= X - cScreenSpace; + moved:= true + end; // if round(Y) < (LAND_HEIGHT - 1024 - 75) then Y:= Y + 25.0; // For if flag is set for flakes rising upwards? if (Gear^.Layer = 2) and (round(Y) - 225 > LAND_HEIGHT) then begin X:= cLeftScreenBorder + random(cScreenSpace); - Y:= Y - (1024 + 250 + random(50)) // TODO - configure in theme (jellies for example could use limited range) + Y:= Y - (1024 + 250 + random(50)); // TODO - configure in theme (jellies for example could use limited range) + moved:= true end else if (Gear^.Layer <> 2) and (round(Y) + 50 > LAND_HEIGHT) then begin X:= cLeftScreenBorder + random(cScreenSpace); - Y:= Y - (1024 + random(25)) + Y:= Y - (1024 + random(25)); + moved:= true + end; + if moved then + begin + Angle:= random(360); + dx:= 0.0000038654705 * random(10000); + dy:= 0.000003506096 * random(7000); + if random(2) = 0 then dx := -dx end; Timer:= 0; tdX:= 0; diff -r 57a508884052 -r 0a494f951dcf hedgewars/hwengine.pas --- a/hedgewars/hwengine.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/hwengine.pas Thu Jul 26 11:10:56 2012 +0200 @@ -32,7 +32,7 @@ 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 SDL13}, uTouch{$ENDIF}{$IFDEF ANDROID}, GLUnit{$ENDIF}; + {$IFDEF SDL13}, uTouch{$ENDIF}{$IFDEF ANDROID}, GLUnit{$ENDIF}, uAILandMarks; {$IFDEF HWLIBRARY} procedure initEverything(complete:boolean); @@ -401,6 +401,7 @@ uAI.initModule; //uAIActions does not need initialization //uAIAmmoTests does not need initialization + uAILandMarks.initModule; uAIMisc.initModule; uAmmos.initModule; uChat.initModule; @@ -432,6 +433,7 @@ begin WriteLnToConsole('Freeing resources...'); uAI.freeModule; + uAILandMarks.freeModule; uAIMisc.freeModule; //stub uCaptions.freeModule; uWorld.freeModule; diff -r 57a508884052 -r 0a494f951dcf hedgewars/uAI.pas --- a/hedgewars/uAI.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uAI.pas Thu Jul 26 11:10:56 2012 +0200 @@ -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}; @@ -336,7 +362,9 @@ switchesNum:= 0; switchImmediatelyAvailable:= (CurAmmoGear <> nil) and (CurAmmoGear^.Kind = gtSwitcher); -switchCount:= HHHasAmmo(PGear(Me)^.Hedgehog^, amSwitch); +if PGear(Me)^.Hedgehog^.BotLevel <> 5 then + switchCount:= HHHasAmmo(PGear(Me)^.Hedgehog^, amSwitch) +else switchCount:= 0; if (PGear(Me)^.State and gstAttacked) = 0 then if Targets.Count > 0 then @@ -390,6 +418,11 @@ BackMe:= PGear(Me)^; while (not StopThinking) and (BestActions.Count = 0) do begin +(* + // Maybe this would get a bit of movement out of them? Hopefully not *toward* water. Need to check how often he'd choose that strategy + if SuddenDeathDmg and ((hwRound(BackMe.Y)+cWaterRise*2) > cWaterLine) then + AddBonus(hwRound(BackMe.X), hwRound(BackMe.Y), 250, -40); +*) FillBonuses(true); WalkMe:= BackMe; Actions.Count:= 0; @@ -401,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; @@ -412,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; @@ -469,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 57a508884052 -r 0a494f951dcf hedgewars/uAIActions.pas --- a/hedgewars/uAIActions.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uAIActions.pas Thu Jul 26 11:10:56 2012 +0200 @@ -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 57a508884052 -r 0a494f951dcf hedgewars/uAIAmmoTests.pas --- a/hedgewars/uAIAmmoTests.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uAIAmmoTests.pas Thu Jul 26 11:10:56 2012 +0200 @@ -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 @@ -599,6 +600,7 @@ d: Longword; fallDmg, valueResult: LongInt; begin +if Me^.Hedgehog^.BotLevel > 3 then exit(BadTurn); dmgMod:= 0.01 * hwFloat2Float(cDamageModifier) * cDamagePercent; Level:= Level; // avoid compiler hint ap.ExplR:= 0; @@ -648,6 +650,7 @@ d: Longword; fallDmg, valueResult: LongInt; begin +if Me^.Hedgehog^.BotLevel > 3 then exit(BadTurn); dmgMod:= 0.01 * hwFloat2Float(cDamageModifier) * cDamagePercent; Level:= Level; // avoid compiler hint ap.ExplR:= 0; @@ -694,9 +697,11 @@ function TestBaseballBat(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt; var valueResult, a, v1, v2: LongInt; - x, y: LongInt; + x, y, trackFall: LongInt; dx, dy: real; begin + if Me^.Hedgehog^.BotLevel < 3 then trackFall:= afTrackFall + else trackFall:= 0; Level:= Level; // avoid compiler hint ap.ExplR:= 0; ap.Time:= 0; @@ -704,20 +709,20 @@ 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 - , -dx, -dy, afTrackFall); - v2:= RateShove(Me, x + 10, y - , 33, 30, 115 - , dx, -dy, afTrackFall); + v1:= RateShove(Me, x - 10, y + 2 + , 32, 30, 115 + , -dx, -dy, trackFall); + v2:= RateShove(Me, x + 10, y + 2 + , 32, 30, 115 + , dx, -dy, trackFall); if (v1 > valueResult) or (v2 > valueResult) then if (v2 > v1) or {don't encourage turning for no gain}((v2 = v1) and (not Me^.dX.isNegative)) then @@ -731,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 @@ -742,38 +747,40 @@ function TestFirePunch(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt; var valueResult, v1, v2, i: LongInt; - x, y: LongInt; + x, y, trackFall: LongInt; begin + if Me^.Hedgehog^.BotLevel = 1 then trackFall:= afTrackFall + else trackFall:= 0; Level:= Level; // avoid compiler hint ap.ExplR:= 0; 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 - , -0.45, -0.9, afTrackFall or afSetSkip); + 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 - , -0.45, -0.9, afTrackFall); + v1:= v1 + RateShove(Me, x - 5, y - 90 + , 19, 30, 40 + , -0.45, -0.9, trackFall); // now try opposite direction v2:= 0; for i:= 0 to 8 do begin - v2:= v2 + RateShove(Me, x + 10, y - 10 * i - , 18, 30, 40 - , 0.45, -0.9, afTrackFall or afSetSkip); + 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 - , 0.45, -0.9, afTrackFall); + v2:= v2 + RateShove(Me, x + 5, y - 90 + , 19, 30, 40 + , 0.45, -0.9, trackFall); if (v2 > v1) or {don't encourage turning for no gain}((v2 = v1) and (not Me^.dX.isNegative)) then @@ -796,8 +803,10 @@ function TestWhip(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt; var valueResult, v1, v2: LongInt; - x, y: LongInt; + x, y, trackFall: LongInt; begin + if Me^.Hedgehog^.BotLevel = 1 then trackFall:= afTrackFall + else trackFall:= 0; Level:= Level; // avoid compiler hint ap.ExplR:= 0; ap.Time:= 0; @@ -809,21 +818,21 @@ {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, afTrackFall or afSetSkip); + , -1, -0.8, trackFall or afSetSkip); v1:= v1 + RateShove(Me, x, y , 30, 30, 25 - , -1, -0.8, afTrackFall); + , -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, afTrackFall or afSetSkip); + , 1, -0.8, trackFall or afSetSkip); v2:= v2 + RateShove(Me, x, y , 30, 30, 25 - , 1, -0.8, afTrackFall); + , 1, -0.8, trackFall); if (v2 > v1) or {don't encourage turning for no gain}((v2 = v1) and (not Me^.dX.isNegative)) then @@ -973,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 57a508884052 -r 0a494f951dcf hedgewars/uAILandMarks.pas --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hedgewars/uAILandMarks.pas Thu Jul 26 11:10:56 2012 +0200 @@ -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 57a508884052 -r 0a494f951dcf hedgewars/uAIMisc.pas --- a/hedgewars/uAIMisc.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uAIMisc.pas Thu Jul 26 11:10:56 2012 +0200 @@ -54,6 +54,7 @@ procedure freeModule; procedure FillTargets; +procedure AddBonus(x, y: LongInt; r: Longword; s: LongInt); inline; procedure FillBonuses(isAfterAttack: boolean); procedure AwareOfExplosion(x, y, r: LongInt); inline; @@ -80,6 +81,11 @@ ar: array[0..Pred(MAXBONUS)] of TBonus; end; + walkbonuses: record + Count: Longword; + ar: array[0..Pred(MAXBONUS div 8)] of TBonus; // don't use too many + end; + implementation uses uCollisions, uVariables, uUtils, uDebug, uLandTexture; @@ -140,9 +146,22 @@ end; end; +procedure AddWalkBonus(x, y: LongInt; r: Longword; s: LongInt); inline; +begin +if(walkbonuses.Count < MAXBONUS div 8) then + begin + walkbonuses.ar[walkbonuses.Count].x:= x; + walkbonuses.ar[walkbonuses.Count].y:= y; + walkbonuses.ar[walkbonuses.Count].Radius:= r; + walkbonuses.ar[walkbonuses.Count].Score:= s; + inc(walkbonuses.Count); + end; +end; + procedure FillBonuses(isAfterAttack: boolean); var Gear: PGear; MyClan: PClan; + i: Longint; begin bonuses.Count:= 0; MyClan:= ThinkingHH^.Hedgehog^.Team^.Clan; @@ -151,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); @@ -178,7 +197,9 @@ if Gear^.Damage >= Gear^.Health then AddBonus(hwRound(Gear^.X), hwRound(Gear^.Y), 60, -25) else - if isAfterAttack and (ThinkingHH^.Hedgehog <> Gear^.Hedgehog) then + if isAfterAttack + and (ThinkingHH^.Hedgehog <> Gear^.Hedgehog) + and ((hwAbs(Gear^.dX) + hwAbs(Gear^.dY)) < _0_1) then if (ClansCount > 2) or (MyClan = Gear^.Hedgehog^.Team^.Clan) then AddBonus(hwRound(Gear^.X), hwRound(Gear^.Y), 150, -3) // hedgehog-friend else @@ -190,6 +211,13 @@ if isAfterAttack and (KnownExplosion.Radius > 0) then with KnownExplosion do AddBonus(X, Y, Radius + 10, -Radius); +if isAfterAttack then + begin + for i:= 0 to Pred(walkbonuses.Count) do + with walkbonuses.ar[i] do + AddBonus(X, Y, Radius, Score); + walkbonuses.Count:= 0 + end; end; procedure AwareOfExplosion(x, y, r: LongInt); inline; @@ -343,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 @@ -404,25 +432,28 @@ begin dX:= 0.005 * dmg + 0.01; dY:= dX; - fallDmg:= trunc(TraceFall(x, y, Point.x, Point.y, dX, dY, erasure) * dmgMod); + 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 + fallDmg:= trunc(TraceFall(x, y, Point.x, Point.y, dX, dY, 0) * dmgMod) + else fallDmg:= trunc(TraceFall(x, y, Point.x, Point.y, dX, dY, erasure) * dmgMod) 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; @@ -503,7 +534,10 @@ dY:= gdY * dmg; if dX < 0 then dX:= dX - 0.01 else dX:= dX + 0.01; - fallDmg:= trunc(TraceFall(x, y, Point.x, Point.y, dX, dY, erasure) * dmgMod); + 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 + fallDmg:= trunc(TraceFall(x, y, Point.x, Point.y, dX, dY, 0) * dmgMod) + else fallDmg:= trunc(TraceFall(x, y, Point.x, Point.y, dX, dY, erasure) * dmgMod); 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 @@ -590,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 @@ -611,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: @@ -636,20 +676,31 @@ end; function HHGo(Gear, AltGear: PGear; var GoInfo: TGoInfo): boolean; -var pX, pY: LongInt; +var pX, pY, tY: LongInt; begin HHGo:= false; +Gear^.CollisionMask:= $FF7F; AltGear^:= Gear^; GoInfo.Ticks:= 0; GoInfo.FallPix:= 0; 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;} -repeat pX:= hwRound(Gear^.X); pY:= hwRound(Gear^.Y); if pY + cHHRadius >= cWaterLine then - exit(false); + begin + if AltGear^.Hedgehog^.BotLevel < 4 then + AddWalkBonus(pX, tY, 250, -40); + exit(false) + end; // hog is falling if (Gear^.State and gstMoving) <> 0 then @@ -658,9 +709,11 @@ 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 + AddWalkBonus(pX, tY, 175, -20); exit(false) end; Gear^.Y:= Gear^.Y + Gear^.dY; @@ -669,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 57a508884052 -r 0a494f951dcf hedgewars/uAmmos.pas --- a/hedgewars/uAmmos.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uAmmos.pas Thu Jul 26 11:10:56 2012 +0200 @@ -32,6 +32,7 @@ procedure SetAmmoReinforcement(var s: shortstring); procedure AssignStores; procedure AddAmmo(var Hedgehog: THedgehog; ammo: TAmmoType); +procedure AddAmmo(var Hedgehog: THedgehog; ammo: TAmmoType; amt: LongWord); procedure SetAmmo(var Hedgehog: THedgehog; ammo: TAmmoType; cnt: LongWord); function HHHasAmmo(var Hedgehog: THedgehog; Ammo: TAmmoType): LongWord; procedure PackAmmo(Ammo: PHHAmmo; Slot: LongInt); @@ -188,7 +189,7 @@ end end; -procedure AddAmmo(var Hedgehog: THedgehog; ammo: TAmmoType); +procedure AddAmmo(var Hedgehog: THedgehog; ammo: TAmmoType; amt: LongWord); var cnt: LongWord; a: PAmmo; begin @@ -199,11 +200,16 @@ cnt:= 0; if (cnt <> AMMO_INFINITE) then begin - inc(cnt, Ammoz[ammo].NumberInCase); + inc(cnt, amt); SetAmmo(Hedgehog, ammo, cnt) end end; +procedure AddAmmo(var Hedgehog: THedgehog; ammo: TAmmoType); +begin + AddAmmo(Hedgehog, ammo, Ammoz[ammo].NumberInCase); +end; + procedure SetAmmo(var Hedgehog: THedgehog; ammo: TAmmoType; cnt: LongWord); var ammos: TAmmoCounts; slot, ami: LongInt; @@ -297,22 +303,23 @@ procedure ApplyAngleBounds(var Hedgehog: THedgehog; AmmoType: TAmmoType); begin -with Hedgehog do - begin - CurMinAngle:= Ammoz[AmmoType].minAngle; - if Ammoz[AmmoType].maxAngle <> 0 then - CurMaxAngle:= Ammoz[AmmoType].maxAngle - else - CurMaxAngle:= cMaxAngle; +if Hedgehog.Gear <> nil then + with Hedgehog do + begin + CurMinAngle:= Ammoz[AmmoType].minAngle; + if Ammoz[AmmoType].maxAngle <> 0 then + CurMaxAngle:= Ammoz[AmmoType].maxAngle + else + CurMaxAngle:= cMaxAngle; - with Hedgehog.Gear^ do - begin - if Angle < CurMinAngle then - Angle:= CurMinAngle; - if Angle > CurMaxAngle then - Angle:= CurMaxAngle; + with Hedgehog.Gear^ do + begin + if Angle < CurMinAngle then + Angle:= CurMinAngle; + if Angle > CurMaxAngle then + Angle:= CurMaxAngle; + end end - end end; procedure SwitchToFirstLegalAmmo(var Hedgehog: THedgehog); @@ -367,19 +374,19 @@ 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]; AddCaption(s, Team^.Clan^.Color, capgrpAmmoinfo); if (Propz and ammoprop_NeedTarget) <> 0 then begin - Gear^.State:= Gear^.State or gstHHChooseTarget; + if Gear <> nil then Gear^.State:= Gear^.State or gstHHChooseTarget; isCursorVisible:= true end else begin - Gear^.State:= Gear^.State and not gstHHChooseTarget; + if Gear <> nil then Gear^.State:= Gear^.State and (not gstHHChooseTarget); isCursorVisible:= false end; end diff -r 57a508884052 -r 0a494f951dcf hedgewars/uCommandHandlers.pas --- a/hedgewars/uCommandHandlers.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uCommandHandlers.pas Thu Jul 26 11:10:56 2012 +0200 @@ -412,18 +412,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; @@ -431,11 +432,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; @@ -652,6 +653,7 @@ procedure chSpeedup_p(var s: shortstring); begin s:= s; // avoid compiler hint +SpeedStart:= RealTicks; isSpeed:= true end; @@ -764,7 +766,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); @@ -785,21 +787,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); @@ -845,10 +847,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 57a508884052 -r 0a494f951dcf hedgewars/uCommands.pas --- a/hedgewars/uCommands.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uCommands.pas Thu Jul 26 11:10:56 2012 +0200 @@ -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 57a508884052 -r 0a494f951dcf hedgewars/uConsts.pas --- a/hedgewars/uConsts.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uConsts.pas Thu Jul 26 11:10:56 2012 +0200 @@ -146,6 +146,7 @@ cBarrelHealth = 60; cShotgunRadius = 22; cBlowTorchC = 6; + cakeDmg = 75; cKeyMaxIndex = 1023; cKbdMaxIndex = 65536;//need more room for the modifier keys @@ -227,20 +228,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; @@ -263,6 +267,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 57a508884052 -r 0a494f951dcf hedgewars/uGame.pas --- a/hedgewars/uGame.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uGame.pas Thu Jul 26 11:10:56 2012 +0200 @@ -46,7 +46,14 @@ if (GameType = gmtDemo) then if isSpeed then - Lag:= Lag * 10 + begin + 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 57a508884052 -r 0a494f951dcf hedgewars/uGears.pas --- a/hedgewars/uGears.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uGears.pas Thu Jul 26 11:10:56 2012 +0200 @@ -37,7 +37,7 @@ procedure initModule; procedure freeModule; -function SpawnCustomCrateAt(x, y: LongInt; crate: TCrateType; content: Longword ): PGear; +function SpawnCustomCrateAt(x, y: LongInt; crate: TCrateType; content, cnt: Longword): PGear; function SpawnFakeCrateAt(x, y: LongInt; crate: TCrateType; explode: boolean; poison: boolean ): PGear; function GetAmmo(Hedgehog: PHedgehog): TAmmoType; function GetUtility(Hedgehog: PHedgehog): TAmmoType; @@ -59,13 +59,13 @@ uses uStore, uSound, uTeams, uRandom, uCollisions, uIO, uLandGraphics, uLocale, uAI, uAmmos, uStats, uVisualGears, uScript, GLunit, uMobile, uVariables, uCommands, uUtils, uTextures, uRenderUtils, uGearsRender, uCaptions, uDebug, uLandTexture, - uGearsHedgehog, uGearsUtils, uGearsList; + uGearsHedgehog, uGearsUtils, uGearsList, uGearsHandlers; var skipFlag: boolean; procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt); forward; //procedure AmmoFlameWork(Ammo: PGear); forward; -function GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): TPGearArray; forward; +function GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): PGearArrayS; forward; procedure SpawnBoxOfSmth; forward; procedure ShotgunShot(Gear: PGear); forward; procedure doStepCase(Gear: PGear); forward; @@ -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 @@ -871,25 +887,30 @@ end end; -function GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): TPGearArray; +var GearsNearArray : TPGearArray; +function GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): PGearArrayS; var t: PGear; - l: Longword; + s: Longword; begin r:= r*r; - GearsNear := nil; + s:= 0; + SetLength(GearsNearArray, s); t := GearsList; while t <> nil do begin if (t^.Kind = Kind) and ((X - t^.X)*(X - t^.X) + (Y - t^.Y)*(Y-t^.Y) < int2hwFloat(r)) then begin - l:= Length(GearsNear); - SetLength(GearsNear, l + 1); - GearsNear[l] := t; + inc(s); + SetLength(GearsNearArray, s); + GearsNearArray[s - 1] := t; end; t := t^.NextGear; end; + + GearsNear.size:= s; + GearsNear.ar:= @GearsNearArray end; {procedure AmmoFlameWork(Ammo: PGear); @@ -928,7 +949,7 @@ CountGears:= count; end; -function SpawnCustomCrateAt(x, y: LongInt; crate: TCrateType; content: Longword): PGear; +function SpawnCustomCrateAt(x, y: LongInt; crate: TCrateType; content, cnt: Longword): PGear; begin FollowGear := AddGear(x, y, gtCase, 0, _0, _0, 0); cCaseFactor := 0; @@ -936,6 +957,8 @@ if (crate <> HealthCrate) and (content > ord(High(TAmmoType))) then content := ord(High(TAmmoType)); + FollowGear^.Power:= cnt; + case crate of HealthCrate: begin @@ -1306,7 +1329,9 @@ @doStepStructure, @doStepLandGun, @doStepTardis, - @doStepIceGun); + @doStepIceGun, + @doStepAddAmmo, + @doStepGenericFaller); begin doStepHandlers:= handlers; @@ -1315,6 +1340,8 @@ CurAmmoGear:= nil; GearsList:= nil; + curHandledGear:= nil; + KilledHHs:= 0; SuddenDeath:= false; SuddenDeathDmg:= false; diff -r 57a508884052 -r 0a494f951dcf hedgewars/uGearsHandlers.pas --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hedgewars/uGearsHandlers.pas Thu Jul 26 11:10:56 2012 +0200 @@ -0,0 +1,87 @@ +(* + * Hedgewars, a free turn based strategy game + * Copyright (c) 2004-2012 Andrey Korotaev + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + *) + +{$INCLUDE "options.inc"} + +unit uGearsHandlers; +interface + +uses uTypes; + +procedure cakeStep(Gear: PGear); + +implementation + +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 := (Gear^.Angle - dA) and 3 +end; + +procedure NextAngle(Gear: PGear; dA: LongInt); inline; +begin + Gear^.Angle := (Gear^.Angle + dA) and 3 +end; + +procedure cakeStep(Gear: PGear); +var + xx, yy, xxn, yyn: LongInt; + dA: LongInt; + tdx, tdy: hwFloat; +begin + dA := hwSign(Gear^.dX); + xx := dirs[Gear^.Angle].x; + yy := dirs[Gear^.Angle].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 + PrevAngle(Gear, dA) + else + begin + Gear^.Tag := 0; + Gear^.Y := Gear^.Y + int2hwFloat(yy); + if not TestCollisionXwithGear(Gear, xxn) then + begin + Gear^.X := Gear^.X + int2hwFloat(xxn); + NextAngle(Gear, dA) + end; + end; + + if (yy = 0) then + if TestCollisionXwithGear(Gear, xx) then + PrevAngle(Gear, dA) + else + begin + Gear^.Tag := 0; + Gear^.X := Gear^.X + int2hwFloat(xx); + if TestCollisionYwithGear(Gear, yyn) = 0 then + begin + Gear^.Y := Gear^.Y + int2hwFloat(yyn); + NextAngle(Gear, dA) + end; + end; +end; + +end. diff -r 57a508884052 -r 0a494f951dcf hedgewars/uGearsHedgehog.pas --- a/hedgewars/uGearsHedgehog.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uGearsHedgehog.pas Thu Jul 26 11:10:56 2012 +0200 @@ -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, @@ -355,7 +356,6 @@ newGear:= AddGear(hwRound(lx), hwRound(ly), gtResurrector, 0, _0, _0, 0); newGear^.SoundChannel := LoopSound(sndResurrector); end; - //amMelonStrike: AddGear(CurWeapon^.Pos, 0, gtAirAttack, 4, _0, _0, 0); amStructure: newGear:= AddGear(hwRound(lx) + hwSign(dX) * 7, hwRound(ly), gtStructure, gstWait, SignAs(_0_02, dX), _0, 3000); amTardis: newGear:= AddGear(hwRound(X), hwRound(Y), gtTardis, 0, _0, _0, 5000); amIceGun: newGear:= AddGear(hwRound(X), hwRound(Y), gtIceGun, 0, _0, _0, 0); @@ -566,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) @@ -586,35 +612,35 @@ 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 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; - 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 = gmtDemo) then - begin - 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); @@ -827,7 +853,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 @@ -953,11 +979,11 @@ SetLittle(Gear^.dX); if (not isFalling) -and (hwAbs(Gear^.dX) + hwAbs(Gear^.dY) < _0_03) then + and (hwAbs(Gear^.dX) + hwAbs(Gear^.dY) < _0_03) then begin Gear^.State:= Gear^.State and (not gstWinner); Gear^.State:= Gear^.State and (not gstMoving); - while TestCollisionYWithGear(Gear,1) = 0 do + while (TestCollisionYWithGear(Gear,1) = 0) and (not CheckGearDrowning(Gear)) do Gear^.Y:= Gear^.Y+_1; SetLittle(Gear^.dX); Gear^.dY:= _0 @@ -1221,6 +1247,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 57a508884052 -r 0a494f951dcf hedgewars/uGearsList.pas --- a/hedgewars/uGearsList.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uGearsList.pas Thu Jul 26 11:10:56 2012 +0200 @@ -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 @@ -40,7 +42,7 @@ begin tmp:= GearsList; ptmp:= GearsList; - while (tmp <> nil) and (tmp^.Z <= Gear^.Z) do + while (tmp <> nil) and (tmp^.Z < Gear^.Z) do begin ptmp:= tmp; tmp:= tmp^.NextGear @@ -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,11 +98,9 @@ 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]; @@ -104,7 +108,7 @@ if CurrentHedgehog <> nil then gear^.Hedgehog:= CurrentHedgehog; -if Ammoz[Gear^.AmmoType].Ammo.Propz and ammoprop_NeedTarget <> 0 then +if (Ammoz[Gear^.AmmoType].Ammo.Propz and ammoprop_NeedTarget <> 0) then gear^.Z:= cHHZ+1 else gear^.Z:= cUsualZ; @@ -294,6 +298,7 @@ gear^.Radius:= 15; gear^.Tag:= Y end; + gtAirAttack: gear^.Z:= cHHZ+2; gtAirBomb: begin gear^.Radius:= 5; gear^.Density:= _2; @@ -458,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); @@ -555,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 57a508884052 -r 0a494f951dcf hedgewars/uGearsRender.pas --- a/hedgewars/uGearsRender.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uGearsRender.pas Thu Jul 26 11:10:56 2012 +0200 @@ -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); @@ -1015,10 +1015,10 @@ DrawSprite(sprUtility, x - 24, y - 24, i); end; end; - if Gear^.Timer <= 1833 then + if Gear^.Timer < 1833 then begin DrawTextureRotatedF(SpritesData[sprPortal].texture, min(abs(1.25 - (Gear^.Timer mod 1333) / 400), 1.25), 0, 0, - Gear^.Angle+WorldDx, Gear^.Power+WorldDy-16, 4+Gear^.Tag, 1, 32, 32, 270); + x, Gear^.Angle+WorldDy-16, 4+Gear^.Tag, 1, 32, 32, 270); end end; gtExplosives: begin @@ -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 57a508884052 -r 0a494f951dcf hedgewars/uGearsUtils.pas --- a/hedgewars/uGearsUtils.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uGearsUtils.pas Thu Jul 26 11:10:56 2012 +0200 @@ -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; @@ -403,34 +415,40 @@ begin splash:= AddVisualGear(X, cWaterLine, vgtSplash); if splash <> nil then + with splash^ do begin - splash^.Scale:= hwFloat2Float(Gear^.Density / _3 * Gear^.dY); - if splash^.Scale > 1 then splash^.Scale:= power(splash^.Scale,0.3333) - else splash^.Scale:= splash^.Scale + ((1-splash^.Scale) / 2); + 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(min(Scale*0.0005/cGravityf,4)) + else Timer:= 1; + // Low Gravity + FrameTicks:= FrameTicks*Timer; end; maxDrops := (hwRound(Gear^.Density) * 3) div 2 + round(vdX * hwRound(Gear^.Density) * 6) + round(vdY * hwRound(Gear^.Density) * 6); for i:= max(maxDrops div 3, min(32, Random(maxDrops))) downto 0 do begin - particle := AddVisualGear(X - 3 + Random(6), cWaterLine, vgtDroplet); + particle := AddVisualGear(X - 3 + Random(7), cWaterLine, vgtDroplet); if particle <> nil then - begin - particle^.dX := particle^.dX - vdX / 10; - particle^.dY := particle^.dY - vdY / 5; - if splash <> nil then + with particle^ do begin - if splash^.Scale > 1 then + dX := dX - vdX / 10; + dY := dY - vdY / 5; + if splash <> nil then begin - particle^.dX:= particle^.dX * power(splash^.Scale,0.3333); // tone down the droplet height further - particle^.dY:= particle^.dY * power(splash^.Scale, 0.3333) - end - else - begin - particle^.dX:= particle^.dX * splash^.Scale; - particle^.dY:= particle^.dY * splash^.Scale + if splash^.Scale > 1 then + begin + dX:= dX * power(splash^.Scale,0.3333); // tone down the droplet height further + dY:= dY * power(splash^.Scale, 0.3333) + end + else + begin + dX:= dX * splash^.Scale; + dY:= dY * splash^.Scale + end end end - end end end; if isSubmersible and (CurAmmoGear^.Pos = 0) then @@ -446,6 +464,10 @@ sparkles: PVisualGear; gX, gY: LongInt; begin + if (Gear^.LastDamage <> nil) then + uStats.HedgehogDamaged(Gear, Gear^.LastDamage, 0, true) + else + uStats.HedgehogDamaged(Gear, CurrentHedgehog, 0, true); AttackBar:= 0; gear^.dX := _0; gear^.dY := _0; diff -r 57a508884052 -r 0a494f951dcf hedgewars/uIO.pas --- a/hedgewars/uIO.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uIO.pas Thu Jul 26 11:10:56 2012 +0200 @@ -402,7 +402,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 57a508884052 -r 0a494f951dcf hedgewars/uInputHandler.pas --- a/hedgewars/uInputHandler.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uInputHandler.pas Thu Jul 26 11:10:56 2012 +0200 @@ -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'h')]:= 'findhh'; DefaultBinds[KeyNameToCode(_S'p')]:= 'pause'; diff -r 57a508884052 -r 0a494f951dcf hedgewars/uRandom.pas --- a/hedgewars/uRandom.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uRandom.pas Thu Jul 26 11:10:56 2012 +0200 @@ -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 57a508884052 -r 0a494f951dcf hedgewars/uScript.pas --- a/hedgewars/uScript.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uScript.pas Thu Jul 26 11:10:56 2012 +0200 @@ -322,7 +322,7 @@ health:= lua_tointeger(L, 3) else health:= cHealthCaseAmount; - gear := SpawnCustomCrateAt(lua_tointeger(L, 1), lua_tointeger(L, 2), HealthCrate, health); + gear := SpawnCustomCrateAt(lua_tointeger(L, 1), lua_tointeger(L, 2), HealthCrate, health, 0); if gear <> nil then lua_pushinteger(L, gear^.uid) else @@ -334,14 +334,16 @@ function lc_spawnammocrate(L: PLua_State): LongInt; Cdecl; var gear: PGear; begin - if lua_gettop(L) <> 3 then + if (lua_gettop(L) <> 3) and (lua_gettop(L) <> 4) then begin LuaError('Lua: Wrong number of parameters passed to SpawnAmmoCrate!'); lua_pushnil(L); end else begin - gear := SpawnCustomCrateAt(lua_tointeger(L, 1), lua_tointeger(L, 2), AmmoCrate, lua_tointeger(L, 3)); + if (lua_gettop(L) = 3) then + gear := SpawnCustomCrateAt(lua_tointeger(L, 1), lua_tointeger(L, 2), AmmoCrate, lua_tointeger(L, 3), 0) + else gear := SpawnCustomCrateAt(lua_tointeger(L, 1), lua_tointeger(L, 2), AmmoCrate, lua_tointeger(L, 3), lua_tointeger(L, 4)); if gear <> nil then lua_pushinteger(L, gear^.uid) else @@ -353,15 +355,16 @@ function lc_spawnutilitycrate(L: PLua_State): LongInt; Cdecl; var gear: PGear; begin - if lua_gettop(L) <> 3 then + if (lua_gettop(L) <> 3) and (lua_gettop(L) <> 4) then begin LuaError('Lua: Wrong number of parameters passed to SpawnUtilityCrate!'); lua_pushnil(L); end else - begin - gear := SpawnCustomCrateAt(lua_tointeger(L, 1), lua_tointeger(L, 2), - UtilityCrate, lua_tointeger(L, 3)); + begin + if (lua_gettop(L) = 3) then + gear := SpawnCustomCrateAt(lua_tointeger(L, 1), lua_tointeger(L, 2), UtilityCrate, lua_tointeger(L, 3), 0) + else gear := SpawnCustomCrateAt(lua_tointeger(L, 1), lua_tointeger(L, 2), UtilityCrate, lua_tointeger(L, 3), lua_tointeger(L, 4)); if gear <> nil then lua_pushinteger(L, gear^.uid) else @@ -978,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; @@ -989,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 57a508884052 -r 0a494f951dcf hedgewars/uSound.pas --- a/hedgewars/uSound.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uSound.pas Thu Jul 26 11:10:56 2012 +0200 @@ -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 57a508884052 -r 0a494f951dcf hedgewars/uTeams.pas --- a/hedgewars/uTeams.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uTeams.pas Thu Jul 26 11:10:56 2012 +0200 @@ -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 57a508884052 -r 0a494f951dcf hedgewars/uTypes.pas --- a/hedgewars/uTypes.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uTypes.pas Thu Jul 26 11:10:56 2012 +0200 @@ -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, @@ -260,6 +260,10 @@ LastDamage: PHedgehog; end; TPGearArray = array of PGear; + PGearArrayS = record + size: LongWord; + ar: ^TPGearArray; + end; PVisualGear = ^TVisualGear; TVGearStepProcedure = procedure (Gear: PVisualGear; Steps: Longword); @@ -336,6 +340,8 @@ HatTex: PTexture; Ammo: PHHAmmo; CurAmmoType: TAmmoType; + PickUpType: LongWord; + PickUpDelay: LongInt; AmmoStore: Longword; Team: PTeam; MultiShootAttacks: Longword; @@ -400,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 57a508884052 -r 0a494f951dcf hedgewars/uVariables.pas --- a/hedgewars/uVariables.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uVariables.pas Thu Jul 26 11:10:56 2012 +0200 @@ -60,10 +60,12 @@ isPaused : boolean; isInMultiShoot : boolean; isSpeed : boolean; + SpeedStart : LongWord; fastUntilLag : boolean; autoCameraOn : boolean; + CheckSum : LongWord; GameTicks : LongWord; GameState : TGameState; GameType : TGameType; @@ -98,6 +100,7 @@ cWaterLine : Word; cGearScrEdgesDist: LongInt; + isAudioMuted : boolean; // originally typed consts ExplosionBorderColor: LongWord; @@ -1443,7 +1446,8 @@ NumberInCase: 1; Ammo: (Propz: ammoprop_ForwMsgs or ammoprop_NoCrosshair or - ammoprop_DontHold; + ammoprop_DontHold or + ammoprop_Track; Count: 1; NumPerTurn: 0; Timer: 0; @@ -2368,6 +2372,8 @@ (* gtLandGun *) , amLandGun (* gtTardis *) , amTardis (* gtIceGun *) , amIceGun +(* gtAddAmmo *) , amNothing +(* gtGenericFaller *) , amNothing ); var @@ -2530,6 +2536,7 @@ CursorMovementX := 0; CursorMovementY := 0; GameTicks := 0; + CheckSum := 0; cWaterLine := LAND_HEIGHT; cGearScrEdgesDist := 240; @@ -2578,6 +2585,7 @@ isPaused := false; isInMultiShoot := false; isSpeed := false; + SpeedStart := 0; fastUntilLag := false; autoCameraOn := true; cScriptName := ''; @@ -2611,7 +2619,6 @@ ExplosionBorderColor:= $FF808080; WaterOpacity:= $80; SDWaterOpacity:= $80; - GrayScale:= false; LuaGoals:= ''; end; @@ -2638,6 +2645,7 @@ cScriptName := ''; cReadyDelay := 5000; cStereoMode := smNone; + GrayScale := false; end; end. diff -r 57a508884052 -r 0a494f951dcf hedgewars/uVisualGears.pas --- a/hedgewars/uVisualGears.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uVisualGears.pas Thu Jul 26 11:10:56 2012 +0200 @@ -295,13 +295,13 @@ dy:= 0; FrameTicks:= 740; Frame:= 19; + Scale:= 0.75; + Timer:= 1; end; vgtDroplet: begin - dx:= 0.001 * (random(75) + 15); - dy:= -0.001 * (random(80) + 120); - if random(2) = 0 then - dx := -dx; + dx:= 0.001 * (random(180) - 90); + dy:= -0.001 * (random(160) + 40); FrameTicks:= 250 + random(1751); Frame:= random(3) end; @@ -651,10 +651,10 @@ DrawTextureF(SpritesData[sprFlame].Texture, Gear^.FrameTicks / 900, round(Gear^.X) + WorldDx, round(Gear^.Y) + WorldDy, (RealTicks shr 7 + Gear^.Frame) mod 8, 1, 16, 16); vgtSplash: if SuddenDeathDmg then //DrawSprite(sprSDSplash, round(Gear^.X) + WorldDx - 40, round(Gear^.Y) + WorldDy - 58, 19 - (Gear^.FrameTicks div 37)) - DrawTextureF(SpritesData[sprSDSplash].Texture, Gear^.scale, round(Gear^.X + WorldDx), round(Gear^.Y + WorldDy - ((SpritesData[sprSDSplash].Height+8)*Gear^.Scale)/2), 19 - (Gear^.FrameTicks div 37), 1, SpritesData[sprSDSplash].Width, SpritesData[sprSDSplash].Height) + DrawTextureF(SpritesData[sprSDSplash].Texture, Gear^.scale, round(Gear^.X + WorldDx), round(Gear^.Y + WorldDy - ((SpritesData[sprSDSplash].Height+8)*Gear^.Scale)/2), 19 - (Gear^.FrameTicks div Gear^.Timer div 37), 1, SpritesData[sprSDSplash].Width, SpritesData[sprSDSplash].Height) else //DrawSprite(sprSplash, round(Gear^.X) + WorldDx - 40, round(Gear^.Y) + WorldDy - 58, 19 - (Gear^.FrameTicks div 37)); - DrawTextureF(SpritesData[sprSplash].Texture, Gear^.scale, round(Gear^.X + WorldDx), round(Gear^.Y + WorldDy - ((SpritesData[sprSplash].Height+8)*Gear^.Scale)/2), 19 - (Gear^.FrameTicks div 37), 1, SpritesData[sprSplash].Width, SpritesData[sprSplash].Height); + DrawTextureF(SpritesData[sprSplash].Texture, Gear^.scale, round(Gear^.X + WorldDx), round(Gear^.Y + WorldDy - ((SpritesData[sprSplash].Height+8)*Gear^.Scale)/2), 19 - (Gear^.FrameTicks div Gear^.Timer div 37), 1, SpritesData[sprSplash].Width, SpritesData[sprSplash].Height); vgtDroplet: if SuddenDeathDmg then DrawSprite(sprSDDroplet, round(Gear^.X) + WorldDx - 8, round(Gear^.Y) + WorldDy - 8, Gear^.Frame) else diff -r 57a508884052 -r 0a494f951dcf hedgewars/uWorld.pas --- a/hedgewars/uWorld.pas Thu Jul 26 11:01:32 2012 +0200 +++ b/hedgewars/uWorld.pas Thu Jul 26 11:10:56 2012 +0200 @@ -1329,7 +1329,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 @@ -1365,6 +1365,19 @@ r.w:= TeamHealthBarWidth + 1; r.h:= HealthTex^.h - 4; DrawTextureFromRect(16, cScreenHeight + DrawHealthY + smallScreenOffset + 2, @r, HealthTex); + if not hasGone and (TeamHealth > 1) then + begin + Tint(Clan^.Color shl 8 or $FF); + for i:= 0 to cMaxHHIndex do + if Hedgehogs[i].Gear <> nil then + begin + inc(h,Hedgehogs[i].Gear^.Health); + if h < TeamHealth then DrawTexture(15 + h*TeamHealthBarWidth div TeamHealth, cScreenHeight + DrawHealthY + smallScreenOffset + 1, SpritesData[sprSlider].Texture); + end; + if TeamsCount * 20 > Longword(cScreenHeight) div 5 then + Tint($FF,$FF,$FF,$80) + else Tint($FF, $FF, $FF, $FF); + end; end; end; if smallScreenOffset <> 0 then @@ -1513,14 +1526,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); @@ -1589,9 +1604,10 @@ isFirstFrame:= false end; +var PrevSentPointTime: LongWord = 0; + procedure MoveCamera; var EdgesDist, wdy, shs,z: LongInt; - PrevSentPointTime: LongWord = 0; begin {$IFNDEF MOBILE} if (not (CurrentTeam^.ExtDriven and isCursorVisible and (not bShowAmmoMenu))) and cHasFocus and (GameState <> gsConfirm) then @@ -1601,7 +1617,7 @@ if not PlacingHogs and (FollowGear <> nil) and (not isCursorVisible) and (not bShowAmmoMenu) and (not fastUntilLag) then if (not autoCameraOn) then FollowGear:= nil - else + else if ((abs(CursorPoint.X - prevPoint.X) + abs(CursorPoint.Y - prevpoint.Y)) > 4) then begin FollowGear:= nil; @@ -1814,6 +1830,7 @@ Frames:= 0; WorldDx:= -512; WorldDy:= -256; + PrevSentPointTime:= 0; FPS:= 0; CountTicks:= 0; diff -r 57a508884052 -r 0a494f951dcf share/hedgewars/Data/Graphics/hedgewars.svg --- a/share/hedgewars/Data/Graphics/hedgewars.svg Thu Jul 26 11:01:32 2012 +0200 +++ b/share/hedgewars/Data/Graphics/hedgewars.svg Thu Jul 26 11:10:56 2012 +0200 @@ -15,10 +15,29 @@ id="svg3761" version="1.1" inkscape:version="0.48.3.1 r9886" - sodipodi:docname="hedgewars2.svg"> + sodipodi:docname="hedgewars.svg"> + + + + + + + + + inkscape:window-width="1896" + inkscape:window-height="1026" + inkscape:window-x="24" + inkscape:window-y="0" + inkscape:window-maximized="1" + showguides="true" + inkscape:guide-bbox="true"> + + @@ -150,7 +198,7 @@ image/svg+xml - + @@ -159,37 +207,33 @@ inkscape:groupmode="layer" id="layer1" transform="translate(603.97091,-479.69834)"> - - - - - - - - - + + + + + diff -r 57a508884052 -r 0a494f951dcf share/hedgewars/Data/Locale/da.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/hedgewars/Data/Locale/da.lua Thu Jul 26 11:10:56 2012 +0200 @@ -0,0 +1,220 @@ +locale = { + [":("] = ":(", + ["!!!"] = "!!!", + ["..."] = "...", + ["Accuracy Bonus!"] = "Præcisionsbonus", + ["Achievement Unlocked"] = "Bedrift Fuldført", -- User_Mission_-_Bamboo_Thicket, User_Mission_-_That_Sinking_Feeling, Tumbler + ["a Hedgewars mini-game"] = "et Hedgewars-minispil", -- Space_Invasion, The_Specialists + ["Aiming Practice"] = "Sigtetræning", --Bazooka, Shotgun, SniperRifle + ["Ammo"] = "Ammunition", + ["Ammo Depleted!"] = "Ammunition Udtømt", + ["ammo extended!"] = "ammunition udstrakt", + ["Ammo is reset at the end of your turn."] = "Ammunition nulstilles i slutningen af turen", + ["Ammo Maniac!"] = "Ammunitionsgalskab", + ["Available points remaining: "] = "Tilgængeligt point tilbage: ", + ["[Backspace]"] = "[Tilbage]", + ["Bamboo Thicket"] = "Bambusbuskads", + ["Barrel Eater!"] = "Tøndeæder!", + ["Barrel Launcher"] = "Tøndekaster", + ["Bat balls at your enemies and|push them into the sea!"] = "Slå bolde på dine fjender og|skub dem i havet!", + ["Bat your opponents through the|baskets and out of the map!"] = "Slå dine modstandere gennem|kurvene og ud af banen!", + ["Bazooka Training"] = "Træning med Bazooka", + ["Best laps per team: "] = "Bedste omgang per hold: ", + ["Best Team Times: "] = "Bedste Holdtid: ", + ["Bloody Rookies"] = "Forbandede Begyndere", -- 01#Boot_Camp, User_Mission_-_Dangerous_Ducklings, User_Mission_-_Diver, User_Mission_-_Spooky_Tree + ["Boom!"] = "Bum!", + ["BOOM!"] = "BUM!", + ["Boss defeated!"] = "Boss besejret!", + ["Boss Slayer!"] = "Boss-morder!", + ["Build a track and race."] = "Byg en bane og ræs.", + ["CAPTURE THE FLAG"] = "EROBR FLAGET", + ["Careless"] = "Sløset", + ["Change Weapon"] = "Skift Våben", + ["Clumsy"] = "Kluntet", + ["Codename: Teamwork"] = "Kodeord: Samarbejde", + ["Complete the track as fast as you can!"] = "Gennemfør banen så hurtigt som muligt!", + ["Congratulations!"] = "Tillykke!", + ["Congratulations! You've eliminated all targets|within the allowed time frame."] = "Tillykke! Du har elimineret alle målene|inden for den tilladte tidsramme.", --Bazooka, Shotgun, SniperRifle + ["Control pillars to score points."] = "Kontroller søjler for at score point.", + ["Cybernetic Empire"] = "Kybernetisk Imperium", + ["DAMMIT, ROOKIE!"] = "FOR HELVEDE, REKRUT!", + ["DAMMIT, ROOKIE! GET OFF MY HEAD!"] = "FOR HELVEDE, REKRUT! KOM NED DERFRA!", + ["Dangerous Ducklings"] = "Farlige Ællinger", + ["Deadweight"] = "Dødvægt", + ["Demolition is fun!"] = "Nedrivning er sjovt!", + ["Depleted Kamikaze!"] = "Udtømt Kamikaze!", + ["Destroy invaders to score points."] = "Tilintetgør indtrængere for at score point.", + ["Double Kill!"] = "Dobbeltdrab!", + ["Drone Hunter!"] = "Dronjæger!", + ["Drowner"] = "Drukner", + ["Each turn you get 1-3 random weapons"] = "Hver tur får du 1-3 tilfældige våben", + ["Each turn you get one random weapon"] = "Hver tur får du ét tilfældigt våben", + ["Eliminate all enemies"] = "Eliminer alle fjender", + ["Eliminate all targets before your time runs out.|You have unlimited ammo for this mission."] = "Eliminer all mål før tiden løber ud.|Du har uendelig ammunition under denne mission.", --Bazooka, Shotgun, SniperRifle + ["Eliminate Poison before the time runs out"] = "Eliminer Giften før tiden løber ud", + ["Eliminate the Blue Team"] = "Eliminer det Blå Hold", + ["Eliminate the enemy before the time runs out"] = "Eliminer fjenden før tiden løber ud", -- User_Mission_-_Bamboo_Thicket, User_Mission_-_Newton_and_the_Hammock + ["Eliminate the enemy hogs to win."] = "Eliminer fjendens pindsvin for at vinde.", + ["Eliminate the enemy specialists."] = "Eliminer fjendens specialister.", + ["- Eliminate Unit 3378 |- Feeble Resistance must survive"] = "- Eliminer Enhed 3378 |- Sølle Modstandere skal overleve", + ["Energetic Engineer"] = "Energisk Ingeniør", + ["Enjoy the swim..."] = "Nyd svømmeturen...", + ["[Enter]"] = "[Enter]", + ["Fastest lap: "] = "Hurtigste omgang: ", + ["Feeble Resistance"] = "Sølle Modstand", + ["Fire"] = "Skyd", + ["Flag captured!"] = "Flag erobred!", + ["Flag respawned!"] = "Flag gendannet!", + ["Flag returned!"] = "Flag returneret!", + ["Flags, and their home base will be placed where each team ends their first turn."] = "Flag og deres hjemmebase bliver placeret der hvor hvert hold afslutter sin første tur.", + ["Flamer"] = "Hetzer", + ["Friendly Fire!"] = "Egenbeskydning!", + ["fuel extended!"] = "brændstof udstrakt!", + ["GAME BEGUN!!!"] = "SPILLET ER STARTET!!!", + ["Game Modifiers: "] = "Spilmodifikatorere", + ["GAME OVER!"] = "SPILLET ER FÆRDIGT!", + ["Game Started!"] = "Spillet er Startet!", + ["Get on over there and take him out!"] = "Kom derover og tag ham ud!", + ["Goal"] = "Mål", + ["GO! GO! GO!"] = "GO! GO! GO!", + ["Good birdy......"] = "God pipfugl......", + ["Good luck out there!"] = "Held og lykke derude!", + ["Good so far!"] = "Godt indtil videre!", + ["Good to go!"] = "Klar!", + ["GOTCHA!"] = "FIK DIG!", + ["Grab Mines/Explosives"] = "Snup Miner/Sprængstof", + ["Hahahaha!"] = "Hahahaha!", + ["Haha, now THAT would be something!"] = "Haha, ja DET ville være noget!", + ["Hapless Hogs"] = "Uheldige Pindsvin", + [" Hapless Hogs left!"] = " Uheldige Pindsvin gik!", + ["Health crates extend your time."] = "Kasse med helbredelse forlænger din tid.", + ["Heavy"] = "Tung", + ["Hedgewars-Basketball"] = "Hedgewars-Basketball", + ["Hedgewars-Knockball"] = "Hedgewars-Knockball", + ["Heh, it's not that bad."] = "Heh, det er ikke så slemt.", + ["Hit Combo!"] = "Slagkombi!", + ["Hmmm..."] = "Hmmm...", + ["Hooray!"] = "Hurra!", + ["Hunter"] = "Jæger", --Bazooka, Shotgun, SniperRifle + ["Instructor"] = "Instruktør", -- 01#Boot_Camp, User_Mission_-_Dangerous_Ducklings + ["invaders destroyed"] = "indtrængere tilintetgjorte", + ["It's a good thing SUDDEN DEATH is 99 turns away..."] = "Det er heldigt at PLUDSELIG DØD er 99 ture væk...", + ["Jumping is disabled"] = "Hop er deaktiveret", + ["Kamikaze Expert!"] = "Kamikaze-ekspert!", + ["Keep it up!"] = "Hold gejsten!", + ["Killing spree!"] = "Drabsorgie!", + ["KILLS"] = "DRAB", + ["Last Target!"] = "Sidste Mål!", + ["[Left Shift]"] = "[Venstre Shift]", + ["Listen up, maggot!!"] = "Lyt efter, maddike!", + ["Lively Lifeguard"] = "Livlig Livredder", + ["Mine Deployer"] = "Mineudsætter", + ["Mine Eater!"] = "Mineæder", + ["|- Mines Time:"] = "|- Tid til Miner:", -- User_Mission_-_Diver, User_Mission_-_Spooky_Tree, User_Mission_-_Teamwork + ["MISSION FAILED"] = "MISSION MISLYKKEDES", -- User_Mission_-_Dangerous_Ducklings, User_Mission_-_Diver, User_Mission_-_Spooky_Tree, User_Mission_-_Teamwork + ["MISSION SUCCESS"] = "MISSION LYKKEDES", + ["MISSION SUCCESSFUL"] = "MISSION VAR SUCCESFULD", -- User_Mission_-_Diver, User_Mission_-_Spooky_Tree, User_Mission_-_Teamwork + ["Movement: [Up], [Down], [Left], [Right]"] = "Bevægelse: [Op], [Ned], [Venstre], [Højre]", + ["Multi-shot!"] = "Flerskud!", + ["Nameless Heroes"] = "Navnløse Helte", + ["New Barrels Per Turn"] = "Nye Tønder Per Tur", + ["NEW CLAN RECORD: "] = "NY KLANREKORD: ", + ["NEW fastest lap: "] = "NY hurtigste omgang: ", + ["New Mines Per Turn"] = "Nyt Antal Miner Per Tur", + ["NEW RACE RECORD: "] = "NY RÆSREKORD: ", + ["Newton's Hammock"] = "Newtons Hængekøje", + ["NOT ENOUGH WAYPOINTS"] = "IKKE NOK RUTEPUNKTER", + ["Not So Friendly Match"] = "Ikke Så Venlig Kamp", -- Basketball, Knockball + ["Oh no! Just try again!"] = "Åh nej! Bare prøv igen!", -- User_Mission_-_Diver, User_Mission_-_Spooky_Tree, User_Mission_-_Teamwork + ["Oh no! Time's up! Just try again."] = "Åh nej! Tiden er løbet ud! Bare prøv igen.", --Bazooka, Shotgun, SniperRifle + ["Operation Diver"] = "Operation Dykker", + ["Opposing Team: "] = "Modstander: ", + ["Pathetic Hog #%d"] = "Patetisk Pindsvin #%d", + ["Pathetic Resistance"] = "Patetisk Modstand", -- User_Mission_-_Bamboo_Thicket, User_Mission_-_Newton_and_the_Hammock + ["Per-Hog Ammo"] = "Ammunition Per Pindsvin", + ["Place more waypoints using [ENTER]"] = "Placer flere rutepunkter med [ENTER]", + ["Place more waypoints using the 'Air Attack' weapon."] = "Placer flere rutepunkter med 'Luftangreb'-våbnet", + ["points"] = "point", -- Control, CTF_Blizzard, Basic_Training_-_Bazooka, Basic_Training_-_Shotgun, Basic_Training_-_Sniper_Rifle + ["Poison"] = "Gift", + ["Power Remaining"] = "Kraft Tilbage", + ["Prepare yourself"] = "Gør dig klar", + ["Press [Precise] to skip intro"] = "Tryk på [Præcis] for at springe introen over", + ["Race complexity limit reached."] = "Kompleksitetsgrænsen for ræset er nået.", + ["RACER"] = "RACER", + [" - Return the enemy flag to your base to score | - First team to 3 captures wins | - You may only score when your flag is in your base | - Hogs will drop the flag if killed, or drowned | - Dropped flags may be returned or recaptured | - Hogs respawn when killed"] = " - Returner fjendens flag til din base for at score | - Første hold til at erobre 3 flag vinder | - Du kan kun score når dit flag er ved din base | Pindsvin taber flaget hvis de dør eller drukner | - Tabte flag kan returneres eller generobres | - Pindsvin genopliver når de bliver dræbt", + ["Round Limit:"] = "Rundebegrænsning: ", + ["Round Limit"] = "Rundebegrænsning", + ["Rounds Complete: "] = "Runder Færdiggjort: ", + ["Rounds Complete"] = "Runder Færdiggjort", + ["RULES OF THE GAME [Press ESC to view]"] = "SPILLETS REGLER [Tryk på ESC for at se]", + ["s|"] = "s|", + ["Save as many hapless hogs as possible!"] = "Red så mange uheldige pindsvin som muligt!", + ["SCORE"] = "SCORE", + ["sec"] = "sek.", -- CTF_Blizzard, TrophyRace, Basic_Training_-_Bazooka, Basic_Training_-_Shotgun, Basic_Training_-_Sniper_Rifle, User_Mission_-_Diver, User_Mission_-_Spooky_Tree, User_Mission_-_Teamwork, Capture_the_Flag + ["See ya!"] = "Ses!", + ["selected!"] = "valgt", + ["s"] = "s", -- GaudyRacer, Space_Invasion + ["Shield boosted! +30 power"] = "Skjold forstærket! +30 kraft", + ["Shield Depleted"] = "Skjold Udtømt", + ["Shield is fully recharged!"] = "Skjold er fuldt genopladt!", + ["Shield Master!"] = "Skjoldmester!", + ["Shield Miser!"] = "Skjoldgnier!", + ["Shield OFF:"] = "Skjold SLÅET FRA:", + ["Shield ON:"] = "Skjold SLÅET TIL:", + ["Shield Seeker!"] = "Skjoldsøger!", + ["Shotgun Team"] = "Haglgeværdshold", + ["Shotgun Training"] = "Træning med Haglgevær", + ["shots remaining."] = "skud tilbage.", + ["Silly"] = "Fjollet", + ["Sinky"] = "Synkende", + ["%s is out and Team %d|scored a penalty!| |Score:"] = "%s er ude og Hold %d|scored en straf!| |Score:", -- Basketball, Knockball + ["%s is out and Team %d|scored a point!| |Score:"] = "%s er ude og Hold %d|scored et point!| |Score:", -- Basketball, Knockball + ["Sniper Training"] = "Træning med Sniperriffel", + ["Sniperz"] = "Sniperz", + ["Sponge"] = "Svamp", + ["Spooky Tree"] = "Uhyggeligt Træ", + ["STATUS UPDATE"] = "STATUSOPDATERING", -- GaudyRacer, Space_Invasion + ["Switched to "] = "Skiftede til ", + ["Team %d: "] = "Hold %d: ", + ["Team Scores"] = "Holdscore", -- Control, Space_Invasion + ["That Sinking Feeling"] = "Følelsen af at Synke", + ["That was pointless."] = "Det var meningsløst.", + ["The enemy is hiding out on yonder ducky!"] = "Fjenden gemmer sig på rapanden derover!", + ["The flag will respawn next round."] = "Flaget gendannes næste runde.", + ["The Nameless One"] = "Den Navnløse Ene", + ["THE SPECIALISTS"] = "SPECIALISTERNE", + ["This one's tricky."] = "Den her er drilagtig.", + ["This rain is really something..."] = "Det her regnvejr er virkelig noget...", + ["TIME: "] = "TID: ", + ["Timed Kamikaze!"] = "Tidsindstillet Kamikaze!", + ["Time Extended!"] = "Tid Forlænget!", + ["Time Extension"] = "Tidsforlængelse", + ["Toggle Shield"] = "Slå Skjold Til/Fra", + ["Toxic Team"] = "Giftigt Hold", -- User_Mission_-_Diver, User_Mission_-_Spooky_Tree, User_Mission_-_Teamwork + ["TRACK COMPLETED"] = "BANE FULDFØRT", + ["TRACK FAILED!"] = "BANE MISLYKKEDES!", + ["TrophyRace"] = "TrofæRæs", + ["T_T"] = "T_T", + ["Tumbling Time Extended!"] = "Tumlende Tid Forlænget", + ["Turn Time"] = "Tid til Tur", + ["Unit"] = "Enhed", + ["Unit 3378"] = "Enhed 3378", + ["Unit 835"] = "Enhed 835", + ["Unlimited Attacks"] = "Uendelige Angreb", + ["Unstoppable!"] = "Ustoppelig!", + ["User Challenge"] = "Brugerudfordring", + ["Use your rope to get from start to finish as fast as you can!"] = "Brug dit reb til at komme fra start til slut så hurtigt som muligt!", + ["Victory for the "] = "Sejr for ", -- CTF_Blizzard, Capture_the_Flag + ["Waypoint placed."] = "Rutepunkt placeret.", + ["Way-Points Remaining"] = "Rutepunkter Tilbage", + ["Weapons Reset"] = "Våben Nulstillede", + ["Well done."] = "Godt klaret.", + ["Will this ever end?"] = "Slutter det her nogensinde?", + ["WINNING TIME: "] = "VINDENDE TID: ", + ["You'd almost swear the water was rising!"] = "Man kunne næsten sværge på at vandet steg!", + ["You have SCORED!!"] = "Du har SCORET!!", + ["You saved"] = "Du reddede", + ["You've failed. Try again."] = "Det lykkedes dig ikke. Prøv igen.", + ["You've reached the goal!| |Time: "] = "Du har nået målet!| |Tid: ", + ["'Zooka Team"] = "'Zooka-hold", + } diff -r 57a508884052 -r 0a494f951dcf share/hedgewars/Data/Locale/en.txt --- a/share/hedgewars/Data/Locale/en.txt Thu Jul 26 11:01:32 2012 +0200 +++ b/share/hedgewars/Data/Locale/en.txt Thu Jul 26 11:10:56 2012 +0200 @@ -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 57a508884052 -r 0a494f951dcf share/hedgewars/Data/Locale/missions_da.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/hedgewars/Data/Locale/missions_da.txt Thu Jul 26 11:10:56 2012 +0200 @@ -0,0 +1,32 @@ +Basic_Training_-_Bazooka.name=Grundliggende Træning med Bazooka +Basic_Training_-_Bazooka.desc="Nøglen er et bruge vinden til din fordel!" + +Basic_Training_-_Grenade.name=Grundliggende Træning med Granater +Basic_Training_-_Grenade.desc="Husk, FØRST hiver du splitten ud OG SÅ kaster du!" + +Basic_Training_-_Shotgun.name=Grundliggende Træning med Haglgevær +Basic_Training_-_Shotgun.desc="Skyd først, spørg bagefter!" + +Basic_Training_-_Sniper_Rifle.name=Grundliggende Træning med Sniperriffel +Basic_Training_-_Sniper_Rifle.desc="Bum, Lige i Hovedet!" + +User_Mission_-_Dangerous_Ducklings.name=Mission: Farlige Ællinger +User_Mission_-_Dangerous_Ducklings.desc="Udmærket, rekrut! Nu skal vi se om du kan huske hvad du har lært!" + +User_Mission_-_Diver.name=Mission: Dykker +User_Mission_-_Diver.desc="Det der 'amfibieangreb' er sværere end det ser ud..." + +User_Mission_-_Teamwork.name=Mission: Samarbejde +User_Mission_-_Teamwork.desc="Kærlighed gør ondt en gang imellem." + +User_Mission_-_Spooky_Tree.name=Mission: Uhyggeligt Træ +User_Mission_-_Spooky_Tree.desc="Der er masser af kasser derude. Men jeg håber virkelig ikke den fugl er sulten." + +User_Mission_-_Bamboo_Thicket.name=Mission: Bambusbuskads +User_Mission_-_Bamboo_Thicket.desc="Døden kommer oppefra." + +User_Mission_-_That_Sinking_Feeling.name=Mission: Følelsen af at Synke +User_Mission_-_That_Sinking_Feeling.desc="Vandet stiger hurtigt og tiden er knap. Mange har prøvet, men få sejret. Kan du redde dem alle sammen?" + +User_Mission_-_Newton_and_the_Hammock.name=Mission: Newton og Hængekøjen +User_Mission_-_Newton_and_the_Hammock.desc="Husk, grislinger: Et legemes hastighed forbliver uændret med mindre legemet bliver påvirket af krafter udefra." \ No newline at end of file diff -r 57a508884052 -r 0a494f951dcf share/hedgewars/Data/Locale/missions_fr.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/hedgewars/Data/Locale/missions_fr.txt Thu Jul 26 11:10:56 2012 +0200 @@ -0,0 +1,47 @@ +Basic_Training_-_Bazooka.name=Initiation au Bazooka +Basic_Training_-_Bazooka.desc="Pour gagner, utiliser le vent à votre avantage !" + +Basic_Training_-_Grenade.name=Entrainement au lancer de Grenade +Basic_Training_-_Grenade.desc="Souvenez vous, retirez la goupille et lancez !" + +Basic_Training_-_Cluster_Bomb.name=Entrainement au lancer de grenade à fragmentation +Basic_Training_-_Cluster_Bomb.desc="Quelqu'un à besoin d'une bonne douche !" + +Basic_Training_-_Shotgun.name=Initiation au Fusil +Basic_Training_-_Shotgun.desc="On tire d'abord, on pose les questions après !" + +Basic_Training_-_Sniper_Rifle.name=Initiation au Sniper +Basic_Training_-_Sniper_Rifle.desc="Pan ! En pleine tête !" + +Basic_Training_-_Rope.name=Initiation à la Corde Ninja +Basic_Training_-_Rope.desc="Bouge de là et Balance toi !" + +User_Mission_-_Dangerous_Ducklings.name=Mission: Canards dangereux +User_Mission_-_Dangerous_Ducklings.desc="Très bien le bleu, il est temps de mettre en pratique ce que tu as appris aux entraînements !" + +User_Mission_-_Diver.name=Mission: Diver +User_Mission_-_Diver.desc="Cet assault 'sous-marin' est plus dur que cela n'y paraît...." + +User_Mission_-_Teamwork.name=Mission: Travail en équipe +User_Mission_-_Teamwork.desc="Parfois, l'amour blesse." + +User_Mission_-_Spooky_Tree.name=Mission: L'arbre qui parle +User_Mission_-_Spooky_Tree.desc="Beaucoup de caisses par ici. J'espère vraiment que cet oiseau n'a pas faim." + +User_Mission_-_Bamboo_Thicket.name=Mission: Forêt de Bamboo +User_Mission_-_Bamboo_Thicket.desc="La mort vient d'en haut." + +User_Mission_-_That_Sinking_Feeling.name=Mission: Cette impression de naufrage +User_Mission_-_That_Sinking_Feeling.desc="L'eau monte rapidement et le temps est compté. Beaucoup ont essayé, sans succès.Pouvez vous tous les sauvez ?" + +User_Mission_-_Newton_and_the_Hammock.name=Mission: Newton et le Hammac +User_Mission_-_Newton_and_the_Hammock.desc="Souvenez vous petits hérissons : La vitesse d'un corps reste constante à moins que ce corps ne soit attiré par une force extérieure!" + +User_Mission_-_The_Great_Escape.name=Mission: La grande évasion +User_Mission_-_The_Great_Escape.desc="Tu pense que tu peux me capturer ?!" + +User_Mission_-_Rope_Knock_Challenge.name=Challenge: A coup de Corde Ninja +User_Mission_-_Rope_Knock_Challenge.desc="Regarde derrière toi !" + +User_Mission_-_RCPlane_Challenge.name=Challenge: Avion télécommandé +User_Mission_-_RCPlane_Challenge.desc="Plutôt confiant, hein, aviateur ?" \ No newline at end of file diff -r 57a508884052 -r 0a494f951dcf share/hedgewars/Data/misc/hedgewars-mimeinfo.xml --- a/share/hedgewars/Data/misc/hedgewars-mimeinfo.xml Thu Jul 26 11:01:32 2012 +0200 +++ b/share/hedgewars/Data/misc/hedgewars-mimeinfo.xml Thu Jul 26 11:10:56 2012 +0200 @@ -11,12 +11,13 @@ Demo de Hedgewars Démonstration d'Hedgewars Demo di Hedgewars - 헤즈와스 데모 + 헤즈와스 데모 Demo gry Hedgewars - Hedgewars Demo + Hedgewars Demo Demo hry Hedgewars Ukázka hry Hedgewars Demo för Hedgewars + Hedgewars-demo @@ -30,13 +31,14 @@ Hedgewars gespeichertes Spiel Partida guardada de Hedgewars Parties enregistrées d'Hedgewars - 헤즈와스 저장된 게임 + 헤즈와스 저장된 게임 Partita salvata di Hedgewars Zapis gry Hedgewars - Partida guardada de Hedgewars + Partida guardada de Hedgewars Uložená hra Hedgewars Uložená hra Hedgewars Sparfil för Hedgewars + Gemt Hedgewars-spil diff -r 57a508884052 -r 0a494f951dcf share/hedgewars/Data/misc/hwengine.desktop.in --- a/share/hedgewars/Data/misc/hwengine.desktop.in Thu Jul 26 11:01:32 2012 +0200 +++ b/share/hedgewars/Data/misc/hwengine.desktop.in Thu Jul 26 11:10:56 2012 +0200 @@ -15,6 +15,7 @@ GenericName[sk]=Engine hry Hedgewars, pre prehrávanie uložených hier a demo súborov GenericName[cs]=Engine hry Hedgewars pro přehrávání uložených her a ukázkových souborů GenericName[sv]=Hedgewarsmotorn, för att öppna demo- och sparfiler +GenericName[da]=Kæmpende Pindsvin Icon=hedgewars.png Exec=${CMAKE_INSTALL_PREFIX}/bin/hwengine ${HEDGEWARS_DATADIR}/hedgewars/Data %f Path=/tmp diff -r 57a508884052 -r 0a494f951dcf tools/PascalBasics.hs --- a/tools/PascalBasics.hs Thu Jul 26 11:01:32 2012 +0200 +++ b/tools/PascalBasics.hs Thu Jul 26 11:10:56 2012 +0200 @@ -9,7 +9,7 @@ import Data.Char builtin = ["succ", "pred", "low", "high", "ord", "inc", "dec", "exit", "break", "continue", "length"] - + pascalLanguageDef = emptyDef { commentStart = "(*" @@ -27,8 +27,8 @@ , "downto", "div", "mod", "record", "set", "nil" , "cdecl", "external", "if", "then", "else" ] -- ++ builtin - , reservedOpNames= [] - , caseSensitive = False + , reservedOpNames= [] + , caseSensitive = False } preprocessorSwitch :: Stream s m Char => ParsecT s u m String @@ -36,11 +36,11 @@ try $ string "{$" s <- manyTill (noneOf "\n") $ char '}' return s - + caseInsensitiveString s = do mapM_ (\a -> satisfy (\b -> toUpper a == toUpper b)) s s return s - + pas = patch $ makeTokenParser pascalLanguageDef where patch tp = tp {stringLiteral = stringL} @@ -50,7 +50,7 @@ , (try $ string "(*") >> manyTill anyChar (try $ string "*)") , (try $ string "//") >> manyTill anyChar (try newline) ] - + comments = do spaces skipMany $ do @@ -66,5 +66,5 @@ s' <- (many $ noneOf "'") (char '\'') return $ '\'' : s' - comments + comments return $ concat (s:ss) diff -r 57a508884052 -r 0a494f951dcf tools/PascalParser.hs --- a/tools/PascalParser.hs Thu Jul 26 11:01:32 2012 +0200 +++ b/tools/PascalParser.hs Thu Jul 26 11:10:56 2012 +0200 @@ -14,12 +14,12 @@ import PascalBasics import PascalUnitSyntaxTree - + knownTypes = ["shortstring", "ansistring", "char", "byte"] pascalUnit = do comments - u <- choice [program, unit, systemUnit] + u <- choice [program, unit, systemUnit, redoUnit] comments return u @@ -27,7 +27,7 @@ i <- liftM (flip Identifier BTUnknown) (identifier pas) comments return i - + unit = do string "unit" >> comments name <- iD @@ -38,7 +38,7 @@ comments return $ Unit name int impl Nothing Nothing - + reference = buildExpressionParser table term "reference" where term = comments >> choice [ @@ -48,9 +48,9 @@ , liftM SimpleReference iD >>= postfixes ] "simple reference" - table = [ + table = [ ] - + postfixes r = many postfix >>= return . foldl (flip ($)) r postfix = choice [ parens pas (option [] parameters) >>= return . FunCall @@ -64,21 +64,23 @@ e <- parens pas expression comments return $ TypeCast (Identifier t BTUnknown) e - - -varsDecl1 = varsParser sepEndBy1 + +varsDecl1 = varsParser sepEndBy1 varsDecl = varsParser sepEndBy varsParser m endsWithSemi = do vs <- m (aVarDecl endsWithSemi) (semi pas) return vs aVarDecl endsWithSemi = do - unless endsWithSemi $ - optional $ choice [ - try $ string "var" - , try $ string "const" - , try $ string "out" - ] + isVar <- liftM (== Just "var") $ + if not endsWithSemi then + optionMaybe $ choice [ + try $ string "var" + , try $ string "const" + , try $ string "out" + ] + else + return Nothing comments ids <- do i <- (commaSep1 pas) $ (try iD "variable declaration") @@ -93,7 +95,7 @@ e <- initExpression comments return (Just e) - return $ VarDeclaration False (ids, t) init + return $ VarDeclaration isVar False (ids, t) init constsDecl = do @@ -114,8 +116,8 @@ comments e <- initExpression comments - return $ VarDeclaration (isNothing t) ([i], fromMaybe (DeriveType e) t) (Just e) - + return $ VarDeclaration False (isNothing t) ([i], fromMaybe (DeriveType e) t) (Just e) + typeDecl = choice [ char '^' >> typeDecl >>= return . PointerTo , try (string "shortstring") >> return (String 255) @@ -211,7 +213,6 @@ comments return $ TypeDeclaration i t - rangeDecl = choice [ try $ rangeft , iD >>= return . Range @@ -221,8 +222,8 @@ e1 <- initExpression string ".." e2 <- initExpression - return $ RangeFromTo e1 e2 - + return $ RangeFromTo e1 e2 + typeVarDeclaration isImpl = (liftM concat . many . choice) [ varSection, constSection, @@ -251,7 +252,7 @@ t <- typesDecl "type declaration" comments return t - + operatorDecl = do try $ string "operator" comments @@ -276,7 +277,7 @@ return Nothing return $ [OperatorDeclaration i rid ret vs b] - + funcDecl = do fp <- try (string "function") <|> try (string "procedure") comments @@ -300,7 +301,7 @@ else return Nothing return $ [FunctionDeclaration i ret vs b] - + functionDecorator = choice [ try $ string "inline;" , try $ caseInsensitiveString "cdecl;" @@ -309,8 +310,8 @@ , try $ string "varargs;" , try (string "external") >> comments >> iD >> optional (string "name" >> comments >> stringLiteral pas)>> string ";" ] >> comments - - + + program = do string "program" comments @@ -347,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 @@ -384,27 +395,27 @@ , 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 ] ] strOrChar [a] = CharCode . show . ord $ a - strOrChar a = StringLiteral a - + strOrChar a = StringLiteral a + phrasesBlock = do try $ string "begin" comments p <- manyTill phrase (try $ string "end" >> notFollowedBy alphaNum) comments return $ Phrases p - + phrase = do o <- choice [ phrasesBlock @@ -414,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 @@ -459,7 +470,7 @@ comments o <- phrase return $ foldr WithBlock o rs - + repeatCycle = do try $ string "repeat" >> space comments @@ -479,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 @@ -487,8 +503,8 @@ comments p <- phrase comments - return $ ForCycle i e1 e2 p - + return $ ForCycle i e1 e2 p up + switchCase = do try $ string "case" comments @@ -515,14 +531,14 @@ p <- phrase comments return (e, p) - + procCall = do r <- reference p <- option [] $ (parens pas) parameters return $ ProcCall r p parameters = (commaSep pas) expression "parameters" - + functionBody = do tv <- typeVarDeclaration True comments @@ -559,7 +575,7 @@ , itypeCast , iD >>= return . InitReference ] - + recField = do i <- iD spaces @@ -569,17 +585,23 @@ spaces return (i ,e) - table = [ + 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 @@ -588,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 @@ -603,7 +625,7 @@ i <- parens pas initExpression comments return $ InitTypeCast (Identifier t BTUnknown) i - + builtInFunction e = do name <- choice $ map (\s -> try $ caseInsensitiveString s >>= \i -> notFollowedBy alphaNum >> return i) builtin spaces @@ -620,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 57a508884052 -r 0a494f951dcf tools/PascalPreprocessor.hs --- a/tools/PascalPreprocessor.hs Thu Jul 26 11:01:32 2012 +0200 +++ b/tools/PascalPreprocessor.hs Thu Jul 26 11:10:56 2012 +0200 @@ -18,8 +18,10 @@ initDefines = Map.fromList [ ("FPC", "") , ("PAS2C", "") + , ("ENDIAN_LITTLE", "") + , ("S3D_DISABLED", "") ] - + preprocess :: String -> IO String preprocess fn = do r <- runParserT (preprocessFile fn) (initDefines, [True]) "" "" @@ -28,17 +30,17 @@ hPutStrLn stderr (show a) return "" (Right a) -> return a - + where preprocessFile fn = do f <- liftIO (readFile fn) setInput f preprocessor - + preprocessor, codeBlock, switch :: ParsecT String (Map.Map String String, [Bool]) IO String - + preprocessor = chainr codeBlock (return (++)) "" - + codeBlock = do s <- choice [ switch @@ -55,7 +57,7 @@ c <- letter <|> oneOf "_" s <- many (alphaNum <|> oneOf "_") return $ c:s - + switch = do try $ string "{$" s <- choice [ @@ -68,7 +70,7 @@ , unknown ] return s - + include = do try $ string "INCLUDE" spaces @@ -85,26 +87,26 @@ ifdef = do s <- try (string "IFDEF") <|> try (string "IFNDEF") let f = if s == "IFNDEF" then not else id - + spaces d <- identifier spaces char '}' - + updateState $ \(m, b) -> (m, (f $ d `Map.member` m) : b) - + return "" if' = do s <- try (string "IF" >> notFollowedBy alphaNum) - + manyTill anyChar (char '}') --char '}' - + updateState $ \(m, b) -> (m, False : b) - + return "" elseSwitch = do @@ -118,7 +120,7 @@ define = do try $ string "DEFINE" spaces - i <- identifier + i <- identifier d <- ((string ":=" >> return ())<|> spaces) >> many (noneOf "}") char '}' updateState $ \(m, b) -> (if (and b) && (head i /= '_') then Map.insert i d m else m, b) @@ -126,7 +128,7 @@ replace s = do (m, _) <- getState return $ Map.findWithDefault s s m - + unknown = do fn <- many1 $ noneOf "}\n" char '}' diff -r 57a508884052 -r 0a494f951dcf tools/PascalUnitSyntaxTree.hs --- a/tools/PascalUnitSyntaxTree.hs Thu Jul 26 11:01:32 2012 +0200 +++ b/tools/PascalUnitSyntaxTree.hs Thu Jul 26 11:10:56 2012 +0200 @@ -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 @@ -17,7 +18,7 @@ data TypesAndVars = TypesAndVars [TypeVarDeclaration] deriving Show data TypeVarDeclaration = TypeDeclaration Identifier TypeDecl - | VarDeclaration Bool ([Identifier], TypeDecl) (Maybe InitExpression) + | VarDeclaration Bool Bool ([Identifier], TypeDecl) (Maybe InitExpression) | FunctionDeclaration Identifier TypeDecl [TypeVarDeclaration] (Maybe (TypesAndVars, Phrase)) | OperatorDeclaration String Identifier TypeDecl [TypeVarDeclaration] (Maybe (TypesAndVars, Phrase)) deriving Show @@ -30,8 +31,9 @@ | String Integer | Set TypeDecl | FunctionType TypeDecl [TypeVarDeclaration] - | DeriveType InitExpression + | DeriveType InitExpression | VoidType + | VarParamType TypeDecl -- this is a hack deriving Show data Range = Range Identifier | RangeFromTo InitExpression InitExpression @@ -47,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]) @@ -106,11 +108,12 @@ | BTFloat | BTRecord String [(String, BaseType)] | BTArray Range BaseType BaseType - | BTFunction Int BaseType + | BTFunction Bool Int BaseType | BTPointerTo BaseType | BTUnresolved String | BTSet BaseType | BTEnum [String] | BTVoid | BTUnit + | BTVarParam BaseType deriving Show diff -r 57a508884052 -r 0a494f951dcf tools/pas2c.hs --- a/tools/pas2c.hs Thu Jul 26 11:01:32 2012 +0200 +++ b/tools/pas2c.hs Thu Jul 26 11:10:56 2012 +0200 @@ -21,7 +21,7 @@ import PascalUnitSyntaxTree -data InsertOption = +data InsertOption = IOInsert | IOLookup | IOLookupLast @@ -30,7 +30,7 @@ type Record = (String, BaseType) type Records = Map.Map String [Record] -data RenderState = RenderState +data RenderState = RenderState { currentScope :: Records, lastIdentifier :: String, @@ -42,7 +42,7 @@ currentFunctionResult :: String, namespaces :: Map.Map String Records } - + emptyState = RenderState Map.empty "" BTUnknown [] 0 Set.empty "" "" getUniq :: State RenderState Int @@ -50,7 +50,7 @@ i <- gets uniqCounter modify(\s -> s{uniqCounter = uniqCounter s + 1}) return i - + addStringConst :: String -> State RenderState Doc addStringConst str = do strs <- gets stringConsts @@ -65,21 +65,22 @@ let sn = "__str" ++ show i modify (\s -> s{lastType = BTString, stringConsts = (sn, str) : strs}) return $ text sn - + escapeStr :: String -> String escapeStr = foldr escapeChar [] 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 docToLower = text . map toLower . render @@ -97,8 +98,8 @@ processed <- gets $ Map.member fileName unless processed $ do print ("Preprocessing '" ++ fileName ++ ".pas'... ") - fc' <- liftIO - $ tryJust (guard . isDoesNotExistError) + fc' <- liftIO + $ tryJust (guard . isDoesNotExistError) $ preprocess (fileName ++ ".pas") case fc' of (Left a) -> do @@ -127,15 +128,21 @@ mapM_ (toCFiles nss) u where toNamespace :: Map.Map String Records -> PascalUnit -> Records - toNamespace nss (System tvs) = + toNamespace nss (System tvs) = currentScope $ execState f (emptyState nss) 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 ++ "_"} + toNamespace nss (Unit (Identifier i _) interface _ _ _) = + 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 @@ -247,27 +266,29 @@ ns <- gets currentScope tom <- gets (Set.member n . toMangle) cu <- gets currentUnit - let i' = case (t, tom) of - (BTFunction p _, True) -> cu ++ i ++ ('_' : show p) - (BTFunction _ _, _) -> cu ++ i - _ -> i - modify (\s -> s{currentScope = Map.insertWith (++) n [(i', t)] (currentScope s), lastIdentifier = n}) + let (i', t') = case (t, tom) of + (BTFunction _ p _, True) -> (cu ++ i ++ ('_' : show p), t) + (BTFunction _ _ _, _) -> (cu ++ i, t) + (BTVarParam t', _) -> ('(' : '*' : i ++ ")" , t') + _ -> (i, t) + modify (\s -> s{currentScope = Map.insertWith (++) n [(i', t')] (currentScope s), lastIdentifier = n}) 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 let i' = map toLower i v <- gets $ Map.lookup i' . currentScope lt <- gets lastType - if isNothing v then + if isNothing v then error $ "Not defined: '" ++ i' ++ "'\n" ++ show lt ++ "\nwith num of params = " ++ show params ++ "\n" ++ show v - else - let vv = fromMaybe (head $ fromJust v) . find checkParam $ fromJust v in + else + let vv = fromMaybe (head $ fromJust v) . find checkParam $ fromJust v in modify (\s -> s{lastType = snd vv, lastIdentifier = fst vv}) >> (return . text . fst $ vv) where - checkParam (_, BTFunction p _) = p == params + checkParam (_, BTFunction _ p _) = p == params checkParam _ = False id2C IODeferred (Identifier i t) = do let i' = map toLower i @@ -278,20 +299,20 @@ 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 - if isNothing v then + if isNothing v then error $ "Not defined: '" ++ i' ++ "'\n" ++ show lt - else + else let vv = f $ fromJust v in modify (\s -> s{lastType = snd vv, lastIdentifier = fst vv}) >> (return . text . fst $ vv) - - + + id2CTyped :: TypeDecl -> Identifier -> State RenderState Doc id2CTyped t (Identifier i _) = do tb <- resolveType t - case (t, tb) of + case (t, tb) of (_, BTUnknown) -> do error $ "id2CTyped: type BTUnknown for " ++ show i ++ "\ntype: " ++ show t (SimpleType {}, BTRecord _ r) -> do @@ -301,7 +322,7 @@ ts <- type2C t id2C IOInsert (Identifier i (BTRecord i r)) _ -> id2C IOInsert (Identifier i tb) - + resolveType :: TypeDecl -> State RenderState BaseType @@ -324,12 +345,12 @@ return . BTRecord "" . concat $ tvs where f :: TypeVarDeclaration -> State RenderState [(String, BaseType)] - f (VarDeclaration _ (ids, td) _) = mapM (\(Identifier i _) -> liftM ((,) i) $ resolveType td) ids + f (VarDeclaration _ _ (ids, td) _) = mapM (\(Identifier i _) -> liftM ((,) i) $ resolveType td) ids resolveType (ArrayDecl (Just i) t) = do t' <- resolveType t - return $ BTArray i BTInt t' + return $ BTArray i BTInt t' resolveType (ArrayDecl Nothing t) = liftM (BTArray RangeInfinite BTInt) $ resolveType t -resolveType (FunctionType t a) = liftM (BTFunction (length a)) $ resolveType t +resolveType (FunctionType t a) = liftM (BTFunction False (length a)) $ resolveType t resolveType (DeriveType (InitHexNumber _)) = return BTInt resolveType (DeriveType (InitNumber _)) = return BTInt resolveType (DeriveType (InitFloat _)) = return BTFloat @@ -344,7 +365,8 @@ resolveType (Sequence ids) = return $ BTEnum $ map (\(Identifier i _) -> map toLower i) ids resolveType (RangeType _) = return $ BTVoid resolveType (Set t) = liftM BTSet $ resolveType t - +resolveType (VarParamType t) = liftM BTVarParam $ resolveType t + resolve :: String -> BaseType -> State RenderState BaseType resolve s (BTUnresolved t) = do @@ -360,46 +382,78 @@ fromPointer s t = do 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 where - cnt (VarDeclaration _ (ids, _) _) = length ids + cnt (VarDeclaration _ _ (ids, _) _) = length ids cnt _ = 1 +hasPassByReference :: [TypeVarDeclaration] -> Bool +hasPassByReference = or . map isVar + where + isVar (VarDeclaration v _ (_, _) _) = v + isVar _ = error $ "hasPassByReference called not on function parameters" + +toIsVarList :: [TypeVarDeclaration] -> [Bool] +toIsVarList = concatMap isVar + where + isVar (VarDeclaration v _ (p, _) _) = replicate (length p) v + isVar _ = error $ "toIsVarList called not on function parameters" + + +funWithVarsToDefine :: String -> [TypeVarDeclaration] -> Doc +funWithVarsToDefine n params = text "#define" <+> text n <> parens abc <+> text (n ++ "__vars") <> parens cparams + where + abc = hcat . punctuate comma . map (char . fst) $ ps + cparams = hcat . punctuate comma . map (\(c, v) -> if v then char '&' <> parens (char c) else char c) $ ps + ps = zip ['a'..] (toIsVarList params) + fun2C :: Bool -> String -> TypeVarDeclaration -> State RenderState [Doc] fun2C _ _ (FunctionDeclaration name returnType params Nothing) = do - t <- type2C returnType + t <- type2C returnType t'<- gets lastType p <- withState' id $ functionParams2C params - n <- id2C IOInsert $ setBaseType (BTFunction (numberOfDeclarations params) t') name - return [t empty <+> n <> parens p] - -fun2C True rv (FunctionDeclaration name returnType params (Just (tvars, phrase))) = do + n <- liftM render . id2C IOInsert $ setBaseType (BTFunction hasVars (numberOfDeclarations params) t') name + if hasVars then + return [funWithVarsToDefine n params $+$ t empty <+> text (n ++ "__vars") <> parens p] + else + return [t empty <+> text n <> parens p] + where + hasVars = hasPassByReference params + + +fun2C True rv (FunctionDeclaration name@(Identifier i _) returnType params (Just (tvars, phrase))) = do let res = docToLower $ text rv <> text "_result" t <- type2C returnType t'<- gets lastType - n <- id2C IOInsert $ setBaseType (BTFunction (numberOfDeclarations params) t') name - + + notDeclared <- liftM isNothing . gets $ Map.lookup (map toLower i) . currentScope + + n <- liftM render . id2C IOInsert $ setBaseType (BTFunction hasVars (numberOfDeclarations params) t') name + let isVoid = case returnType of VoidType -> True _ -> False - + (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 [ - t empty <+> n <> parens p + let define = if hasVars then text "#ifndef" <+> text n $+$ funWithVarsToDefine n params $+$ text "#endif" else empty + return [ + define $+$ - text "{" - $+$ + --(if notDeclared && hasVars then funWithVarsToDefine n params else empty) $+$ + t empty <+> text (if hasVars then n ++ "__vars" else n) <> parens p + $+$ + text "{" + $+$ nest 4 phrasesBlock $+$ text "}"] @@ -407,69 +461,112 @@ phrase2C' (Phrases p) = liftM vcat $ mapM phrase2C p phrase2C' p = phrase2C p un [a] b = a : b - + hasVars = hasPassByReference params + 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] - -tvar2C _ (VarDeclaration isConst (ids, t) mInitExpr) = do - t' <- liftM (((if isConst then text "const" else empty) <+>) . ) $ type2C t + return $ if includeType then [text "typedef" <+> tp i] else [] + +tvar2C _ _ _ _ (VarDeclaration True _ (ids, t) Nothing) = do + t' <- liftM ((empty <+>) . ) $ type2C t + liftM (map(\i -> t' i)) $ mapM (id2CTyped (VarParamType t)) ids + +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"] - (_, BTFunction{}, _, Nothing) -> liftM (map(\i -> t' $ text "*" <+> i)) $ mapM (id2CTyped t) ids - _ -> liftM (map(\i -> t' i <+> ie)) $ mapM (id2CTyped t) ids + return $ if includeType then [text "#define" <+> i' <+> parens ie <> text "\n"] else [] + (_, BTFunction{}, _, Nothing) -> liftM (map(\i -> t' i)) $ 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) - -tvar2C f (OperatorDeclaration op (Identifier i _) ret params body) = do + 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 r <- op2CTyped op (extractTypes params) fun2C f i (FunctionDeclaration r ret params body) - + op2CTyped :: String -> [TypeDecl] -> State RenderState Identifier op2CTyped op t = do t' <- liftM (render . hcat . punctuate (char '_') . map (\t -> t empty)) $ mapM type2C t bt <- gets lastType return $ Identifier (t' ++ "_op_" ++ opStr) bt - where + where opStr = case op of "+" -> "add" "-" -> "sub" "*" -> "mul" "/" -> "div" + "/(float)" -> "div" "=" -> "eq" "<" -> "lt" ">" -> "gt" "<>" -> "neq" _ -> error $ "op2CTyped: unknown op '" ++ op ++ "'" - + extractTypes :: [TypeVarDeclaration] -> [TypeDecl] extractTypes = concatMap f where - f (VarDeclaration _ (ids, t) _) = replicate (length ids) t + f (VarDeclaration _ _ (ids, t) _) = replicate (length ids) t f a = error $ "extractTypes: can't extract from " ++ show a initExpr2C, initExpr2C' :: InitExpression -> State RenderState Doc initExpr2C (InitArray values) = liftM (braces . vcat . punctuate comma) $ mapM initExpr2C values initExpr2C a = initExpr2C' a initExpr2C' InitNull = return $ text "NULL" -initExpr2C' (InitAddress expr) = liftM ((<>) (text "&")) (initExpr2C' expr) +initExpr2C' (InitAddress expr) = do + ie <- initExpr2C' expr + lt <- gets lastType + case lt of + BTFunction True _ _ -> return $ text "&" <> ie <> text "__vars" + _ -> return $ text "&" <> ie initExpr2C' (InitPrefixOp op expr) = liftM (text (op2C op) <>) (initExpr2C' expr) initExpr2C' (InitBinOp op expr1 expr2) = do e1 <- initExpr2C' expr1 @@ -500,7 +597,7 @@ initExpr2C' (InitRange a) = error $ show a --return $ text "<>" initExpr2C' (InitSet []) = return $ text "0" initExpr2C' (InitSet a) = return $ text "<>" -initExpr2C' (BuiltInFunction "low" [InitReference e]) = return $ +initExpr2C' (BuiltInFunction "low" [InitReference e]) = return $ case e of (Identifier "LongInt" _) -> int (-2^31) (Identifier "SmallInt" _) -> int (-2^15) @@ -515,7 +612,7 @@ initExpr2C' (BuiltInFunction "pred" [BuiltInFunction "succ" [e]]) = initExpr2C' e initExpr2C' (BuiltInFunction "succ" [e]) = liftM (<> text " + 1") $ initExpr2C' e initExpr2C' (BuiltInFunction "pred" [e]) = liftM (<> text " - 1") $ initExpr2C' e -initExpr2C' b@(BuiltInFunction _ _) = error $ show b +initExpr2C' b@(BuiltInFunction _ _) = error $ show b initExpr2C' a = error $ "initExpr2C: don't know how to render " ++ show a @@ -550,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 @@ -561,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 @@ -574,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' @@ -582,7 +679,7 @@ type2C' (FunctionType returnType params) = do t <- type2C returnType p <- withState' id $ functionParams2C params - return (\i -> t empty <+> i <> parens p) + return (\i -> (t empty <> (parens $ text "*" <> i) <> parens p)) type2C' (DeriveType (InitBinOp _ _ i)) = type2C' (DeriveType i) type2C' (DeriveType (InitPrefixOp _ i)) = type2C' (DeriveType i) type2C' (DeriveType (InitNumber _)) = return (text "int" <+>) @@ -610,7 +707,7 @@ e <- expr2C expr p1 <- (phrase2C . wrapPhrase) phrase1 el <- elsePart - return $ + return $ text "if" <> parens e $+$ p1 $+$ el where elsePart | isNothing mphrase2 = return $ empty @@ -634,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 @@ -654,34 +762,36 @@ e <- expr2C expr cs <- mapM case2C cases d <- dflt - return $ + return $ text "switch" <> parens e $+$ braces (nest 4 . vcat $ cs ++ d) where case2C :: ([InitExpression], Phrase) -> State RenderState Doc case2C (e, p) = do ies <- mapM range2C e ph <- phrase2C p - return $ + 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)] - + phrase2C wb@(WithBlock ref p) = do - r <- ref2C ref + r <- ref2C ref t <- gets lastType case t of (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) - return $ - text "for" <> (parens . hsep . punctuate (char ';') $ [i <+> text "=" <+> e1, i <+> text "<=" <+> e2, text "++" <> i]) + cmp <- return $ if up == True then "<=" else ">=" + inc <- return $ if up == True then "++" else "--" + return $ + text "for" <> (parens . hsep . punctuate (char ';') $ [i <+> text "=" <+> parens e1, i <+> text cmp <+> parens e2, text inc <> i]) $$ ph phrase2C (RepeatCycle e' p') = do @@ -716,13 +826,13 @@ e2 <- expr2C expr2 t2 <- gets lastType case (op2C op, t1, t2) of - ("+", BTString, BTString) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strconcat" (BTFunction 2 BTString)) - ("+", BTString, BTChar) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strappend" (BTFunction 2 BTString)) - ("+", BTChar, BTString) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strprepend" (BTFunction 2 BTString)) - ("+", BTChar, BTChar) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_chrconcat" (BTFunction 2 BTString)) - ("==", BTString, BTChar) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strcomparec" (BTFunction 2 BTBool)) - ("==", BTString, BTString) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strcompare" (BTFunction 2 BTBool)) - ("!=", BTString, _) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strncompare" (BTFunction 2 BTBool)) + ("+", BTString, BTString) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strconcat" (BTFunction False 2 BTString)) + ("+", BTString, BTChar) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strappend" (BTFunction False 2 BTString)) + ("+", BTChar, BTString) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strprepend" (BTFunction False 2 BTString)) + ("+", BTChar, BTChar) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_chrconcat" (BTFunction False 2 BTString)) + ("==", BTString, BTChar) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strcomparec" (BTFunction False 2 BTBool)) + ("==", BTString, BTString) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strcompare" (BTFunction False 2 BTBool)) + ("!=", BTString, _) -> expr2C $ BuiltInFunCall [expr1, expr2] (SimpleReference $ Identifier "_strncompare" (BTFunction False 2 BTBool)) ("&", BTBool, _) -> return $ parens e1 <+> text "&&" <+> parens e2 ("|", BTBool, _) -> return $ parens e1 <+> text "||" <+> parens e2 (_, BTRecord t1 _, BTRecord t2 _) -> do @@ -732,16 +842,27 @@ -- aw, "LongInt" here is hwengine-specific hack i <- op2CTyped op [SimpleType (Identifier t1 undefined), SimpleType (Identifier "LongInt" undefined)] ref2C $ FunCall [expr1, expr2] (SimpleReference i) - ("in", _, _) -> + ("in", _, _) -> 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 @@ -765,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}) @@ -794,24 +920,25 @@ _ -> 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' - BTArray {} -> return $ text "length_ar" <> 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 expr2C (BuiltInFunCall params ref) = do - r <- ref2C ref + r <- ref2C ref t <- gets lastType ps <- mapM expr2C params case t of - BTFunction _ t' -> do + BTFunction _ _ t' -> do modify (\s -> s{lastType = t'}) _ -> error $ "BuiltInFunCall lastType: " ++ show t - return $ + return $ r <> parens (hsep . punctuate (char ',') $ ps) expr2C a = error $ "Don't know how to render " ++ show a @@ -820,15 +947,15 @@ i <- id2C IOLookup name t <- gets lastType case t of - BTFunction _ rt -> do + 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 t <- gets lastType case t of - BTFunction _ rt -> do + BTFunction _ _ rt -> do modify(\s -> s{lastType = rt}) return $ i <> parens empty _ -> return $ i @@ -844,7 +971,7 @@ -- conversion routines ref2C ae@(ArrayElement [expr] ref) = do e <- expr2C expr - r <- ref2C ref + r <- ref2C ref t <- gets lastType case t of (BTArray _ _ t') -> modify (\st -> st{lastType = t'}) @@ -862,13 +989,13 @@ _ -> return $ r <> brackets e ref2C (SimpleReference name) = id2C IOLookup name ref2C rf@(RecordField (Dereference ref1) ref2) = do - r1 <- ref2C ref1 + r1 <- ref2C ref1 t <- fromPointer (show ref1) =<< gets lastType r2 <- case t of BTRecord _ rs -> withRecordNamespace "" rs $ ref2C ref2 BTUnit -> error "What??" a -> error $ "dereferencing from " ++ show a ++ "\n" ++ show rf - return $ + return $ r1 <> text "->" <> r2 ref2C rf@(RecordField ref1 ref2) = do r1 <- ref2C ref1 @@ -888,7 +1015,7 @@ r <- fref2C ref t <- gets lastType case t of - BTFunction _ t' -> do + BTFunction _ _ t' -> do ps <- liftM (parens . hsep . punctuate (char ',')) $ mapM expr2C params modify (\s -> s{lastType = t'}) return $ r <> ps @@ -898,10 +1025,13 @@ where fref2C (SimpleReference name) = id2C (IOLookupFunction $ length params) name fref2C a = ref2C a - + ref2C (Address ref) = do r <- ref2C ref - return $ text "&" <> parens r + lt <- gets lastType + case lt of + BTFunction True _ _ -> return $ text "&" <> parens (r <> text "__vars") + _ -> return $ text "&" <> parens r ref2C (TypeCast t'@(Identifier i _) expr) = do lt <- expr2C expr >> gets lastType case (map toLower i, lt) of @@ -909,7 +1039,7 @@ ("shortstring", BTPointerTo _) -> ref2C $ FunCall [expr] (SimpleReference (Identifier "pchar2str" $ BTString)) (a, _) -> do e <- expr2C expr - t <- id2C IOLookup t' + t <- id2C IOLookup t' return . parens $ parens t <> e ref2C (RefExpression expr) = expr2C expr @@ -917,7 +1047,7 @@ op2C :: String -> String op2C "or" = "|" op2C "and" = "&" -op2C "not" = "!" +op2C "not" = "~" op2C "xor" = "^" op2C "div" = "/" op2C "mod" = "%" @@ -925,5 +1055,6 @@ op2C "shr" = ">>" op2C "<>" = "!=" op2C "=" = "==" +op2C "/" = "/(float)" op2C a = a