222 lines
7.5 KiB
Standard ML
222 lines
7.5 KiB
Standard ML
structure PlayerAttack =
|
|
struct
|
|
(* - Handle collisions where player hits enemy directly - *)
|
|
structure PlayerAttackEnemy =
|
|
MakeQuadTreeFold
|
|
(struct
|
|
type env = Time.time
|
|
type state = FallingEnemyMap.t * EnemyMap.t
|
|
|
|
open EnemyType
|
|
|
|
fun defeatEnemy (enemyID, enemyMap, fallingMap, time) =
|
|
case EnemyMap.get (enemyID, enemyMap) of
|
|
SOME (enemy: EnemyType.enemy) =>
|
|
let
|
|
val {x, y, variant, ...} = enemy
|
|
val fallenEnemy =
|
|
{x = x, y = y, variant = variant, time = time}
|
|
val fallingMap =
|
|
FallingEnemyMap.add (enemyID, fallenEnemy, fallingMap)
|
|
val enemyMap = EnemyMap.remove (enemyID, enemyMap)
|
|
in
|
|
(fallingMap, enemyMap)
|
|
end
|
|
| NONE => (fallingMap, enemyMap)
|
|
|
|
fun shieldSlimeAttacked (enemyID, enemy, enemyMap, fallingMap, time) =
|
|
if #shieldOn enemy then (fallingMap, enemyMap)
|
|
else defeatEnemy (enemyID, enemyMap, fallingMap, time)
|
|
|
|
fun onPlayerAttack (enemyID, enemy, enemyMap, fallingMap, time) =
|
|
case #variant enemy of
|
|
PATROL_SLIME => defeatEnemy (enemyID, enemyMap, fallingMap, time)
|
|
| FOLLOW_SLIME => defeatEnemy (enemyID, enemyMap, fallingMap, time)
|
|
| STRAIGHT_BAT => defeatEnemy (enemyID, enemyMap, fallingMap, time)
|
|
| SHIELD_SLIME =>
|
|
shieldSlimeAttacked (enemyID, enemy, enemyMap, fallingMap, time)
|
|
|
|
fun fold (enemyID, time, (fallingMap, enemyMap)) =
|
|
case EnemyMap.get (enemyID, enemyMap) of
|
|
SOME enemy =>
|
|
onPlayerAttack (enemyID, enemy, enemyMap, fallingMap, time)
|
|
| NONE => (fallingMap, enemyMap)
|
|
end)
|
|
|
|
structure PlayerAttackFalling =
|
|
MakeQuadTreeFold
|
|
(struct
|
|
type env = Time.time
|
|
type state = PlayerType.defeated_enemies list * FallingEnemyMap.t
|
|
|
|
open Time
|
|
|
|
fun fold (fallingID, mainAttackTime, (defeatedList, fallingMap)) =
|
|
case FallingEnemyMap.get (fallingID, fallingMap) of
|
|
SOME {time = fallingStartTime, ...} =>
|
|
if mainAttackTime > fallingStartTime then
|
|
let
|
|
val defeatedList = {angle = 1} :: defeatedList
|
|
val fallingMap =
|
|
FallingEnemyMap.remove (fallingID, fallingMap)
|
|
in
|
|
(defeatedList, fallingMap)
|
|
end
|
|
else
|
|
(defeatedList, fallingMap)
|
|
| NONE => (defeatedList, fallingMap)
|
|
end)
|
|
|
|
fun helpAttackEnemies
|
|
( projectileX
|
|
, projectileY
|
|
, enemyMap
|
|
, enemyTree
|
|
, fallingMap
|
|
, player
|
|
, mainAttackTime
|
|
) =
|
|
let
|
|
val width = Constants.projectileWidth
|
|
val height = Constants.projectileHeight
|
|
|
|
val fallingTree = FallingEnemies.generateTree fallingMap
|
|
val (defeatedList, fallingMap) = PlayerAttackFalling.foldRegion
|
|
( projectileX
|
|
, projectileY
|
|
, width
|
|
, height
|
|
, mainAttackTime
|
|
, ([], fallingMap)
|
|
, fallingTree
|
|
)
|
|
|
|
val (fallingMap, enemyMap) = PlayerAttackEnemy.foldRegion
|
|
( projectileX
|
|
, projectileY
|
|
, width
|
|
, height
|
|
, mainAttackTime
|
|
, (fallingMap, enemyMap)
|
|
, enemyTree
|
|
)
|
|
|
|
val defeatedList = Vector.fromList defeatedList
|
|
val defeatedList = Vector.concat [defeatedList, #enemies player]
|
|
val player =
|
|
PlayerPatch.withPatch (player, PlayerPatch.W_ENEMIES defeatedList)
|
|
in
|
|
(player, enemyMap, fallingMap)
|
|
end
|
|
|
|
fun attackEnemies (player: PlayerType.player, enemyMap, enemyTree, fallingMap) =
|
|
let
|
|
open PlayerType
|
|
open EntityType
|
|
val {x, y, facing, mainAttack, ...} = player
|
|
in
|
|
case mainAttack of
|
|
MAIN_ATTACKING {timePressed, ...} =>
|
|
(case facing of
|
|
FACING_RIGHT =>
|
|
let
|
|
val projectileX = x + Constants.playerWidth
|
|
val projectileY = y + Constants.projectileOffsetY
|
|
in
|
|
helpAttackEnemies
|
|
( projectileX
|
|
, projectileY
|
|
, enemyMap
|
|
, enemyTree
|
|
, fallingMap
|
|
, player
|
|
, timePressed
|
|
)
|
|
end
|
|
| FACING_LEFT =>
|
|
let
|
|
val projectileX = x - Constants.projectileWidth
|
|
val projectileY = y + Constants.projectileOffsetY
|
|
in
|
|
helpAttackEnemies
|
|
( projectileX
|
|
, projectileY
|
|
, enemyMap
|
|
, enemyTree
|
|
, fallingMap
|
|
, player
|
|
, timePressed
|
|
)
|
|
end)
|
|
| _ => (player, enemyMap, fallingMap)
|
|
end
|
|
|
|
(* - Handle collisions when player's projectile hits enemy - *)
|
|
structure ProjectileHitEnemy =
|
|
MakeQuadTreeFold
|
|
(struct
|
|
type env = Time.time
|
|
type state = FallingEnemyMap.t * EnemyMap.t
|
|
|
|
open EnemyType
|
|
|
|
fun onDefeated (enemyID, enemy, enemyMap, fallingMap, currentTime) =
|
|
let
|
|
val {x, y, variant, ...} = enemy
|
|
val fallingItem =
|
|
{x = x, y = y, variant = variant, time = currentTime}
|
|
val fallingMap =
|
|
FallingEnemyMap.add (enemyID, fallingItem, fallingMap)
|
|
val enemyMap = EnemyMap.remove (enemyID, enemyMap)
|
|
in
|
|
(fallingMap, enemyMap)
|
|
end
|
|
|
|
fun onShieldSlimeAttacked
|
|
(enemyID, enemy, enemyMap, fallingMap, currentTime) =
|
|
if #shieldOn enemy then (fallingMap, enemyMap)
|
|
else onDefeated (enemyID, enemy, enemyMap, fallingMap, currentTime)
|
|
|
|
fun onProjectileAttack
|
|
(enemyID, enemy, enemyMap, fallingMap, currentTime) =
|
|
case #variant enemy of
|
|
PATROL_SLIME =>
|
|
onDefeated (enemyID, enemy, enemyMap, fallingMap, currentTime)
|
|
| FOLLOW_SLIME =>
|
|
onDefeated (enemyID, enemy, enemyMap, fallingMap, currentTime)
|
|
| STRAIGHT_BAT =>
|
|
onDefeated (enemyID, enemy, enemyMap, fallingMap, currentTime)
|
|
| SHIELD_SLIME =>
|
|
onShieldSlimeAttacked
|
|
(enemyID, enemy, enemyMap, fallingMap, currentTime)
|
|
|
|
fun fold (enemyID, currentTime, (fallingMap, enemyMap)) =
|
|
case EnemyMap.get (enemyID, enemyMap) of
|
|
SOME enemy =>
|
|
onProjectileAttack
|
|
(enemyID, enemy, enemyMap, fallingMap, currentTime)
|
|
| NONE => (fallingMap, enemyMap)
|
|
end)
|
|
|
|
fun helpProjectileHitEnemy
|
|
(pos, projectiles, enemyTree, enemyMap, fallingMap, currentTime) =
|
|
if pos = Vector.length projectiles then
|
|
(fallingMap, enemyMap)
|
|
else
|
|
let
|
|
val {x, y, ...}: PlayerType.player_projectile =
|
|
Vector.sub (projectiles, pos)
|
|
val size = Constants.projectileSizeInt
|
|
val (fallingMap, enemyMap) = ProjectileHitEnemy.foldRegion
|
|
(x, y, size, size, currentTime, (fallingMap, enemyMap), enemyTree)
|
|
in
|
|
helpProjectileHitEnemy
|
|
(pos + 1, projectiles, enemyTree, enemyMap, fallingMap, currentTime)
|
|
end
|
|
|
|
fun projectileHitEnemy
|
|
(projectiles, enemyMap, enemyTree, fallingMap, currentTime) =
|
|
helpProjectileHitEnemy
|
|
(0, projectiles, enemyTree, enemyMap, fallingMap, currentTime)
|
|
end
|