-- | An effect is a processed version of an action, ready
-- to change tiles in the world but it only contains raw
-- information. Example:
--
-- A monster 'M' wants to attack a guy '@' with its hands,
-- then the game generates an 'Hit' action:
-- "Action 'M' '@' (Hit 'Bare_Hands')" or something like that.
-- Then an effect is returned, and it could be (ChangeInHp (-4)),
-- beacuse an normal punch attack has -2 change in hp, but in this
-- case, the monster M has an power to increase the attack when using
-- its hands.
-- In the final part, the program look at the effect and the target,
-- and generates the final state of the target tile (In this case
-- would be the loss in HP, counting with any defense tool that the
-- target could be using).

module Effect where

import Data.List

import qualified World as W
import qualified Tile as T
import qualified Tile.TileType as TT
import qualified Attribute as A

-- | Represent an effect to a target CTile.
data Effect = Effect W.CTile EffectType
            deriving (Eq, Show)

-- | All the possible effects generated by actions:
data EffectType = ChangeInPositionAbove W.TileCoord   -- ^ Change in position to get above something.
                | ChangeInPositionInside W.TileCoord  -- ^ Change in position to get inside something.
                | OccupySameSpace W.TileCoord         -- ^ Change in position to occupy the same space.
                | ChangeInHP Int                      -- ^ Change the HP by an Int.
                | Break                               -- ^ Break something.
                | Sprawl W.CTile                      -- ^ Hit something with force.
                | Sprawled W.CTile                    -- ^ Get sprawled by something.
                | NoEffect                            -- ^ No effect, Nothing.
                deriving (Eq, Show)

-- | Returns the sprawl damage to the two
-- tiles, who sprawled and who got sprawled.
sprawlDamage :: T.Tile -> T.Tile -> (Int, Int)
sprawlDamage _ _ = (-5, -5)

-- | Retuns the type of an effect.
effectType :: Effect -> EffectType
effectType (Effect _ e) = e

-- Handles an effect by changing the world state.
-- WARNING : This function will be big, very big.
onEffect :: W.WorldState -> Effect -> W.WorldState
onEffect ws@(W.World s str tiles) (Effect t@(_, tile) (ChangeInPositionAbove c2)) =
    W.World s str $ (c2, T.Above tile (snd $ W.loadTile c2 ws)) :
                    (W.deleteTile (W.loadTile c2 ws) $ W.deleteTile t tiles)
onEffect ws@(W.World s str tiles) (Effect t@(_, tile) (ChangeInPositionInside c2)) =
    W.World s str $ (c2, T.Inside tile (snd $ W.loadTile c2 ws)) :
                    (W.deleteTile (W.loadTile c2 ws) $ W.deleteTile t tiles)
onEffect ws@(W.World s str tiles) (Effect t@(_, tile) (OccupySameSpace c2))=
    W.World s str $ (c2, T.Tiles tile (snd $ W.loadTile c2 ws)) :
                    (W.deleteTile (W.loadTile c2 ws) $ W.deleteTile t tiles)
onEffect (W.World s str tiles) (Effect t@(c, (T.Tile tt@(TT.TEntity _) a)) (ChangeInHP hp)) =
    W.World s str $ (c, T.Tile tt ((A.addHp (A.findSomeData a) hp) : (delete (A.findSomeData a) a))) :
                    (W.deleteTile t tiles)
onEffect (W.World s str tiles) (Effect t@(c, (T.Tiles (T.Tile tt@(TT.TEntity _) a) t2)) (ChangeInHP hp)) =
    W.World s str $ (c, T.Tiles (T.Tile tt ((A.addHp (A.findSomeData a) hp) : (delete (A.findSomeData a) a))) t2) :
                    (W.deleteTile t tiles)
onEffect (W.World s str tiles) (Effect t@(c, (T.Above (T.Tile tt@(TT.TEntity _) a) t2)) (ChangeInHP hp)) =
    W.World s str $ (c, T.Above (T.Tile tt ((A.addHp (A.findSomeData a) hp) : (delete (A.findSomeData a) a))) t2) :
                    (W.deleteTile t tiles)
onEffect (W.World s str tiles) (Effect t@(c, (T.Inside (T.Tile tt@(TT.TEntity _) a) t2)) (ChangeInHP hp)) =
    W.World s str $ (c, T.Inside (T.Tile tt ((A.addHp (A.findSomeData a) hp) : (delete (A.findSomeData a) a))) t2) :
                    (W.deleteTile t tiles)
onEffect ws (Effect _ (ChangeInHP _)) = ws
onEffect (W.World s str tiles) (Effect t@(c, tile) Break) =
    W.World s str $ (c, T.mapAttribute (A.addAttribute A.Broke ) tile) :
                    (W.deleteTile t tiles)
onEffect (W.World s str tiles) (Effect t@(c, tile) (Sprawl (_, tile2))) =
    W.World s str $ (c, T.mapAttribute (\x -> A.addHp (A.findSomeData x) (fst $ sprawlDamage tile tile2) : (delete (A.findSomeData x) x)) tile) :
                    (W.deleteTile t tiles)
onEffect (W.World s str tiles) (Effect t@(c, tile) (Sprawled (_, tile2))) =
    W.World s str $ (c, T.mapAttribute (\x -> A.addHp (A.findSomeData x) (fst $ sprawlDamage tile2 tile) : (delete (A.findSomeData x) x)) tile) :
                    (W.deleteTile t tiles)
onEffect ws _ = ws

--onEffect (W.World _ _ tiles) (Effect (x,y) ()) = undefined
