From d9635547257b17020da110d1976573df38e22b2c Mon Sep 17 00:00:00 2001 From: Tim McGilchrist Date: Thu, 17 Mar 2022 15:17:59 +1100 Subject: [PATCH] Run ocamlformat --- src/ai.ml | 988 +++++----- src/ai.mli | 19 +- src/charactermaker.ml | 1235 ++++++------ src/charactermaker.mli | 32 +- src/characters.ml | 524 +++--- src/characters.mli | 117 +- src/command.ml | 24 +- src/gui.ml | 4025 +++++++++++++++++++++------------------- src/gui.mli | 6 +- src/interactions.ml | 189 +- src/interactions.mli | 54 +- src/main.ml | 220 ++- src/room.ml | 1463 +++++++++------ src/state.mli | 25 +- test/test_state.ml | 175 +- 15 files changed, 4830 insertions(+), 4266 deletions(-) diff --git a/src/ai.ml b/src/ai.ml index 0dd7cb3..70400df 100644 --- a/src/ai.ml +++ b/src/ai.ml @@ -1,482 +1,506 @@ -open Types -open Interactions - -(*[path_tile] store the intermediary values of our Djikstra's shortest -*path algorithm*) -type path_tile = - { - length: int; - prev: (int*int) option; - } - -(*[path_map] is a data type to mirror our ingame map but store the paths to -*traverse to an allied unit from an enemy*) -type path_map = - { - width: int; - length: int; - grid: path_tile array array; - } - -(*[check_exist] ensures if a specific item exists in a list*) - let rec check_exist co lst = - match lst with - |[] -> false - |h::t -> if fst h = co then true else check_exist co t - -(*[a_range_add] adds on to my attack range area*) - let a_range_add ma i co fl ml sl = - let addon = if i > ma then [] else( - let nleft = ((fst co) - 1, snd co) in - let cleft = if (fst co) - 1 < 0 || - List.mem nleft ml || - List.mem nleft sl || - check_exist nleft fl then [] else (nleft, i)::[] in - let nright = ((fst co) + 1, snd co) in - let cright = if (fst co) + 1 > 14 || - List.mem nright ml || - List.mem nright sl || - check_exist nright fl then cleft else (nright, i)::cleft in - let nup = (fst co, snd co - 1) in - let cup = if (snd co) - 1 < 0 || - List.mem nup ml || - List.mem nup sl || - check_exist nup fl then cright else (nup, i)::cright in - let ndown = (fst co, snd co + 1) in - let cdown = if (snd co) + 1 > 14 || - List.mem ndown ml || - List.mem ndown sl || - check_exist ndown fl then cup else (ndown, i)::cup in - cdown) in - fl @ addon - -(*[attack_range_helper] helps construct an attack range based on a weapon's range*) - let rec attack_range_helper mi ma i co fl ml sl = - let nml = (if i < mi then co::ml else ml) in - let nsl = (if i >= mi then co::sl else sl) in - let nfl = a_range_add ma (i + 1) co fl ml sl in - match nfl with - |[] -> nsl - |(h, x)::t -> attack_range_helper mi ma x h t nml nsl - -(*[attack_range] returns a list of coordinates within a character's attack range*) -let attack_range c = - let w = extract c.inv.(c.eqp) in - attack_range_helper (fst w.range) (snd w.range) 0 c.location [] [] [] - -(*[add_f2] is a list of frontier tiles sorted in increasing distance from a -* a settled node, as this is a grid map we know every frontier node is -* adjacent to a settled node therefore it's distance is its movement cost*) -let rec add_f2 (tile:tile) (i:int) (f :( tile * int) list) : (tile * int) list= - match f with - |[] -> [(tile,i)] - |h::t -> - if fst h = tile then (if i < snd h then (tile, i) :: t - else h :: t) else h :: (add_f2 tile i t) - -(*[check_valid] is whether or not given a location you can move in a certain - * direction *) -let check_valid d (m : map) loc = - match d with - |North -> snd loc - 1 > 0 - |East -> fst loc + 1 < m.width - |South -> snd loc + 1 < m.length - |West -> fst loc - 1 > 0 - -(*[check_adjacent] is whether or not given two tiles are adjacent on a map*) -let check_adjacent (t : tile) (f : tile) (m : map) = - match t.coordinate, f.coordinate with - |(x,y), (a,b) -> - ((abs (b - y)) = 1 && a = x) || - ((abs (a - x)) = 1 && b = y) - -(*[check_settled] is whether or not a given tile is already in the settled set*) -let rec check_settled (s : tile list) (tl : tile) = - match s with - |[] -> false - |h::t -> - if h = tl then true else check_settled t tl - -(*[check_dir] ensures movement in a certain direction is valid and adds the -*node to the frontier if it is viable or returns the same frontier if its not*) -let check_dir (d:direction) (t:tile) (map:map) (s: tile list) (f:(tile * int) list): ( tile * int) list = - let mapg = map.grid in - match t.coordinate with - |(x, y) -> - if (check_valid d map t.coordinate) then - (let next = match d with - |North -> mapg.(x).(y - 1) - |East -> mapg.(x + 1).(y) - |South -> mapg.(x).(y + 1) - |West -> mapg.(x - 1).(y) - in - match next.ground with - |Wall -> f - |Door -> f - |Damaged_wall (x) -> f - |Mountain -> f - |Ocean -> f - |Peaks -> if check_settled s next then f else add_f2 next 3 f - |Forest -> if check_settled s next then f else add_f2 next 2 f - |Desert -> if check_settled s next then f else add_f2 next 2 f - |_ -> if check_settled s next then f else add_f2 next 1 f) - else f - -(*[check_surround] checks movement in all directions of a given coordinate -*to expand the frontier set*) -let check_surround s t map f:(tile * int) list = - f - |> check_dir South t map s - |> check_dir East t map s - |> check_dir North t map s - |> check_dir West t map s - -(*[fill_map] initializes the path_map necessary to compute Djikstra's*) -let fill_map len wid = - let (t : path_tile) = {length = 1000;prev = None} in - Array.make_matrix len wid t - -(*[new_map] refreshes the map for a new target destination*) -let new_map (c : character)(pmap : path_map) = - let (t : path_tile) = {length = 1000;prev = None} in - let pmap2 = - { - length = pmap.length; - width = pmap.width; - grid = Array.make_matrix pmap.length pmap.width t - } - in - pmap2.grid.(fst c.location).(snd c.location) <- {length= 0; prev= None}; - pmap2 - -(*[update_map] takes a [path_map] and updates its values if a shorter path is -* found by the algorithm*) -let update_map (pmap : path_map) x y (ptile : path_tile) : path_map = - pmap.grid.(x).(y) <- ptile; - pmap - -(*[path_adjust] removes the movement cost of the tile the character is currently - * on from the shortest path cost*) -let rec path_adjust (lst : (int*(int*int)) list) acc sub = - match lst with - |[] -> acc - |h::t -> - match h with - |(x,y) -> - path_adjust t ((x - sub, y)::acc) sub - -(*[path_finder] searches a completed [path_map] to output a list of coordinates -* from the ally unit to the original enemy unit's coordinates*) -let rec path_finder coor pmap acc = - match coor with - |(x, y) -> - match pmap.grid.(x).(y).prev with - |None -> - if List.length acc > 0 then - List.rev (path_adjust acc [] (fst (List.hd acc))) - else - acc - |Some t -> - path_finder t pmap ((pmap.grid.(x).(y).length, t)::acc) - -(*[update_frontier] finds the updated costs of the frontier set adjacent to the - * newest settled node [tl]*) -let rec update_frontier (f : ( tile * int) list) (tl : tile) (m : map) (pmap : path_map) = - match f with - |[] -> pmap - |h::t -> - match (fst h).coordinate with - |(x,y) -> - let cost = - match m.grid.(x).(y).ground with - |Peaks -> 3 - |Forest -> 2 - |Desert -> 2 - |_ -> 1 in - let curr = pmap.grid.(fst tl.coordinate).(snd tl.coordinate).length in - if check_adjacent tl (fst h) m && curr + cost < pmap.grid.(x).(y).length then - let newt : path_tile = {length = (curr + cost); prev= Some tl.coordinate} in - let pmap2 = update_map pmap x y newt in - update_frontier t tl m pmap2 - else - update_frontier t tl m pmap - -(*[found_frontier] returns the lowest cost adjacent tile in the settled set to -* traverse to a given tile in the frontier*) -let rec found_frontier (last : int*int)(s : tile list) (tile : tile) (map : map) (pmap : path_map) mini = - match s with - |[] -> - if pmap.grid.(fst tile.coordinate).(snd tile.coordinate).length = 0 then - pmap - else - update_map pmap (fst tile.coordinate) (snd tile.coordinate) {length = mini; prev = Some last} - |h::t -> - if check_adjacent h tile map then - let cost = match map.grid.(fst h.coordinate).(snd h.coordinate).ground with - |Peaks -> 3 - |Forest -> 2 - |Desert -> 2 - |_ -> 1 in - let new_length = pmap.grid.(fst h.coordinate).(snd h.coordinate).length + - cost in - let pre = h.coordinate in - if new_length < mini then - found_frontier (pre) t tile map pmap new_length - else - (found_frontier last t tile map pmap mini) - else - (found_frontier last t tile map pmap mini) - -(*[naive_frontier] returns an arbitrary adjacent tile in the settled set to - * traverse to a given tile in the frontier*) -let rec naive_frontier c (s : tile list) (tile : tile) (map : map) (pmap : path_map)= - match s with - |[] -> - if pmap.grid.(fst tile.coordinate).(snd tile.coordinate).length = 0 then - (fst tile.coordinate, snd tile.coordinate) - else - c.location - |h::t -> - if check_adjacent h tile map then - let pre = h.coordinate in - pre - else - (naive_frontier c t tile map pmap) - -(*[print_frontier] debugging helper to print out frontier entries*) -let rec print_frontier lst = - match lst with - |[]->() - |h::t -> - print_string ("Frontier Entry:"^(string_of_int (fst (fst h).coordinate))^" "^(string_of_int (snd (fst h).coordinate))); - print_frontier t - - -(*[path_helper] runs djikstra's algorithm on the given map to find the shortest -* path from the enemy unit to the player unit it is targeting, and then calls -*[path_finder] to output a complete path -* f = frontier set, tile * int (move) list -* s = settled set, tile list -* t = current tile -* m = moves left -* map = map*) -let rec path_helper (c : character)(dest : int*int) (f: (tile*int) list) (s : tile list) tile (map : map) pmap = - let new_f = check_surround s tile map f in - match new_f with - |[] -> - path_finder dest pmap [] - |h::t -> - match (fst h).coordinate with - |(x,y) -> - if (fst h).coordinate = dest then - (let pmap2 = found_frontier (naive_frontier c s tile map pmap) s tile map pmap 1000 in - path_finder dest pmap2 []) - else - (let pmap2 = update_frontier new_f tile map pmap in - path_helper c dest t ((fst h)::s) (fst h) map pmap2) - -(*[search_helper] picks the closest player unit to attack and outputs the -* coordinates of the unit*) -let rec search_helper (m : map) (c : character) (lst : character list) pmap target = - match lst with - |[] -> - target - |h::t -> - match c.location with (x, y) -> - let check = path_helper c h.location [] [(m.grid.(x).(y))] m.grid.(x).(y) m (new_map c pmap) in - if List.length check > 0 && fst (List.hd (List.rev check)) < fst (List.hd (List.rev target)) && - (fst h.health) > 0 then - (search_helper m c t (new_map c pmap) check) - else - search_helper m c t (new_map c pmap) target - -(*[run] returns a free tile from a set that is not inhabited by another character*) -let rec run (lst : (int*int) list) (m : map) (loc : int*int) = - match lst with - |[] -> loc - |h::t -> - match h with - |(x, y) -> - if x >= 0 && x < m.width && y >= 0 && y < m.length then - match m.grid.(x).(y).c with - |Some k -> - run t m loc - |None -> - (x, y) - else - run t m loc - -(*[near_enemy] is a helper for [step_back] and it finds the enemy that is within - * an enemies minimum attack range*) -let rec near_enemy (lst : (int*int) list) (m : map) (c : int*int) loc acc = - match lst with - |[] -> loc - |h::t -> - match h with - |(x, y) -> - if x >= 0 && x < m.width && y >= 0 && y < m.length then - match m.grid.(x).(y).c with - |Some k -> - if not (k.allegiance = Enemy) then run (acc@t) m loc - else near_enemy t m c loc (h::acc) - |None -> - near_enemy t m c loc (h::acc) - else - near_enemy t m c loc acc - -(*[step_back] finds enemies that are adjacent to a character and returns a location - * for the character to run to*) -let step_back (m : map) (c : int*int) loc = - match c with - |(x, y) -> - near_enemy [(x, y - 1) ; (x + 1,y) ; (x, y + 1) ; (x - 1,y)] m c loc [] - - -(*[move] iterates through the shortest path to a target enemy unit, and moves as -* far on the path as permitted by its movement stats*) -let rec move (m : map) lst (c : character) range last (attk : int*int) loc = - match lst with - |[] -> (last) - |h::t -> - match h with - |(a, b) -> - if a <= range && (List.length t)> (fst attk) then - (match t with - |[] -> - (if m.grid.(fst b).(snd b).c = None then - move m t c range b attk b - else - loc) - |s::r -> - match s with - |(q, w) -> - (if q <= range then - move m t c range b attk b - else if m.grid.(fst b).(snd b).c = None then - move m t c range b attk b - else - loc)) - else if (List.length t) + 1 < (fst attk) then - step_back m c.location loc - else - (loc) - -(*[update_move] updates both characters and maps upon a character moving to a different -* position on the board*) -let update_move (m : map) (c : character) (init : int*int) (loc : int*int) = - c.location <- loc; - match init, loc with - |(x,y),(h, t) -> - let replace_tile = m.grid.(x).(y) in - let new_tile = m.grid.(h).(t) in - m.grid.(x).(y) <- - {coordinate = replace_tile.coordinate; - ground = replace_tile.ground; - tile_type = replace_tile.tile_type; - c = None}; - m.grid.(h).(t) <- - {coordinate = new_tile.coordinate; - ground = new_tile.ground; - tile_type = new_tile.tile_type; - c = Some c} - -(*[attack_inrange] will directly attack a player character only if it is standing - * on a space that is within its attack range*) -let rec attack_inrange m (c : character) (lst : character list) = - match lst with - |[] -> () - |h::t -> - match h.location, c.location with - |(x,y), (a, b)-> - if c.eqp > -1 && (fst h.health) > 0 && (fst c.health > 0) then - (let ar = attack_range c in - if List.exists (fun (q, r) -> q = x && r = y) ar = true then - combat c h - else - attack_inrange m c t) - else - () - -(*[search] finds the nearest enemy, and the moves and attacks for the enemy unit - * depending on the distance and tendencies of unit of that difficulty level - * AI Difficulty Behavior Detailed Below: - * Insane -> Omniscient unit that will track and move towards nearest player - * controlled unit no matter where it is on the board - * Hard -> Can sense player units within four times its movement zone, and will - * move towards players that enter that zone and attack if possible - * Normal -> Can sense player units within two times its movement zone and will - * move towards players that enter that zone and attack if possible - * Easy -> Will never move but will attack if player enters attack range*) -let search (m : map) (c : character) (lst : character list) pm (attk : int*int) = - if fst c.health = 0 then () else - match c.behave with - |Insane -> - ( match lst with - |[] -> () - |h::t -> - let init = - match c.location with (x, y) -> - path_helper c h.location [] [(m.grid.(x).(y))] m.grid.(x).(y) m (new_map c pm) in - let shortestpath = search_helper m c t pm init in - print_int (List.length shortestpath); - if List.length shortestpath > 0 then - let dest = snd (List.hd shortestpath) in - let go = move m shortestpath c c.mov c.location attk dest in - update_move m c c.location (go); - attack_inrange m c lst) - |Hard -> - (match lst with - |[] -> () - |h::t -> - let init = - match c.location with (x, y) -> - path_helper c h.location [] [(m.grid.(x).(y))] m.grid.(x).(y) m (new_map c pm) in - let close = search_helper m c t pm init in - if List.length close > 0 && fst (List.hd (List.rev close)) <= c.mov*4 then - let dest = snd (List.hd close) in - let go = move m close c c.mov c.location attk dest in - update_move m c c.location (go); - attack_inrange m c lst) - |Normal -> - (match lst with - |[] -> () - |h::t -> - let init = - match c.location with (x, y) -> - path_helper c h.location [] [(m.grid.(x).(y))] m.grid.(x).(y) m (new_map c pm) in - let close = search_helper m c t pm init in - if List.length close > 0 && fst (List.hd (List.rev close)) <= c.mov*2 then - let dest = snd (List.hd close) in - let go = move m close c c.mov c.location attk dest in - update_move m c c.location (go); - attack_inrange m c lst) - |Easy -> - if c.eqp > -1 then - let ind = c.eqp in - let item = (c.inv.(ind)) in - match item with - |None -> - () - |Some i -> - attack_inrange m c lst - -(*[ai_helper] iterates through enemy units and moves and attacks for them - * through calls to the helper functions*) -let rec ai_helper (m : map) (clist : character list) plist = - match clist with - |[] -> () - |h::t -> - let new_pm = - {width = m.width; - length = m.length; - grid = (fill_map m.length m.width)} in - if h.eqp > -1 then - (search m h plist new_pm ((extract h.inv.(h.eqp)).range); - ai_helper m t plist) - else - ai_helper m t plist - -(*[step] returns unit after all enemy characters have performed -* their desired actions*) -let step (e : character list) (p : character list) (m : map) = - ai_helper m e p +open Types +open Interactions + +(*[path_tile] store the intermediary values of our Djikstra's shortest + *path algorithm*) +type path_tile = { length : int; prev : (int * int) option } + +(*[path_map] is a data type to mirror our ingame map but store the paths to + *traverse to an allied unit from an enemy*) +type path_map = { width : int; length : int; grid : path_tile array array } + +(*[check_exist] ensures if a specific item exists in a list*) +let rec check_exist co lst = + match lst with + | [] -> false + | h :: t -> if fst h = co then true else check_exist co t + +(*[a_range_add] adds on to my attack range area*) +let a_range_add ma i co fl ml sl = + let addon = + if i > ma then [] + else + let nleft = (fst co - 1, snd co) in + let cleft = + if + fst co - 1 < 0 + || List.mem nleft ml || List.mem nleft sl || check_exist nleft fl + then [] + else [ (nleft, i) ] + in + let nright = (fst co + 1, snd co) in + let cright = + if + fst co + 1 > 14 + || List.mem nright ml || List.mem nright sl || check_exist nright fl + then cleft + else (nright, i) :: cleft + in + let nup = (fst co, snd co - 1) in + let cup = + if + snd co - 1 < 0 + || List.mem nup ml || List.mem nup sl || check_exist nup fl + then cright + else (nup, i) :: cright + in + let ndown = (fst co, snd co + 1) in + let cdown = + if + snd co + 1 > 14 + || List.mem ndown ml || List.mem ndown sl || check_exist ndown fl + then cup + else (ndown, i) :: cup + in + cdown + in + fl @ addon + +(*[attack_range_helper] helps construct an attack range based on a weapon's range*) +let rec attack_range_helper mi ma i co fl ml sl = + let nml = if i < mi then co :: ml else ml in + let nsl = if i >= mi then co :: sl else sl in + let nfl = a_range_add ma (i + 1) co fl ml sl in + match nfl with + | [] -> nsl + | (h, x) :: t -> attack_range_helper mi ma x h t nml nsl + +(*[attack_range] returns a list of coordinates within a character's attack range*) +let attack_range c = + let w = extract c.inv.(c.eqp) in + attack_range_helper (fst w.range) (snd w.range) 0 c.location [] [] [] + +(*[add_f2] is a list of frontier tiles sorted in increasing distance from a + * a settled node, as this is a grid map we know every frontier node is + * adjacent to a settled node therefore it's distance is its movement cost*) +let rec add_f2 (tile : tile) (i : int) (f : (tile * int) list) : + (tile * int) list = + match f with + | [] -> [ (tile, i) ] + | h :: t -> + if fst h = tile then if i < snd h then (tile, i) :: t else h :: t + else h :: add_f2 tile i t + +(*[check_valid] is whether or not given a location you can move in a certain + * direction *) +let check_valid d (m : map) loc = + match d with + | North -> snd loc - 1 > 0 + | East -> fst loc + 1 < m.width + | South -> snd loc + 1 < m.length + | West -> fst loc - 1 > 0 + +(*[check_adjacent] is whether or not given two tiles are adjacent on a map*) +let check_adjacent (t : tile) (f : tile) (m : map) = + match (t.coordinate, f.coordinate) with + | (x, y), (a, b) -> (abs (b - y) = 1 && a = x) || (abs (a - x) = 1 && b = y) + +(*[check_settled] is whether or not a given tile is already in the settled set*) +let rec check_settled (s : tile list) (tl : tile) = + match s with + | [] -> false + | h :: t -> if h = tl then true else check_settled t tl + +(*[check_dir] ensures movement in a certain direction is valid and adds the + *node to the frontier if it is viable or returns the same frontier if its not*) +let check_dir (d : direction) (t : tile) (map : map) (s : tile list) + (f : (tile * int) list) : (tile * int) list = + let mapg = map.grid in + match t.coordinate with + | x, y -> + if check_valid d map t.coordinate then + let next = + match d with + | North -> mapg.(x).(y - 1) + | East -> mapg.(x + 1).(y) + | South -> mapg.(x).(y + 1) + | West -> mapg.(x - 1).(y) + in + match next.ground with + | Wall -> f + | Door -> f + | Damaged_wall x -> f + | Mountain -> f + | Ocean -> f + | Peaks -> if check_settled s next then f else add_f2 next 3 f + | Forest -> if check_settled s next then f else add_f2 next 2 f + | Desert -> if check_settled s next then f else add_f2 next 2 f + | _ -> if check_settled s next then f else add_f2 next 1 f + else f + +(*[check_surround] checks movement in all directions of a given coordinate + *to expand the frontier set*) +let check_surround s t map f : (tile * int) list = + f |> check_dir South t map s |> check_dir East t map s + |> check_dir North t map s |> check_dir West t map s + +(*[fill_map] initializes the path_map necessary to compute Djikstra's*) +let fill_map len wid = + let (t : path_tile) = { length = 1000; prev = None } in + Array.make_matrix len wid t + +(*[new_map] refreshes the map for a new target destination*) +let new_map (c : character) (pmap : path_map) = + let (t : path_tile) = { length = 1000; prev = None } in + let pmap2 = + { + length = pmap.length; + width = pmap.width; + grid = Array.make_matrix pmap.length pmap.width t; + } + in + pmap2.grid.(fst c.location).(snd c.location) <- { length = 0; prev = None }; + pmap2 + +(*[update_map] takes a [path_map] and updates its values if a shorter path is + * found by the algorithm*) +let update_map (pmap : path_map) x y (ptile : path_tile) : path_map = + pmap.grid.(x).(y) <- ptile; + pmap + +(*[path_adjust] removes the movement cost of the tile the character is currently + * on from the shortest path cost*) +let rec path_adjust (lst : (int * (int * int)) list) acc sub = + match lst with + | [] -> acc + | h :: t -> ( match h with x, y -> path_adjust t ((x - sub, y) :: acc) sub) + +(*[path_finder] searches a completed [path_map] to output a list of coordinates + * from the ally unit to the original enemy unit's coordinates*) +let rec path_finder coor pmap acc = + match coor with + | x, y -> ( + match pmap.grid.(x).(y).prev with + | None -> + if List.length acc > 0 then + List.rev (path_adjust acc [] (fst (List.hd acc))) + else acc + | Some t -> path_finder t pmap ((pmap.grid.(x).(y).length, t) :: acc)) + +(*[update_frontier] finds the updated costs of the frontier set adjacent to the + * newest settled node [tl]*) +let rec update_frontier (f : (tile * int) list) (tl : tile) (m : map) + (pmap : path_map) = + match f with + | [] -> pmap + | h :: t -> ( + match (fst h).coordinate with + | x, y -> + let cost = + match m.grid.(x).(y).ground with + | Peaks -> 3 + | Forest -> 2 + | Desert -> 2 + | _ -> 1 + in + let curr = pmap.grid.(fst tl.coordinate).(snd tl.coordinate).length in + if + check_adjacent tl (fst h) m + && curr + cost < pmap.grid.(x).(y).length + then + let newt : path_tile = + { length = curr + cost; prev = Some tl.coordinate } + in + let pmap2 = update_map pmap x y newt in + update_frontier t tl m pmap2 + else update_frontier t tl m pmap) + +(*[found_frontier] returns the lowest cost adjacent tile in the settled set to + * traverse to a given tile in the frontier*) +let rec found_frontier (last : int * int) (s : tile list) (tile : tile) + (map : map) (pmap : path_map) mini = + match s with + | [] -> + if pmap.grid.(fst tile.coordinate).(snd tile.coordinate).length = 0 then + pmap + else + update_map pmap (fst tile.coordinate) (snd tile.coordinate) + { length = mini; prev = Some last } + | h :: t -> + if check_adjacent h tile map then + let cost = + match map.grid.(fst h.coordinate).(snd h.coordinate).ground with + | Peaks -> 3 + | Forest -> 2 + | Desert -> 2 + | _ -> 1 + in + let new_length = + pmap.grid.(fst h.coordinate).(snd h.coordinate).length + cost + in + let pre = h.coordinate in + if new_length < mini then found_frontier pre t tile map pmap new_length + else found_frontier last t tile map pmap mini + else found_frontier last t tile map pmap mini + +(*[naive_frontier] returns an arbitrary adjacent tile in the settled set to + * traverse to a given tile in the frontier*) +let rec naive_frontier c (s : tile list) (tile : tile) (map : map) + (pmap : path_map) = + match s with + | [] -> + if pmap.grid.(fst tile.coordinate).(snd tile.coordinate).length = 0 then + (fst tile.coordinate, snd tile.coordinate) + else c.location + | h :: t -> + if check_adjacent h tile map then + let pre = h.coordinate in + pre + else naive_frontier c t tile map pmap + +(*[print_frontier] debugging helper to print out frontier entries*) +let rec print_frontier lst = + match lst with + | [] -> () + | h :: t -> + print_string + ("Frontier Entry:" + ^ string_of_int (fst (fst h).coordinate) + ^ " " + ^ string_of_int (snd (fst h).coordinate)); + print_frontier t + +(*[path_helper] runs djikstra's algorithm on the given map to find the shortest + * path from the enemy unit to the player unit it is targeting, and then calls + *[path_finder] to output a complete path + * f = frontier set, tile * int (move) list + * s = settled set, tile list + * t = current tile + * m = moves left + * map = map*) +let rec path_helper (c : character) (dest : int * int) (f : (tile * int) list) + (s : tile list) tile (map : map) pmap = + let new_f = check_surround s tile map f in + match new_f with + | [] -> path_finder dest pmap [] + | h :: t -> ( + match (fst h).coordinate with + | x, y -> + if (fst h).coordinate = dest then + let pmap2 = + found_frontier + (naive_frontier c s tile map pmap) + s tile map pmap 1000 + in + path_finder dest pmap2 [] + else + let pmap2 = update_frontier new_f tile map pmap in + path_helper c dest t (fst h :: s) (fst h) map pmap2) + +(*[search_helper] picks the closest player unit to attack and outputs the + * coordinates of the unit*) +let rec search_helper (m : map) (c : character) (lst : character list) pmap + target = + match lst with + | [] -> target + | h :: t -> ( + match c.location with + | x, y -> + let check = + path_helper c h.location [] + [ m.grid.(x).(y) ] + m.grid.(x).(y) + m (new_map c pmap) + in + if + List.length check > 0 + && fst (List.hd (List.rev check)) < fst (List.hd (List.rev target)) + && fst h.health > 0 + then search_helper m c t (new_map c pmap) check + else search_helper m c t (new_map c pmap) target) + +(*[run] returns a free tile from a set that is not inhabited by another character*) +let rec run (lst : (int * int) list) (m : map) (loc : int * int) = + match lst with + | [] -> loc + | h :: t -> ( + match h with + | x, y -> + if x >= 0 && x < m.width && y >= 0 && y < m.length then + match m.grid.(x).(y).c with Some k -> run t m loc | None -> (x, y) + else run t m loc) + +(*[near_enemy] is a helper for [step_back] and it finds the enemy that is within + * an enemies minimum attack range*) +let rec near_enemy (lst : (int * int) list) (m : map) (c : int * int) loc acc = + match lst with + | [] -> loc + | h :: t -> ( + match h with + | x, y -> + if x >= 0 && x < m.width && y >= 0 && y < m.length then + match m.grid.(x).(y).c with + | Some k -> + if not (k.allegiance = Enemy) then run (acc @ t) m loc + else near_enemy t m c loc (h :: acc) + | None -> near_enemy t m c loc (h :: acc) + else near_enemy t m c loc acc) + +(*[step_back] finds enemies that are adjacent to a character and returns a location + * for the character to run to*) +let step_back (m : map) (c : int * int) loc = + match c with + | x, y -> + near_enemy [ (x, y - 1); (x + 1, y); (x, y + 1); (x - 1, y) ] m c loc [] + +(*[move] iterates through the shortest path to a target enemy unit, and moves as + * far on the path as permitted by its movement stats*) +let rec move (m : map) lst (c : character) range last (attk : int * int) loc = + match lst with + | [] -> last + | h :: t -> ( + match h with + | a, b -> + if a <= range && List.length t > fst attk then + match t with + | [] -> + if m.grid.(fst b).(snd b).c = None then + move m t c range b attk b + else loc + | s :: r -> ( + match s with + | q, w -> + if q <= range then move m t c range b attk b + else if m.grid.(fst b).(snd b).c = None then + move m t c range b attk b + else loc) + else if List.length t + 1 < fst attk then step_back m c.location loc + else loc) + +(*[update_move] updates both characters and maps upon a character moving to a different + * position on the board*) +let update_move (m : map) (c : character) (init : int * int) (loc : int * int) = + c.location <- loc; + match (init, loc) with + | (x, y), (h, t) -> + let replace_tile = m.grid.(x).(y) in + let new_tile = m.grid.(h).(t) in + m.grid.(x).(y) <- + { + coordinate = replace_tile.coordinate; + ground = replace_tile.ground; + tile_type = replace_tile.tile_type; + c = None; + }; + m.grid.(h).(t) <- + { + coordinate = new_tile.coordinate; + ground = new_tile.ground; + tile_type = new_tile.tile_type; + c = Some c; + } + +(*[attack_inrange] will directly attack a player character only if it is standing + * on a space that is within its attack range*) +let rec attack_inrange m (c : character) (lst : character list) = + match lst with + | [] -> () + | h :: t -> ( + match (h.location, c.location) with + | (x, y), (a, b) -> + if c.eqp > -1 && fst h.health > 0 && fst c.health > 0 then + let ar = attack_range c in + if List.exists (fun (q, r) -> q = x && r = y) ar = true then + combat c h + else attack_inrange m c t + else ()) + +(*[search] finds the nearest enemy, and the moves and attacks for the enemy unit + * depending on the distance and tendencies of unit of that difficulty level + * AI Difficulty Behavior Detailed Below: + * Insane -> Omniscient unit that will track and move towards nearest player + * controlled unit no matter where it is on the board + * Hard -> Can sense player units within four times its movement zone, and will + * move towards players that enter that zone and attack if possible + * Normal -> Can sense player units within two times its movement zone and will + * move towards players that enter that zone and attack if possible + * Easy -> Will never move but will attack if player enters attack range*) +let search (m : map) (c : character) (lst : character list) pm + (attk : int * int) = + if fst c.health = 0 then () + else + match c.behave with + | Insane -> ( + match lst with + | [] -> () + | h :: t -> + let init = + match c.location with + | x, y -> + path_helper c h.location [] + [ m.grid.(x).(y) ] + m.grid.(x).(y) + m (new_map c pm) + in + let shortestpath = search_helper m c t pm init in + print_int (List.length shortestpath); + if List.length shortestpath > 0 then ( + let dest = snd (List.hd shortestpath) in + let go = move m shortestpath c c.mov c.location attk dest in + update_move m c c.location go; + attack_inrange m c lst)) + | Hard -> ( + match lst with + | [] -> () + | h :: t -> + let init = + match c.location with + | x, y -> + path_helper c h.location [] + [ m.grid.(x).(y) ] + m.grid.(x).(y) + m (new_map c pm) + in + let close = search_helper m c t pm init in + if + List.length close > 0 + && fst (List.hd (List.rev close)) <= c.mov * 4 + then ( + let dest = snd (List.hd close) in + let go = move m close c c.mov c.location attk dest in + update_move m c c.location go; + attack_inrange m c lst)) + | Normal -> ( + match lst with + | [] -> () + | h :: t -> + let init = + match c.location with + | x, y -> + path_helper c h.location [] + [ m.grid.(x).(y) ] + m.grid.(x).(y) + m (new_map c pm) + in + let close = search_helper m c t pm init in + if + List.length close > 0 + && fst (List.hd (List.rev close)) <= c.mov * 2 + then ( + let dest = snd (List.hd close) in + let go = move m close c c.mov c.location attk dest in + update_move m c c.location go; + attack_inrange m c lst)) + | Easy -> ( + if c.eqp > -1 then + let ind = c.eqp in + let item = c.inv.(ind) in + match item with None -> () | Some i -> attack_inrange m c lst) + +(*[ai_helper] iterates through enemy units and moves and attacks for them + * through calls to the helper functions*) +let rec ai_helper (m : map) (clist : character list) plist = + match clist with + | [] -> () + | h :: t -> + let new_pm = + { width = m.width; length = m.length; grid = fill_map m.length m.width } + in + if h.eqp > -1 then ( + search m h plist new_pm (extract h.inv.(h.eqp)).range; + ai_helper m t plist) + else ai_helper m t plist + +(*[step] returns unit after all enemy characters have performed + * their desired actions*) +let step (e : character list) (p : character list) (m : map) = ai_helper m e p diff --git a/src/ai.mli b/src/ai.mli index ee3ff2e..6b88303 100644 --- a/src/ai.mli +++ b/src/ai.mli @@ -1,15 +1,14 @@ open Types (* * AI Difficulty Behavior Detailed Below: -* Insane -> Omniscient unit that will track and move towards nearest player -* controlled unit no matter where it is on the board -* Hard -> Can sense player units within four times its movement zone, and will -* move towards players that enter that zone and attack if possible -* Normal -> Can sense player units within two times its movement zone and will -* move towards players that enter that zone and attack if possible -* Easy -> Will never move but will attack if player enters attack range*) - + * Insane -> Omniscient unit that will track and move towards nearest player + * controlled unit no matter where it is on the board + * Hard -> Can sense player units within four times its movement zone, and will + * move towards players that enter that zone and attack if possible + * Normal -> Can sense player units within two times its movement zone and will + * move towards players that enter that zone and attack if possible + * Easy -> Will never move but will attack if player enters attack range*) (*[step] returns unit after all enemy characters have performed -* their desired actions*) -val step: character list -> character list -> map -> unit + * their desired actions*) +val step : character list -> character list -> map -> unit diff --git a/src/charactermaker.ml b/src/charactermaker.ml index 320c542..cd11925 100644 --- a/src/charactermaker.ml +++ b/src/charactermaker.ml @@ -1,594 +1,641 @@ -open Types -open Interactions -open Characters - -let nbow = - { - iname = "Iron Bow"; - wtype = Bow; - mgt = 3; - acc = 75; - crit = 10; - range = (2, 2); - uses = 45; - cost = 10; - sell = 10; - level = 'd'; - users = []; - effective = []; - penalty = []; - } - -let nsword = - { - iname = "Iron Sword"; - wtype = Sword; - mgt = 4; - acc = 90; - crit = 5; - range = (1, 1); - uses = 40; - cost = 10; - sell = 10; - level = 'd'; - users = []; - effective = []; - penalty = []; - } - -let ntome = - { - iname = "Fire"; - wtype = Tome; - mgt = 5; - acc = 80; - crit = 3; - range = (1, 2); - uses = 30; - cost = 10; - sell = 10; - level = 'd'; - users = []; - effective = []; - penalty = []; - } - -let sbow = - { - iname = "Steel Bow"; - wtype = Bow; - mgt = 7; - acc = 70; - crit = 5; - range = (1, 2); - uses = 30; - cost = 10; - sell = 10; - level = 'c'; - users = []; - effective = []; - penalty = [(Spd, (-5, -3))]; - } - -let ssword = - { - iname = "Kodachi"; - wtype = Sword; - mgt = 9; - acc = 85; - crit = 10; - range = (1, 2); - uses = 30; - cost = 10; - sell = 10; - level = 'c'; - users = []; - effective = []; - penalty = [(Spd, (-5, -3))]; - } - -let stome = - { - iname = "Ultimate Tome"; - wtype = Tome; - mgt = 10; - acc = 75; - crit = 0; - range = (1, 2); - uses = 30; - cost = 10; - sell = 10; - level = 'c'; - users = []; - effective = []; - penalty = [Spd, (-5, -3)]; - } - -let make_archer loc = - let arch = - { - name = "Archer"; - stage = Ready; - class' = Archer; - growths = []; - caps = []; - level = 2; - exp = 0; - health = (16,16); - allegiance = Enemy; - str = 6; - mag = 1; - def = 3; - spd = 4; - res = 2; - skl = 8; - lck = 2; - mov = 3; - con = 0; - aid = 0; - hit = 0; - atk = 0; - crit = 0; - avoid = 0; - inv = [|Some nbow;None;None;None;None|]; - eqp = 0; - ability = []; - supports = []; - wlevels = [(Bow,'d',0)]; - ai = Norm; - behave = Normal; - location = loc; - movement = []; - attackable = []; - direction = South; - is_attacking = false; - } in Characters.update_character arch; - arch - -let make_swordsman loc = - let swd = - { - name = "Melee"; - stage = Ready; - class' = Swordsman; - growths = []; - caps = []; - level = 2; - exp = 0; - health = (19, 19); - allegiance = Enemy; - str = 7; - mag = 0; - def = 3; - spd = 6; - res = 3; - skl = 7; - lck = 2; - mov = 4; - con = 0; - aid = 0; - hit = 0; - atk = 0; - crit = 0; - avoid = 0; - inv = [|Some nsword;None;None;None;None|]; - eqp = 0; - ability = []; - supports = []; - wlevels = [(Sword,'c',0)]; - ai = Norm; - behave = Hard; - location= loc; - movement= []; - attackable = []; - direction= South; - is_attacking=false; - } in Characters.update_character swd; - swd - -let make_mage loc = - let mg = - { - name = "Mage"; - stage = Ready; - class' = Mage; - growths = []; - caps = []; - level = 2; - exp = 0; - health = (17, 17); - allegiance = Enemy; - str = 1; - mag = 8; - def = 1; - spd = 4; - res = 5; - skl = 5; - lck = 3; - mov = 4; - con = 0; - aid = 0; - hit = 0; - atk = 0; - crit = 0; - avoid = 0; - inv = [|Some ntome;None;None;None;None|]; - eqp = 0; - ability = []; - supports = []; - wlevels = [(Tome,'d',0)]; - ai = Norm; - behave = Normal; - location= loc; - movement= []; - attackable = []; - direction= South; - is_attacking=false; - } in Characters.update_character mg; - mg - -let make_rangedboss (loc : int*int) = - let arch = - { - name = "Archer"; - stage = Ready; - class' = Archer; - growths = []; - caps = []; - level = 3; - exp = 0; - health = (25, 25); - allegiance = Enemy; - str = 7; - mag = 4; - def = 4; - spd = 7; - res = 4; - skl = 13; - lck = 4; - mov = 0; - con = 0; - aid = 0; - hit = 0; - atk = 0; - crit = 0; - avoid = 0; - inv = [|Some sbow;None;None;None;None|]; - eqp = 0; - ability = []; - supports = []; - wlevels = [(Bow,'b',0)]; - ai = BossStay; - behave = Easy; - location= loc; - movement= []; - attackable = []; - direction= South; - is_attacking=false; - } in - Characters.update_character arch; - arch - - let make_meleeboss loc = - let swd = - { - name = "Melee Boss"; - stage= Ready; - class' = Paladin; - growths = []; - caps = []; - level = 3; - exp = 0; - health = (30,30); - allegiance = Enemy; - str = 7; - mag = 0; - def = 5; - spd = 3; - res = 0; - skl = 5; - lck = 4; - mov = 0; - con = 0; - aid = 0; - hit = 0; - atk = 0; - crit = 0; - avoid = 0; - inv = [|Some ssword;None;None;None;None|]; - eqp = 0; - ability = []; - supports = []; - wlevels = [(Sword,'b',0); (Bow,'a',0)]; - ai = BossHunt; - behave = Easy; - location= loc; - movement= []; - attackable = []; - direction= South; - is_attacking=false; - } in Characters.update_character swd; - swd - - let make_mageboss loc = - let mg = - { - name = "Mage Boss"; - stage= Ready; - class' = Mage; - growths = []; - caps = []; - level = 3; - exp = 0; - health = (29,29); - allegiance = Enemy; - str = 3; - mag = 9; - def = 2; - spd = 7; - res = 4; - skl = 5; - lck = 4; - mov = 0; - con = 0; - aid = 0; - hit = 0; - atk = 0; - crit = 0; - avoid = 0; - inv = [|Some stome;None;None;None;None|]; - eqp = 0; - ability = []; - supports = []; - wlevels = [(Tome,'b',0)]; - ai = BossHunt; - behave = Normal; - location= loc; - movement= []; - attackable = []; - direction= South; - is_attacking=false; - } in Characters.update_character mg; - mg - -let mk = { - iname = "Mani Katti"; - wtype = Sword; - mgt = 6; - acc = 90; - crit = 20; - range = (1, 1); - uses = 30; - cost = 960; - sell = 20; - level = 'd'; - users = []; - effective = []; - penalty = []; -} - - -let mk = { - iname = "Mani Katti"; - wtype = Sword; - mgt = 6; - acc = 90; - crit = 20; - range = (1, 1); - uses = 30; - cost = 960; - sell = 20; - level = 'd'; - users = []; - effective = []; - penalty = []; -} - -let key = { - iname = "Key"; - wtype = Key; - mgt = 0; - acc = 0; - crit = 0; - range = (0, 0); - uses = 3; - cost = 0; - sell = 0; - level = 'd'; - users = []; - effective = []; - penalty = []; -} - -let vul = { - iname = "Vulnerary"; - wtype = Potion; - mgt = 10; - acc = 0; - crit = 0; - range = (0, 0); - uses = 3; - cost = 0; - sell = 0; - level = 'd'; - users = []; - effective = []; - penalty = []; -} - -let elixer = { - iname = "Elixer"; - wtype = Potion; - mgt = 20; - acc = 0; - crit = 0; - range = (0, 0); - uses = 3; - cost = 0; - sell = 0; - level = 'd'; - users = []; - effective = []; - penalty = []; -} - - -let make_lyn loc = - let lyn = - { - name = "Lyn"; - stage = Ready; - class' = Lord; - growths = [(Spd, 80); (Str, 60); (Def, 40); (Skl, 75); - (Mag, 10); (Health, 55); (Res, 45); (Lck, 50)]; - caps = []; - level = 1; - exp = 0; - health = (21, 21); - allegiance = Player; - str = 5; - mag = 0; - def = 3; - spd = 9; - res = 3; - skl = 7; - lck = 5; - mov = 4; - con = 0; - aid = 0; - hit = 0; - atk = 0; - crit = 0; - avoid = 0; - inv = [|Some (mk);Some (key);Some (vul);None;None|]; - eqp = 0; - ability = []; - supports = []; - wlevels = [(Sword,'d',0)]; - ai = BossHunt; - behave = Normal; - location = loc; - movement = []; - attackable = []; - direction= South; - is_attacking=false; - } in Characters.update_character lyn; - lyn - -let wolf = - { - iname = "Wolf Beil"; - wtype = Axe; - mgt = 9; - acc = 75; - crit = 10; - range = (1, 1); - uses = 30; - cost = 960; - sell = 20; - level = 'd'; - users = []; - effective = []; - penalty = []; - } - -let make_hector loc = - let hector = - { - name = "Hector"; - stage = Ready; - class' = Lord; - growths = [(Spd, 60); (Str, 80); (Def, 75); (Skl, 55); - (Mag, 5); (Health, 70); (Res, 20); (Lck, 60)]; - caps = []; - level = 1; - exp = 0; - health = (25, 25); - allegiance = Player; - str = 7; - mag = 0; - def = 7; - spd = 3; - res = 1; - skl = 5; - lck = 4; - mov = 3; - con = 0; - aid = 0; - hit = 0; - atk = 0; - crit = 0; - avoid = 0; - inv = [|Some (wolf);Some (elixer);None;None;None|]; - eqp = 0; - ability = []; - supports = []; - wlevels = [(Axe,'d',0)]; - ai = BossHunt; - behave = Normal; - location = loc; - movement = []; - attackable = []; - direction= South; - is_attacking=false; - } in Characters.update_character hector; - hector - - let make_erk loc = - let erk = - { - name = "Erk"; - stage = Ready; - class' = Mage; - growths = [(Spd, 70); (Str, 20); (Def, 40); (Skl, 60); - (Mag, 80); (Health, 40); (Res, 60); (Lck, 30)]; - caps = []; - level = 1; - exp = 0; - health = (20, 20); - allegiance = Player; - str = 1; - mag = 7; - def = 2; - spd = 5; - res = 5; - skl = 5; - lck = 4; - mov = 4; - con = 0; - aid = 0; - hit = 0; - atk = 0; - crit = 0; - avoid = 0; - inv = [|Some (ntome);Some (elixer);None;None;None|]; - eqp = 0; - ability = []; - supports = []; - wlevels = [(Tome,'d',0)]; - ai = BossHunt; - behave = Normal; - location = loc; - movement = []; - attackable = []; - direction= South; - is_attacking=false; - } in Characters.update_character erk; - erk - -let ilance = - { - iname = "Iron Lance"; - wtype = Lance; - mgt = 8; - acc = 85; - crit = 5; - range = (1, 1); - uses = 30; - cost = 960; - sell = 20; - level = 'd'; - users = []; - effective = []; - penalty = []; - } +open Types +open Interactions +open Characters + +let nbow = + { + iname = "Iron Bow"; + wtype = Bow; + mgt = 3; + acc = 75; + crit = 10; + range = (2, 2); + uses = 45; + cost = 10; + sell = 10; + level = 'd'; + users = []; + effective = []; + penalty = []; + } + +let nsword = + { + iname = "Iron Sword"; + wtype = Sword; + mgt = 4; + acc = 90; + crit = 5; + range = (1, 1); + uses = 40; + cost = 10; + sell = 10; + level = 'd'; + users = []; + effective = []; + penalty = []; + } + +let ntome = + { + iname = "Fire"; + wtype = Tome; + mgt = 5; + acc = 80; + crit = 3; + range = (1, 2); + uses = 30; + cost = 10; + sell = 10; + level = 'd'; + users = []; + effective = []; + penalty = []; + } + +let sbow = + { + iname = "Steel Bow"; + wtype = Bow; + mgt = 7; + acc = 70; + crit = 5; + range = (1, 2); + uses = 30; + cost = 10; + sell = 10; + level = 'c'; + users = []; + effective = []; + penalty = [ (Spd, (-5, -3)) ]; + } + +let ssword = + { + iname = "Kodachi"; + wtype = Sword; + mgt = 9; + acc = 85; + crit = 10; + range = (1, 2); + uses = 30; + cost = 10; + sell = 10; + level = 'c'; + users = []; + effective = []; + penalty = [ (Spd, (-5, -3)) ]; + } + +let stome = + { + iname = "Ultimate Tome"; + wtype = Tome; + mgt = 10; + acc = 75; + crit = 0; + range = (1, 2); + uses = 30; + cost = 10; + sell = 10; + level = 'c'; + users = []; + effective = []; + penalty = [ (Spd, (-5, -3)) ]; + } + +let make_archer loc = + let arch = + { + name = "Archer"; + stage = Ready; + class' = Archer; + growths = []; + caps = []; + level = 2; + exp = 0; + health = (16, 16); + allegiance = Enemy; + str = 6; + mag = 1; + def = 3; + spd = 4; + res = 2; + skl = 8; + lck = 2; + mov = 3; + con = 0; + aid = 0; + hit = 0; + atk = 0; + crit = 0; + avoid = 0; + inv = [| Some nbow; None; None; None; None |]; + eqp = 0; + ability = []; + supports = []; + wlevels = [ (Bow, 'd', 0) ]; + ai = Norm; + behave = Normal; + location = loc; + movement = []; + attackable = []; + direction = South; + is_attacking = false; + } + in + Characters.update_character arch; + arch + +let make_swordsman loc = + let swd = + { + name = "Melee"; + stage = Ready; + class' = Swordsman; + growths = []; + caps = []; + level = 2; + exp = 0; + health = (19, 19); + allegiance = Enemy; + str = 7; + mag = 0; + def = 3; + spd = 6; + res = 3; + skl = 7; + lck = 2; + mov = 4; + con = 0; + aid = 0; + hit = 0; + atk = 0; + crit = 0; + avoid = 0; + inv = [| Some nsword; None; None; None; None |]; + eqp = 0; + ability = []; + supports = []; + wlevels = [ (Sword, 'c', 0) ]; + ai = Norm; + behave = Hard; + location = loc; + movement = []; + attackable = []; + direction = South; + is_attacking = false; + } + in + Characters.update_character swd; + swd + +let make_mage loc = + let mg = + { + name = "Mage"; + stage = Ready; + class' = Mage; + growths = []; + caps = []; + level = 2; + exp = 0; + health = (17, 17); + allegiance = Enemy; + str = 1; + mag = 8; + def = 1; + spd = 4; + res = 5; + skl = 5; + lck = 3; + mov = 4; + con = 0; + aid = 0; + hit = 0; + atk = 0; + crit = 0; + avoid = 0; + inv = [| Some ntome; None; None; None; None |]; + eqp = 0; + ability = []; + supports = []; + wlevels = [ (Tome, 'd', 0) ]; + ai = Norm; + behave = Normal; + location = loc; + movement = []; + attackable = []; + direction = South; + is_attacking = false; + } + in + Characters.update_character mg; + mg + +let make_rangedboss (loc : int * int) = + let arch = + { + name = "Archer"; + stage = Ready; + class' = Archer; + growths = []; + caps = []; + level = 3; + exp = 0; + health = (25, 25); + allegiance = Enemy; + str = 7; + mag = 4; + def = 4; + spd = 7; + res = 4; + skl = 13; + lck = 4; + mov = 0; + con = 0; + aid = 0; + hit = 0; + atk = 0; + crit = 0; + avoid = 0; + inv = [| Some sbow; None; None; None; None |]; + eqp = 0; + ability = []; + supports = []; + wlevels = [ (Bow, 'b', 0) ]; + ai = BossStay; + behave = Easy; + location = loc; + movement = []; + attackable = []; + direction = South; + is_attacking = false; + } + in + Characters.update_character arch; + arch + +let make_meleeboss loc = + let swd = + { + name = "Melee Boss"; + stage = Ready; + class' = Paladin; + growths = []; + caps = []; + level = 3; + exp = 0; + health = (30, 30); + allegiance = Enemy; + str = 7; + mag = 0; + def = 5; + spd = 3; + res = 0; + skl = 5; + lck = 4; + mov = 0; + con = 0; + aid = 0; + hit = 0; + atk = 0; + crit = 0; + avoid = 0; + inv = [| Some ssword; None; None; None; None |]; + eqp = 0; + ability = []; + supports = []; + wlevels = [ (Sword, 'b', 0); (Bow, 'a', 0) ]; + ai = BossHunt; + behave = Easy; + location = loc; + movement = []; + attackable = []; + direction = South; + is_attacking = false; + } + in + Characters.update_character swd; + swd + +let make_mageboss loc = + let mg = + { + name = "Mage Boss"; + stage = Ready; + class' = Mage; + growths = []; + caps = []; + level = 3; + exp = 0; + health = (29, 29); + allegiance = Enemy; + str = 3; + mag = 9; + def = 2; + spd = 7; + res = 4; + skl = 5; + lck = 4; + mov = 0; + con = 0; + aid = 0; + hit = 0; + atk = 0; + crit = 0; + avoid = 0; + inv = [| Some stome; None; None; None; None |]; + eqp = 0; + ability = []; + supports = []; + wlevels = [ (Tome, 'b', 0) ]; + ai = BossHunt; + behave = Normal; + location = loc; + movement = []; + attackable = []; + direction = South; + is_attacking = false; + } + in + Characters.update_character mg; + mg + +let mk = + { + iname = "Mani Katti"; + wtype = Sword; + mgt = 6; + acc = 90; + crit = 20; + range = (1, 1); + uses = 30; + cost = 960; + sell = 20; + level = 'd'; + users = []; + effective = []; + penalty = []; + } + +let mk = + { + iname = "Mani Katti"; + wtype = Sword; + mgt = 6; + acc = 90; + crit = 20; + range = (1, 1); + uses = 30; + cost = 960; + sell = 20; + level = 'd'; + users = []; + effective = []; + penalty = []; + } + +let key = + { + iname = "Key"; + wtype = Key; + mgt = 0; + acc = 0; + crit = 0; + range = (0, 0); + uses = 3; + cost = 0; + sell = 0; + level = 'd'; + users = []; + effective = []; + penalty = []; + } + +let vul = + { + iname = "Vulnerary"; + wtype = Potion; + mgt = 10; + acc = 0; + crit = 0; + range = (0, 0); + uses = 3; + cost = 0; + sell = 0; + level = 'd'; + users = []; + effective = []; + penalty = []; + } + +let elixer = + { + iname = "Elixer"; + wtype = Potion; + mgt = 20; + acc = 0; + crit = 0; + range = (0, 0); + uses = 3; + cost = 0; + sell = 0; + level = 'd'; + users = []; + effective = []; + penalty = []; + } + +let make_lyn loc = + let lyn = + { + name = "Lyn"; + stage = Ready; + class' = Lord; + growths = + [ + (Spd, 80); + (Str, 60); + (Def, 40); + (Skl, 75); + (Mag, 10); + (Health, 55); + (Res, 45); + (Lck, 50); + ]; + caps = []; + level = 1; + exp = 0; + health = (21, 21); + allegiance = Player; + str = 5; + mag = 0; + def = 3; + spd = 9; + res = 3; + skl = 7; + lck = 5; + mov = 4; + con = 0; + aid = 0; + hit = 0; + atk = 0; + crit = 0; + avoid = 0; + inv = [| Some mk; Some key; Some vul; None; None |]; + eqp = 0; + ability = []; + supports = []; + wlevels = [ (Sword, 'd', 0) ]; + ai = BossHunt; + behave = Normal; + location = loc; + movement = []; + attackable = []; + direction = South; + is_attacking = false; + } + in + Characters.update_character lyn; + lyn + +let wolf = + { + iname = "Wolf Beil"; + wtype = Axe; + mgt = 9; + acc = 75; + crit = 10; + range = (1, 1); + uses = 30; + cost = 960; + sell = 20; + level = 'd'; + users = []; + effective = []; + penalty = []; + } + +let make_hector loc = + let hector = + { + name = "Hector"; + stage = Ready; + class' = Lord; + growths = + [ + (Spd, 60); + (Str, 80); + (Def, 75); + (Skl, 55); + (Mag, 5); + (Health, 70); + (Res, 20); + (Lck, 60); + ]; + caps = []; + level = 1; + exp = 0; + health = (25, 25); + allegiance = Player; + str = 7; + mag = 0; + def = 7; + spd = 3; + res = 1; + skl = 5; + lck = 4; + mov = 3; + con = 0; + aid = 0; + hit = 0; + atk = 0; + crit = 0; + avoid = 0; + inv = [| Some wolf; Some elixer; None; None; None |]; + eqp = 0; + ability = []; + supports = []; + wlevels = [ (Axe, 'd', 0) ]; + ai = BossHunt; + behave = Normal; + location = loc; + movement = []; + attackable = []; + direction = South; + is_attacking = false; + } + in + Characters.update_character hector; + hector + +let make_erk loc = + let erk = + { + name = "Erk"; + stage = Ready; + class' = Mage; + growths = + [ + (Spd, 70); + (Str, 20); + (Def, 40); + (Skl, 60); + (Mag, 80); + (Health, 40); + (Res, 60); + (Lck, 30); + ]; + caps = []; + level = 1; + exp = 0; + health = (20, 20); + allegiance = Player; + str = 1; + mag = 7; + def = 2; + spd = 5; + res = 5; + skl = 5; + lck = 4; + mov = 4; + con = 0; + aid = 0; + hit = 0; + atk = 0; + crit = 0; + avoid = 0; + inv = [| Some ntome; Some elixer; None; None; None |]; + eqp = 0; + ability = []; + supports = []; + wlevels = [ (Tome, 'd', 0) ]; + ai = BossHunt; + behave = Normal; + location = loc; + movement = []; + attackable = []; + direction = South; + is_attacking = false; + } + in + Characters.update_character erk; + erk + +let ilance = + { + iname = "Iron Lance"; + wtype = Lance; + mgt = 8; + acc = 85; + crit = 5; + range = (1, 1); + uses = 30; + cost = 960; + sell = 20; + level = 'd'; + users = []; + effective = []; + penalty = []; + } diff --git a/src/charactermaker.mli b/src/charactermaker.mli index 3e3a327..b91e08b 100644 --- a/src/charactermaker.mli +++ b/src/charactermaker.mli @@ -1,14 +1,22 @@ -open Types -open Interactions +open Types +open Interactions (*[Charactermaker] is a module designed to easily create character instances - * at a given coordinate*) -val make_archer : int*int -> character -val make_swordsman : int*int -> character -val make_mage : int*int -> character -val make_rangedboss : int*int -> character -val make_meleeboss : int*int -> character -val make_mageboss : int*int -> character -val make_lyn : int * int -> character -val make_hector : int * int -> character -val make_erk : int * int -> character + * at a given coordinate*) +val make_archer : int * int -> character + +val make_swordsman : int * int -> character + +val make_mage : int * int -> character + +val make_rangedboss : int * int -> character + +val make_meleeboss : int * int -> character + +val make_mageboss : int * int -> character + +val make_lyn : int * int -> character + +val make_hector : int * int -> character + +val make_erk : int * int -> character diff --git a/src/characters.ml b/src/characters.ml index 656e48f..44c91e5 100644 --- a/src/characters.ml +++ b/src/characters.ml @@ -1,262 +1,262 @@ -open Types - - -(** - * [cap lst s] is a function that finds the cap of a skill, s, in a list of * skill caps, lst. If s is not in lst, then it will return a cap of 40. - * requires: - * - [lst] is a valid list - * - [s] is a valid stat -*) -let rec cap lst s = - match lst with - |[] -> 40 - |h::t -> if fst h = s then snd h else cap t s - -(** - * [equipped c] is a fuction that returns an item option that represent the - * character, c,'s equipped item. If they do not have an equipped item then it - * will return [None]. - * requires: - * - [c] is a valid character -*) -let equipped c = - if c.eqp = -1 then None else (c.inv.(c.eqp)) - -(** - * [lv_to_int a] is a function that converts a weapon level, a, represented by - * a character to an int. - * requires: - * - [a] is a character that is from a - e or s. - * raises: "invalid weapon level" if it is not one of the above characters. -*) -let lv_to_int a = - match a with - |'s' -> 5 - |'a' -> 4 - |'b' -> 3 - |'c' -> 2 - |'d' -> 1 - |'e' -> 0 - |_ -> failwith "invalid weapon level" - -(** - * [comp a b] is fuction that returns true if weapon level a is greater than - * or equal to b. Has unspecified behaviour if a and b are not in a - e or s. - * requires: - * - [a] is a character from a - e or s. - * - [b] is a character from a - e or s. -*) -let comp a b = - (lv_to_int a) >= (lv_to_int b) - - -(** - * [prof wlvlst i] is a fuction that checks if the holder of a weapon level - * list is capable of using an item, i. Returns false if not and true if so. - * requires: - * - [wlvlst] is a weapon level list of type (wtype * char * int) list. - * - [i] is a valid item. -*) -let rec prof wlvlst i = - match wlvlst with - |[] -> false - |(x, y, z)::t -> if i.wtype = x then (if comp y i.level then true else false) - else prof t i - -(** - * [equippable c i] is a fuction that checks if a character, c, can equip an * item, i. - * requires: - * - [c] is a valid character. - * - [i] is a valid item. -*) -let equippable c i = - match i.wtype with - | Staff | Potion | Key -> false - | x -> prof c.wlevels i - -(** - * [equip_id c n] find the index of the first equippable item in a character. - * Returns -1 if they have no equippable items. - * requires: - * - [c] is a valid character. - * - the initial [n] passed in is 0. - * Has unspecified behaviour if the [n] passed in is not 0 to start with. -*) -let rec equip_id c n = - match c.inv.(n) with - |None -> if n = 4 then -1 else equip_id c (n+1) - |Some x -> if equippable c x then n - else if n = 4 then -1 else equip_id c (n+1) - -(** - * [stat_up c s i] is a function that returns a character, [c], with the passed - * stat, [s], changed by [i] points. If increasing a stat would push it past - * the cap then cap the stat instead. - * requires: - * - [c] is a valid character - * - [s] is a valid stat - * - [i] is an int. -*) -let stat_up (c:character) s i = - match s with - |Health -> - let from_cap = 60 - snd c.health in - if from_cap < i then c.health <- ((fst c.health) + from_cap, - (snd c.health) + from_cap) - else - c.health <- ((fst c.health) + i, (snd c.health) + i) - |Str -> - let str = c.str + i in - let cap_str = cap c.caps Str in - if str > cap_str then c.str <- cap_str else c.str <- str - |Mag -> - let mag = c.mag + i in - let cap_mag = cap c.caps Mag in - if mag > cap_mag then c.mag <- cap_mag else c.mag <- mag - |Def -> - let def = c.def + i in - let cap_def = cap c.caps Def in - if def > cap_def then c.def <- cap_def else c.def <- def - |Spd -> - let spd = c.spd + i in - let cap_spd = cap c.caps Spd in - if spd > cap_spd then c.spd <- cap_spd else c.spd <- spd - |Res -> - let res = c.res + i in - let cap_res = cap c.caps Res in - if res > cap_res then c.res <- cap_res else c.res <- res - |Skl -> - let skl = c.skl + i in - let cap_skl = cap c.caps Skl in - if skl > cap_skl then c.skl <- cap_skl else c.skl <- skl - |Lck -> - let lck = c.lck + i in - let cap_lck = cap c.caps Lck in - if lck > cap_lck then c.lck <- cap_lck else c.lck <- lck - -(** - * [level_up_h c g] takes a list of stat growths, [g], and a character, [c] and - * rolls a number for each stat. If the number is high enough it will - * increment that stat by 1, otherwise 0. Returns [c] with all its stats rolled - * requires: - * - [c] is a valid character - * - [g] is that character's growth rates. -*) -let rec level_up_h c g = - match g with - |[] -> () - |h::t -> - if let rng = Random.int 100 in - snd h > rng - then (stat_up c (fst h) 1; level_up_h c t) - else level_up_h c t - -(** [level_up c] is a function that returns [c] with its stats rolled for and - * exp decreased by 100 if [c]'s current exp is more than 100, otherwise - * returns [c]. - * requires: [c] is a valid character -*) -let level_up c = - if c.exp >= 100 then (level_up_h c c.growths; c.exp <- c.exp - 100; - c.level <- c.level + 1) - else () - -(** [update_health c i] returns [c] with its health lowered by [i]. If [c]'s - * health would have gone over it's max health or under 0 then set it to max - * or 0 respectively. - * requires: [c] and [i] are valid characters and int respectively -*) -let update_health (c:character) i = - if i >= fst c.health then c.health <- (0, snd c.health); - if fst c.health - i > snd c.health then c.health <- (snd c.health, snd c.health) - else c.health <- (fst c.health - i), snd c.health - -(** [add_item c i] adds an item [i] to [c]'s inventory. - * requires: - * - [c] is a valid character - - [i] is a valid item -*) -let rec add_helper a i n = - if n = 5 then () else - match a.(n) with - |Some x -> add_helper a i (n + 1) - |None -> a.(n) <- Some i - -let add_item c i = - add_helper c.inv i 0 - -(** [update_character c] updates a characters values to be correct. If the - * character has > 100 xp, it will level it up. If the character has too - * little or too much hp, it will fix it. It will also update a characters - * hit, atk, crit, and avoid stats. - * requires: [c] is a character -*) -let rec update_character c = - if c.exp > 100 then (level_up c; update_character c); - if fst c.health < 0 then (c.health <- (0, snd c.health); update_character c); - if fst c.health > snd c.health then (c.health <- (snd c.health, snd c.health); update_character c); - let e = equip_id c 0 in - let calc_hit = - if e = -1 then 0 else - match c.inv.(e) with - |None -> 0 - |Some x -> x.acc + 2 * c.skl + c.lck - in - let calc_atk = - if e = -1 then 0 else - match c.inv.(e) with - |None -> 0 - |Some x -> if c.class' = Mage then x.mgt + c.mag else x.mgt + c.str - in - let calc_crit = - if e = -1 then 0 else - match c.inv.(e) with - |None -> 0 - |Some x -> x.crit + (c.lck / 2) - in - let calc_avoid = c.spd + c.lck in - c.hit <- calc_hit; - c.atk <- calc_atk; - c.crit <- calc_crit; - c.avoid <- calc_avoid; - c.eqp <- e - -(** - * [remove_item a i] removes an item i from a characters inventory. - * requires: - * - [a] is a valid character - * - [i] is an int from 0 to 4. - * Has unspecified behaviour if passed a number not in that range. -*) -let remove_item a i = - a.inv.(i) <- None - -(** - * [move_to_top a i] is a function that takes an index, i, and move the item - * in that index to the from of a character, a,'s inventory. - * requires: - * - [a] is a valid character - * - [i] is an int from 0 to 4. - * Has unspecified behavious if [i] is not in that range. -*) -let move_to_top a i = - let temp = a.inv.(0) in - a.inv.(0) <- a.inv.(i); - a.inv.(i) <- temp; - update_character a - -(** - * [use i] decrements the number uses on an item option and - * rewraps it. - * requires: - * - [i] is a valid item option that isn't [None]. - * raises: "no uses" if passed None. -*) -let use i = - match i with - |None -> failwith "no uses" - |Some x -> if x.uses = 1 then None else Some {x with uses = x.uses - 1} - -(** - * [] -*) \ No newline at end of file +open Types + +(** + * [cap lst s] is a function that finds the cap of a skill, s, in a list of * skill caps, lst. If s is not in lst, then it will return a cap of 40. + * requires: + * - [lst] is a valid list + * - [s] is a valid stat +*) +let rec cap lst s = + match lst with [] -> 40 | h :: t -> if fst h = s then snd h else cap t s + +(** + * [equipped c] is a fuction that returns an item option that represent the + * character, c,'s equipped item. If they do not have an equipped item then it + * will return [None]. + * requires: + * - [c] is a valid character +*) +let equipped c = if c.eqp = -1 then None else c.inv.(c.eqp) + +(** + * [lv_to_int a] is a function that converts a weapon level, a, represented by + * a character to an int. + * requires: + * - [a] is a character that is from a - e or s. + * raises: "invalid weapon level" if it is not one of the above characters. +*) +let lv_to_int a = + match a with + | 's' -> 5 + | 'a' -> 4 + | 'b' -> 3 + | 'c' -> 2 + | 'd' -> 1 + | 'e' -> 0 + | _ -> failwith "invalid weapon level" + +(** + * [comp a b] is fuction that returns true if weapon level a is greater than + * or equal to b. Has unspecified behaviour if a and b are not in a - e or s. + * requires: + * - [a] is a character from a - e or s. + * - [b] is a character from a - e or s. +*) +let comp a b = lv_to_int a >= lv_to_int b + +(** + * [prof wlvlst i] is a fuction that checks if the holder of a weapon level + * list is capable of using an item, i. Returns false if not and true if so. + * requires: + * - [wlvlst] is a weapon level list of type (wtype * char * int) list. + * - [i] is a valid item. +*) +let rec prof wlvlst i = + match wlvlst with + | [] -> false + | (x, y, z) :: t -> + if i.wtype = x then if comp y i.level then true else false else prof t i + +(** + * [equippable c i] is a fuction that checks if a character, c, can equip an * item, i. + * requires: + * - [c] is a valid character. + * - [i] is a valid item. +*) +let equippable c i = + match i.wtype with Staff | Potion | Key -> false | x -> prof c.wlevels i + +(** + * [equip_id c n] find the index of the first equippable item in a character. + * Returns -1 if they have no equippable items. + * requires: + * - [c] is a valid character. + * - the initial [n] passed in is 0. + * Has unspecified behaviour if the [n] passed in is not 0 to start with. +*) +let rec equip_id c n = + match c.inv.(n) with + | None -> if n = 4 then -1 else equip_id c (n + 1) + | Some x -> + if equippable c x then n else if n = 4 then -1 else equip_id c (n + 1) + +(** + * [stat_up c s i] is a function that returns a character, [c], with the passed + * stat, [s], changed by [i] points. If increasing a stat would push it past + * the cap then cap the stat instead. + * requires: + * - [c] is a valid character + * - [s] is a valid stat + * - [i] is an int. +*) +let stat_up (c : character) s i = + match s with + | Health -> + let from_cap = 60 - snd c.health in + if from_cap < i then + c.health <- (fst c.health + from_cap, snd c.health + from_cap) + else c.health <- (fst c.health + i, snd c.health + i) + | Str -> + let str = c.str + i in + let cap_str = cap c.caps Str in + if str > cap_str then c.str <- cap_str else c.str <- str + | Mag -> + let mag = c.mag + i in + let cap_mag = cap c.caps Mag in + if mag > cap_mag then c.mag <- cap_mag else c.mag <- mag + | Def -> + let def = c.def + i in + let cap_def = cap c.caps Def in + if def > cap_def then c.def <- cap_def else c.def <- def + | Spd -> + let spd = c.spd + i in + let cap_spd = cap c.caps Spd in + if spd > cap_spd then c.spd <- cap_spd else c.spd <- spd + | Res -> + let res = c.res + i in + let cap_res = cap c.caps Res in + if res > cap_res then c.res <- cap_res else c.res <- res + | Skl -> + let skl = c.skl + i in + let cap_skl = cap c.caps Skl in + if skl > cap_skl then c.skl <- cap_skl else c.skl <- skl + | Lck -> + let lck = c.lck + i in + let cap_lck = cap c.caps Lck in + if lck > cap_lck then c.lck <- cap_lck else c.lck <- lck + +(** + * [level_up_h c g] takes a list of stat growths, [g], and a character, [c] and + * rolls a number for each stat. If the number is high enough it will + * increment that stat by 1, otherwise 0. Returns [c] with all its stats rolled + * requires: + * - [c] is a valid character + * - [g] is that character's growth rates. +*) +let rec level_up_h c g = + match g with + | [] -> () + | h :: t -> + if + let rng = Random.int 100 in + snd h > rng + then ( + stat_up c (fst h) 1; + level_up_h c t) + else level_up_h c t + +(** [level_up c] is a function that returns [c] with its stats rolled for and + * exp decreased by 100 if [c]'s current exp is more than 100, otherwise + * returns [c]. + * requires: [c] is a valid character +*) +let level_up c = + if c.exp >= 100 then ( + level_up_h c c.growths; + c.exp <- c.exp - 100; + c.level <- c.level + 1) + else () + +(** [update_health c i] returns [c] with its health lowered by [i]. If [c]'s + * health would have gone over it's max health or under 0 then set it to max + * or 0 respectively. + * requires: [c] and [i] are valid characters and int respectively +*) +let update_health (c : character) i = + if i >= fst c.health then c.health <- (0, snd c.health); + if fst c.health - i > snd c.health then + c.health <- (snd c.health, snd c.health) + else c.health <- (fst c.health - i, snd c.health) + +(** [add_item c i] adds an item [i] to [c]'s inventory. + * requires: + * - [c] is a valid character + - [i] is a valid item +*) +let rec add_helper a i n = + if n = 5 then () + else + match a.(n) with + | Some x -> add_helper a i (n + 1) + | None -> a.(n) <- Some i + +let add_item c i = add_helper c.inv i 0 + +(** [update_character c] updates a characters values to be correct. If the + * character has > 100 xp, it will level it up. If the character has too + * little or too much hp, it will fix it. It will also update a characters + * hit, atk, crit, and avoid stats. + * requires: [c] is a character +*) +let rec update_character c = + if c.exp > 100 then ( + level_up c; + update_character c); + if fst c.health < 0 then ( + c.health <- (0, snd c.health); + update_character c); + if fst c.health > snd c.health then ( + c.health <- (snd c.health, snd c.health); + update_character c); + let e = equip_id c 0 in + let calc_hit = + if e = -1 then 0 + else + match c.inv.(e) with None -> 0 | Some x -> x.acc + (2 * c.skl) + c.lck + in + let calc_atk = + if e = -1 then 0 + else + match c.inv.(e) with + | None -> 0 + | Some x -> if c.class' = Mage then x.mgt + c.mag else x.mgt + c.str + in + let calc_crit = + if e = -1 then 0 + else match c.inv.(e) with None -> 0 | Some x -> x.crit + (c.lck / 2) + in + let calc_avoid = c.spd + c.lck in + c.hit <- calc_hit; + c.atk <- calc_atk; + c.crit <- calc_crit; + c.avoid <- calc_avoid; + c.eqp <- e + +(** + * [remove_item a i] removes an item i from a characters inventory. + * requires: + * - [a] is a valid character + * - [i] is an int from 0 to 4. + * Has unspecified behaviour if passed a number not in that range. +*) +let remove_item a i = a.inv.(i) <- None + +(** + * [move_to_top a i] is a function that takes an index, i, and move the item + * in that index to the from of a character, a,'s inventory. + * requires: + * - [a] is a valid character + * - [i] is an int from 0 to 4. + * Has unspecified behavious if [i] is not in that range. +*) +let move_to_top a i = + let temp = a.inv.(0) in + a.inv.(0) <- a.inv.(i); + a.inv.(i) <- temp; + update_character a + +(** + * [use i] decrements the number uses on an item option and + * rewraps it. + * requires: + * - [i] is a valid item option that isn't [None]. + * raises: "no uses" if passed None. +*) +let use i = + match i with + | None -> failwith "no uses" + | Some x -> if x.uses = 1 then None else Some { x with uses = x.uses - 1 } + +(** + * [] +*) diff --git a/src/characters.mli b/src/characters.mli index f4c3a05..b711942 100644 --- a/src/characters.mli +++ b/src/characters.mli @@ -1,59 +1,58 @@ -open Types - - -(** - * [character] handles all the functions that involve reading and editing - * character values -*) - -(** - * [equipped] returns the character's equipped item -*) -val equipped : character -> item option - -(** - * [equippable] returns whether or not a character can equip an item -*) -val equippable: character -> item -> bool - -(** - * [stat_up] increases a stat by a certain amount -*) -val stat_up : character -> stat -> int -> unit - -(** - * level_up returns the character with its level increased and stats - * incremented. -*) -val level_up : character -> unit - -(** - * [update_health ch] will return the character [ch] with its health incremented -*) -val update_health : character -> int -> unit - -(** - * [update character] updates all the character -*) -val update_character : character -> unit - -(** - * [add_item] adds an item to a characters inventory. If there is no space - * then it does nothing -*) -val add_item : character -> item -> unit - -(** - * [remove_item] removes an item from a characters inventory -*) -val remove_item : character -> int -> unit - -(** - * [move_to_top] moves an item to the top of the inventory -*) -val move_to_top : character -> int -> unit - -(** - * [use i] decrements the number of uses on an item by 1 -*) -val use : item option -> item option \ No newline at end of file +open Types + +(** + * [character] handles all the functions that involve reading and editing + * character values +*) + +val equipped : character -> item option +(** + * [equipped] returns the character's equipped item +*) + +val equippable : character -> item -> bool +(** + * [equippable] returns whether or not a character can equip an item +*) + +val stat_up : character -> stat -> int -> unit +(** + * [stat_up] increases a stat by a certain amount +*) + +val level_up : character -> unit +(** + * level_up returns the character with its level increased and stats + * incremented. +*) + +val update_health : character -> int -> unit +(** + * [update_health ch] will return the character [ch] with its health incremented +*) + +val update_character : character -> unit +(** + * [update character] updates all the character +*) + +val add_item : character -> item -> unit +(** + * [add_item] adds an item to a characters inventory. If there is no space + * then it does nothing +*) + +val remove_item : character -> int -> unit +(** + * [remove_item] removes an item from a characters inventory +*) + +val move_to_top : character -> int -> unit +(** + * [move_to_top] moves an item to the top of the inventory +*) + +val use : item option -> item option +(** + * [use i] decrements the number of uses on an item by 1 +*) diff --git a/src/command.ml b/src/command.ml index ee09765..a4d430a 100644 --- a/src/command.ml +++ b/src/command.ml @@ -1,19 +1,21 @@ open Types open Gui open Js_of_ocaml - module Html = Dom_html + let js = Js.string let keydown event = Dom.preventDefault event; - let () = match event##.keyCode with - |90 ->input := A (* Mapped to Z used to select units *) - |88 ->input := B (* Mapped to X used to deselect *) - |65 ->input := LT - |38 ->input := Up - |40 ->input := Down - |37 ->input := Left - |39 ->input := Right - |_ ->input := Nothing - in Js._true + let () = + match event##.keyCode with + | 90 -> input := A (* Mapped to Z used to select units *) + | 88 -> input := B (* Mapped to X used to deselect *) + | 65 -> input := LT + | 38 -> input := Up + | 40 -> input := Down + | 37 -> input := Left + | 39 -> input := Right + | _ -> input := Nothing + in + Js._true diff --git a/src/gui.ml b/src/gui.ml index f823772..fe04695 100644 --- a/src/gui.ml +++ b/src/gui.ml @@ -1,1906 +1,2119 @@ -open Types -open State -open Interactions -open Js_of_ocaml - -let canvas_width = 546. -let canvas_height = 390. - -module Html = Dom_html -let js = Js.string -let document = Html.document - -let clock = ref 1 -let sync = ref true -let transition = ref 1000 -let transition_start = ref false - -(*********************************************************) -(***************** Map Drawing Functions *****************) -(*********************************************************) - -(* [tile_to_img_mapping obj] returns the image source - * as a Js.string directiory location of the - * associated tile *) -let tile_to_img_mapping (tile : tile) = - match tile.tile_type with - | Grass -> js "Sprites/grass.png" - | Tree -> js "Sprites/tree.png" - | Crack -> js "Sprites/Crack.png" - | Bridge -> js "Sprites/Bridge.png" - | Bush -> js "Sprites/Bush.png" - | Darkbush -> js "Sprites/Darkbush.png" - | Water1 -> js "Sprites/Water1.png" - | Water2 -> js "Sprites/Water2.png" - | Water3 -> js "Sprites/Water3.png" - | Water4 -> js "Sprites/Water4.png" - | Water5 -> js "Sprites/Water5.png" - | Water6 -> js "Sprites/Water6.png" - | Water7 -> js "Sprites/Water7.png" - | Water8 -> js "Sprites/Water8.png" - | Water9 -> js "Sprites/Water9.png" - | Water10 -> js "Sprites/Water10.png" - | Wall1 -> js "Sprites/Wall1.png" - | Wall2 -> js "Sprites/Wall2.png" - | Wall3 -> js "Sprites/Wall3.png" - | Wall4 -> js "Sprites/Wall4.png" - | Wall5 -> js "Sprites/Wall5.png" - | Wall6 -> js "Sprites/Wall6.png" - | Castle1 -> js "Sprites/Map2/castle1.png" - | Castle2 -> js "Sprites/Map2/castle2.png" - | Castle3 -> js "Sprites/Map2/castle3.png" - | Castle4 -> js "Sprites/Map2/castle4.png" - | Castle5 -> js "Sprites/Map2/castle5.png" - | Castle6 -> js "Sprites/Map2/castle6.png" - | Castle7 -> js "Sprites/Map2/castle7.png" - | Castle8 -> js "Sprites/Map2/castle8.png" - | Castle9 -> js "Sprites/Map2/castle9.png" - | House1 -> js "Sprites/Map2/house1.png" - | House2 -> js "Sprites/Map2/house2.png" - | House3 -> js "Sprites/Map2/house3.png" - | House4 -> js "Sprites/Map2/house4.png" - | House5 -> js "Sprites/Map2/house5.png" - | House6 -> js "Sprites/Map2/house6.png" - | Water11 -> js "Sprites/Map2/Water11.png" - | Water12 -> js "Sprites/Map2/Water12.png" - | Chesttile -> js "Sprites/Map2/chest.png" - - -(* [draw_tiles map] draws each of the tiles of the state's current - * active map *) -let draw_map (context: Html.canvasRenderingContext2D Js.t) state = - context##.fillStyle := (js "black"); - context##fillRect 0. 0. canvas_width canvas_height; - let draw_tiles (grid : tile array array) = - for i = 0 to 14 do - for j = 0 to 14 do - let tile = grid.(i).(j) in - let x = fst tile.coordinate in - let y = snd tile.coordinate in - let img_src = tile_to_img_mapping tile in - let img = Html.createImg document in - img##.src := img_src; - context##drawImage img (26.*.float_of_int x) (26.*.float_of_int y) - done - done in - draw_tiles state.act_map.grid - -(*********************************************************) -(**************** Cursor Drawing Functions ***************) -(*********************************************************) - -(* [clock ()] updates the clock at every loop of the game. - * Every 15 "time" units, sync is negated which represents the - * static movement of the cursor and players *) -let clock () = - clock := if !clock < 35 then !clock + 1 else 1; - transition := if (!transition >= 0) && (!transition_start) = true then !transition - 2 else !transition; - let x1 = !clock mod 35 in (* bounds *) - match x1 with - | 0 -> sync := not(!sync) - | _ -> () - -(* [draw_cursor context tile] draws the cursor (big) on the - * canvas given the integer location defined in tile *) -let draw_cursor_big (context: Html.canvasRenderingContext2D Js.t) tile = - let (x,y) = tile.coordinate in - let img = Html.createImg document in - img##.src := js "Sprites/CursorLarge.png"; - context##drawImage img (26. *. float_of_int x) (26. *. float_of_int y) - -(* [draw_cursor context tile] draws the cursor (small) on the - * canvas given the integer location defined in tile *) -let draw_cursor_small (context: Html.canvasRenderingContext2D Js.t) tile = - let (x,y) = tile.coordinate in - let img = Html.createImg document in - img##.src := js "Sprites/CursorSmall.png"; - context##drawImage img (26. *. float_of_int x) (26. *. float_of_int y) - -(* [draw_cursor context tile] chooses to draw a big cursor or small - * cursor based on the current synchornization reference (sync) and - * then draws that cursor on the coordinate defined by tile *) -let draw_cursor (context: Html.canvasRenderingContext2D Js.t) tile = - match (!sync) with - | true -> - draw_cursor_small context tile - | false -> - draw_cursor_big context tile - - -(*********************************************************) -(**************** Sprite Drawing Functions ***************) -(*********************************************************) - -(* [testf context] is a debugging function *) -let testf context = - let img = Html.createImg document in - img##.src := js "Sprites/databackground.png"; - context##drawImage img 0. 0. - -(* [draw_sprite] draws the sprite located at (sx,sy) with - * sw width and sh height inside the spritesheet and - * projects it onto the canvas at location (x,y) *) -let draw_sprite img_src context (sx, sy) (sw, sh) (x,y) = - let img = Html.createImg document in - img##.src := img_src; - context##drawImage_full img sx sy sw sh x y 25. 25. - -(* [draw_sprite] draws the sprite located at (sx,sy) with - * sw width and sh height inside the spritesheet and - * projects it onto the canvas at location (x,y) *) -let draw_sprite_hector img_src context (sx, sy) (sw, sh) (x,y) = - let img = Html.createImg document in - img##.src := img_src; - context##drawImage_full img sx sy sw sh x y 30. 25. - -(* [draw_lyn context character] draws the proper sprite configuration - * for the character lyn based on the character's direction and stage - * fields. Also accounts for animation by using the sync gloal - * reference which allows switching between sprites *) -let draw_lyn (context: Html.canvasRenderingContext2D Js.t) character = - let img = js "Sprites/lynsheet.png" in - match character.direction with - | South -> begin - match character.stage with - | Ready|MoveDone|AttackSelect|TradeSelect -> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (417., 400.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (457., 399.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - | MoveSelect -> begin - match ((!sync)) with - | true-> - let sprite_coordinate = (463., 419.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 6.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (420., 420.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 6.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - | Done when character.is_attacking=true-> begin - match ((!sync)) with - | true-> - let sprite_coordinate = (463., 419.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 6.,26. *. (float_of_int y) +. 6.) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;moved_forward:=true - - | false -> - let sprite_coordinate = (420., 420.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 6.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;if !moved_forward = true then - (moved_forward:=false;attacking:=false;character.is_attacking<-false) else () - end - | Done when character.is_attacking=false -> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (417., 400.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (457., 399.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - |Done -> () - end - | East -> begin - match character.stage with - | Ready|MoveDone|AttackSelect|TradeSelect -> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (417., 400.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (457., 399.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - | MoveSelect -> begin - match ((!sync)) with - | true-> - let sprite_coordinate = (418., 442.) in - let sprite_wxl = (16., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 0.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (441., 442.) in - let sprite_wxl = (16., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 0.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - | Done when character.is_attacking = true ->begin - match ((!sync)) with - | true-> - let sprite_coordinate = (418., 442.) in - let sprite_wxl = (16., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 6.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;moved_forward:=true - | false -> - let sprite_coordinate = (441., 442.) in - let sprite_wxl = (16., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 0.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;if !moved_forward = true then - (moved_forward:=false;attacking:=false;character.is_attacking<-false) else () - end - | Done when character.is_attacking = false-> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (417., 400.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (457., 399.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - |Done -> () - end - | North -> begin - match character.stage with - | Ready|MoveDone|AttackSelect|TradeSelect -> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (417., 400.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (457., 399.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - | MoveSelect -> begin - match ((!sync)) with - | true-> - let sprite_coordinate = (419., 461.) in - let sprite_wxl = (16., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 0.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (442., 461.) in - let sprite_wxl = (16., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 0.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - | Done when character.is_attacking = true-> begin - match ((!sync)) with - | false-> - let sprite_coordinate = (419., 461.) in - let sprite_wxl = (16., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 0.,26. *. (float_of_int y) -. 6.) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;moved_forward:=true - | true-> - let sprite_coordinate = (442., 461.) in - let sprite_wxl = (16., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 0.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;if !moved_forward = true then - (moved_forward:=false;attacking:=false;character.is_attacking<-false) else () - end - | Done when character.is_attacking = false-> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (417., 400.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (457., 399.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - |Done -> () - end - | West -> begin - match character.stage with - | Ready|MoveDone|AttackSelect|TradeSelect -> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (417., 400.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (457., 399.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - | MoveSelect -> begin - match ((!sync)) with - | true-> - let sprite_coordinate = (419., 461.) in - let sprite_wxl = (16., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 0.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (442., 461.) in - let sprite_wxl = (16., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 0.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - | Done when character.is_attacking = true-> begin - match ((!sync)) with - | false-> - let sprite_coordinate = (419., 461.) in - let sprite_wxl = (16., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 0.,26. *. (float_of_int y) -. 6.) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;moved_forward:=true - | true-> - let sprite_coordinate = (442., 461.) in - let sprite_wxl = (16., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 6.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;if !moved_forward = true then - (moved_forward:=false;attacking:=false;character.is_attacking<-false) else () - end - | Done when character.is_attacking = false-> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (417., 400.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (457., 399.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - |Done -> () - end - - -(* [draw_hector context character] draws the proper sprite configuration - * for the character lyn based on the character's direction and stage - * fields. Also accounts for animation by using the sync gloal - * reference which allows switching between sprites *) -let draw_hector (context: Html.canvasRenderingContext2D Js.t) character = - let img = js "Sprites/PlayerSprites.png" in - match character.direction with - | South -> begin - match character.stage with - | Ready|MoveDone|AttackSelect|TradeSelect -> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (224., 280.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (224., 312.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - end - | MoveSelect -> begin - match ((!sync)) with - | true-> - let sprite_coordinate = (258., 345.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (258., 281.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - end - | Done when character.is_attacking=true-> begin - match ((!sync)) with - | true-> - let sprite_coordinate = (224., 280.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y) +. 6.) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;moved_forward:=true - - | false -> - let sprite_coordinate = (329., 339.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;if !moved_forward = true then - (moved_forward:=false;attacking:=false;character.is_attacking<-false) else () - end - | Done when character.is_attacking=false -> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (224., 280.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (224., 312.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - end - |Done -> () - end - | East -> begin - match character.stage with - | Ready|MoveDone|AttackSelect|TradeSelect -> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (224., 280.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (224., 312.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - end - | MoveSelect -> begin - match ((!sync)) with - | true-> - let sprite_coordinate = (258., 345.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (258., 281.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - end - | Done when character.is_attacking = true ->begin - match ((!sync)) with - | true-> - let sprite_coordinate = (224., 280.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 3.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;moved_forward:=true - | false -> - let sprite_coordinate = (329., 339.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;if !moved_forward = true then - (moved_forward:=false;attacking:=false;character.is_attacking<-false) else () - end - | Done when character.is_attacking = false-> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (224., 280.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (224., 312.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - end - |Done -> () - end - | North -> begin - match character.stage with - | Ready|MoveDone|AttackSelect|TradeSelect -> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (224., 280.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (224., 312.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - end - | MoveSelect -> begin - match ((!sync)) with - | true-> - let sprite_coordinate = (258., 345.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (258., 281.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - end - | Done when character.is_attacking = true-> begin - match ((!sync)) with - | true-> - let sprite_coordinate = (224., 280.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y) -. 6.) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;moved_forward:=true - | false -> - let sprite_coordinate = (329., 339.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;if !moved_forward = true then - (moved_forward:=false;attacking:=false;character.is_attacking<-false) else () - end - | Done when character.is_attacking = false-> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (224., 280.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (224., 312.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - end - |Done -> () - end - | West -> begin - match character.stage with - | Ready|MoveDone|AttackSelect|TradeSelect -> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (224., 280.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (224., 312.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - end - | MoveSelect -> begin - match ((!sync)) with - | true-> - let sprite_coordinate = (258., 345.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (258., 281.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - end - | Done when character.is_attacking = true-> begin - match ((!sync)) with - | true-> - let sprite_coordinate = (224., 280.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 9.,26. *. (float_of_int y) -. 6.) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;moved_forward:=true - | false -> - let sprite_coordinate = (329., 339.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;if !moved_forward = true then - (moved_forward:=false;attacking:=false;character.is_attacking<-false) else () - end - | Done when character.is_attacking = false-> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (224., 280.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (224., 312.) in - let sprite_wxl = (22., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 3.,26. *. (float_of_int y)) in - draw_sprite_hector img context sprite_coordinate sprite_wxl coordinate - end - |Done -> () - end - -(* [draw_erk context character] draws the proper sprite configuration - * for the character lyn based on the character's direction and stage - * fields. Also accounts for animation by using the sync gloal - * reference which allows switching between sprites *) -let draw_erk (context: Html.canvasRenderingContext2D Js.t) character = - let img = js "Sprites/PlayerSprites.png" in - match character.direction with - | South -> begin - match character.stage with - | Ready|MoveDone|AttackSelect|TradeSelect -> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (197., 1907.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (198., 1939.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - | MoveSelect -> begin - match ((!sync)) with - | true-> - let sprite_coordinate = (262., 1874.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 6.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (263., 1938.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 6.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - | Done when character.is_attacking=true-> begin - match ((!sync)) with - | true-> - let sprite_coordinate = (325., 1908.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 6.,26. *. (float_of_int y) +. 6.) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;moved_forward:=true - - | false -> - let sprite_coordinate = (198., 1939.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 6.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;if !moved_forward = true then - (moved_forward:=false;attacking:=false;character.is_attacking<-false) else () - end - | Done when character.is_attacking=false -> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (197., 1907.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (198., 1939.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - |Done -> () - end - | East -> begin - match character.stage with - | Ready|MoveDone|AttackSelect|TradeSelect -> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (197., 1907.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (198., 1939.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - | MoveSelect -> begin - match ((!sync)) with - | true-> - let sprite_coordinate = (262., 1874.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 6.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (263., 1938.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 6.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - | Done when character.is_attacking = true ->begin - match ((!sync)) with - | true-> - let sprite_coordinate = (325., 1908.) in - let sprite_wxl = (16., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 6.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;moved_forward:=true - | false -> - let sprite_coordinate = (198., 1939.) in - let sprite_wxl = (16., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 0.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;if !moved_forward = true then - (moved_forward:=false;attacking:=false;character.is_attacking<-false) else () - end - | Done when character.is_attacking = false-> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (197., 1907.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (198., 1939.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - |Done -> () - end - | North -> begin - match character.stage with - | Ready|MoveDone|AttackSelect|TradeSelect -> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (197., 1907.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (198., 1939.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - | MoveSelect -> begin - match ((!sync)) with - | true-> - let sprite_coordinate = (262., 1874.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 6.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (263., 1938.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 6.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - | Done when character.is_attacking = true-> begin - match ((!sync)) with - | true-> - let sprite_coordinate = (325., 1908.) in - let sprite_wxl = (16., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 0.,26. *. (float_of_int y) -. 6.) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;moved_forward:=true - | false -> - let sprite_coordinate = (198., 1939.) in - let sprite_wxl = (16., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 0.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;if !moved_forward = true then - (moved_forward:=false;attacking:=false;character.is_attacking<-false) else () - end - | Done when character.is_attacking = false-> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (197., 1907.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (198., 1939.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - |Done -> () - end - | West -> begin - match character.stage with - | Ready|MoveDone|AttackSelect|TradeSelect -> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (197., 1907.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (198., 1939.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - | MoveSelect -> begin - match ((!sync)) with - | true-> - let sprite_coordinate = (262., 1874.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 6.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (263., 1938.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 6.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - | Done when character.is_attacking = true-> begin - match ((!sync)) with - | true-> - let sprite_coordinate = (325., 1908.) in - let sprite_wxl = (16., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) -. 6.,26. *. (float_of_int y) -. 6.) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;moved_forward:=true - | false -> - let sprite_coordinate = (198., 1939.) in - let sprite_wxl = (16., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x) +. 0.,26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate;if !moved_forward = true then - (moved_forward:=false;attacking:=false;character.is_attacking<-false) else () - end - | Done when character.is_attacking = false-> begin - match ((!sync)) with - | true -> - let sprite_coordinate = (197., 1907.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - | false -> - let sprite_coordinate = (198., 1939.) in - let sprite_wxl = (15., 16.) in - let (x,y) = character.location in - let coordinate = (26. *. (float_of_int x),26. *. (float_of_int y)) in - draw_sprite img context sprite_coordinate sprite_wxl coordinate - end - |Done -> () - end - - -(* [draw_archer context enemy] draws the archer - * [eenmy] on the [context] *) -let draw_archer context enemy = - match ((!sync)) with - | true -> - let img = Html.createImg document in - let (x,y) = enemy.location in - img##.src := js "Sprites/EnemySprites/Enemy_Archer_NE.png"; - context##drawImage_full img 20. 11. 26. 26. (float_of_int x *. 26. +. 6.) (float_of_int y *. 26.) 25. 22. - | false -> - let img = Html.createImg document in - let (x,y) = enemy.location in - img##.src := js "Sprites/EnemySprites/Enemy_Archer_E.png"; - context##drawImage_full img 16. 18. 26. 26. (float_of_int x *. 26. +. 6.) (float_of_int y *. 26.) 25. 28. - -(* [draw_player context character_list] draws all the characters inside - * the character_list. [character_list] is a general list of characters - * which may be players, allies, or enemies *) -let rec draw_player (context: Html.canvasRenderingContext2D Js.t) character_list = - match character_list with - | [] -> () - | h::t -> - match h.name with - | "Lyn" -> draw_lyn context h;draw_player context t - | "Erk" -> draw_erk context h; draw_player context t - | "Hector" -> draw_hector context h;draw_player context t - | "Archer" -> - draw_archer context h; - draw_player context t - | _ -> () - -(*********************************************************) -(***************** Menu Drawing Functions ****************) -(*********************************************************) - -(* [draw_back_1 context] draws the background for a - * menu of size 1 *) -let draw_back_1 (context : Html.canvasRenderingContext2D Js.t) = - let x = 281. in - let y = 26. in - let rec ys x y = - if x = 385. then () - else - let img = Html.createImg document in - img##.src := js "Sprites/databackground.png"; - context##drawImage img x y; - if y = 26. then ys (x+.26.) 26. else ys x (y+.26.) in - ys x y - -(* [draw_text_1 context str_arr] draws the outer white - * rectangle around the menu and text in str_arr - * on a menu of size 1 *) -let draw_text_1 (context : Html.canvasRenderingContext2D Js.t) str_arr = - context##.strokeStyle := (js "white"); - context##.font := js "16px sans-serif"; - context##strokeRect 280. 26. 110. 30.; - let position = ref 50. in - for i = 0 to Array.length str_arr - 1 do - context##.fillStyle := (js "white"); - context##fillText (js str_arr.(i)) 300. !position; - position := !position +. 25. - done - -(* [draw_back_2 context] draws the background for a - * menu of size 2 *) -let draw_back_2 (context : Html.canvasRenderingContext2D Js.t) = - let x = 281. in - let y = 26. in - let rec ys x y = - if x = 385. then () - else - let img = Html.createImg document in - img##.src := js "Sprites/databackground.png"; - context##drawImage img x y; - if y = 52. then ys (x+.26.) 26. else ys x (y+.26.) in - ys x y - -(* [draw_text_2 context str_arr] draws the outer white - * rectangle around the menu and text in str_arr - * on a menu of size 2 *) -let draw_text_2 (context : Html.canvasRenderingContext2D Js.t) str_arr = - context##.strokeStyle := (js "white"); - context##.font := js "16px sans-serif"; - context##strokeRect 280. 26. 110. 56.; - let position = ref 50. in - for i = 0 to Array.length str_arr - 1 do - context##.fillStyle := (js "white"); - context##fillText (js str_arr.(i)) 300. !position; - position := !position +. 25. - done - -(* [draw_back_4 context] draws the background for a - * menu of size 4 *) -let draw_back_4 (context : Html.canvasRenderingContext2D Js.t) = - let x = 281. in - let y = 26. in - let rec ys x y = - if x = 385. then () - else - let img = Html.createImg document in - img##.src := js "Sprites/databackground.png"; - context##drawImage img x y; - if y = 104. then ys (x+.26.) 26. else ys x (y+.26.) in - ys x y - -(* [draw_text_4 context str_arr] draws the outer white - * rectangle around the menu and text in str_arr - * on a menu of size 4 *) -let draw_text_4 (context : Html.canvasRenderingContext2D Js.t) str_arr = - context##.strokeStyle := (js "white"); - context##.font := js "16px sans-serif"; - context##strokeRect 280. 26. 110. 108. ; - let position = ref 50. in - for i = 0 to Array.length str_arr - 1 do - context##.fillStyle := (js "white"); - context##fillText (js str_arr.(i)) 300. !position; - position := !position +. 25. - done - -(* [draw_back_5 context] draws the background for a - * menu of size 5 *) -let draw_back_5 (context : Html.canvasRenderingContext2D Js.t) = - let x = 281. in - let y = 26. in - let rec ys x y = - if x = 385. then () - else - let img = Html.createImg document in - img##.src := js "Sprites/databackground.png"; - context##drawImage img x y; - if y = 130. then ys (x+.26.) 26. else ys x (y+.26.) in - ys x y - -(* [draw_text_5 context str_arr] draws the outer white - * rectangle around the menu and text in str_arr - * on a menu of size 5 *) -let draw_text_5 (context : Html.canvasRenderingContext2D Js.t) str_arr = - context##.strokeStyle := (js "white"); - context##.font := js "16px sans-serif"; - context##strokeRect 280. 26. 110. 134.; - let position = ref 50. in - for i = 0 to Array.length str_arr - 1 do - context##.fillStyle := (js "white"); - context##fillText (js str_arr.(i)) 300. !position; - position := !position +. 25. - done - -(* [draw_back_6 context] draws the background for a - * menu of size 6 *) -let draw_back_6 context = - let x = 281. in - let y = 26. in - let rec ys x y = - if x = 385. then () - else - let img = Html.createImg document in - img##.src := js "Sprites/databackground.png"; - context##drawImage img x y; - if y = 156. then ys (x+.26.) 26. else ys x (y+.26.) in - ys x y - -(* [draw_text_6 context str_arr] draws the outer white - * rectangle around the menu and text in str_arr - * on a menu of size 6 *) -let draw_text_6 context str_arr = - context##.strokeStyle := (js "white"); - context##.font := js "16px sans-serif"; - context##strokeRect 280. 26. 110. 161.; - let position = ref 50. in - for i = 0 to Array.length str_arr - 1 do - context##.fillStyle := (js "white"); - context##fillText (js str_arr.(i)) 300. !position; - position := !position +. 25. - done - -(* [draw_back_7 context] draws the background for a - * menu of size 7 *) -let draw_back_7 context = - let x = 281. in - let y = 26. in - let rec ys x y = - if x = 385. then () - else - let img = Html.createImg document in - img##.src := js "Sprites/databackground.png"; - context##drawImage img x y; - if y = 182. then ys (x+.26.) 26. else ys x (y+.26.) in - ys x y - -(* [draw_text_7 context str_arr] draws the outer white - * rectangle around the menu and text in str_arr - * on a menu of size 7 *) -let draw_text_7 context str_arr = - context##.strokeStyle := (js "white"); - context##.font := js "16px sans-serif"; - context##strokeRect 280. 26. 110. 186.; - let position = ref 50. in - for i = 0 to Array.length str_arr - 1 do - context##.fillStyle := (js "white"); - context##fillText (js str_arr.(i)) 300. !position; - position := !position +. 25. - done - -(* [draw_1_menu context menu] draws the [menu] - * of size 1 *) -let draw_1_menu context menu = - draw_back_1 context; - draw_text_1 context menu.options - -(* [draw_2_menu context menu] draws the [menu] - * of size 2 *) -let draw_2_menu context menu = - draw_back_2 context; - draw_text_2 context menu.options - -(* [draw_4_menu context menu] draws the [menu] - * of size 4 *) -let draw_4_menu context menu = - draw_back_4 context; - draw_text_4 context menu.options - -(* [draw_5_menu context menu] draws the [menu] - * of size 5 *) -let draw_5_menu context menu = - draw_back_5 context; - draw_text_5 context menu.options - -(* [draw_6_menu context menu] draws the [menu] - * of size 6 *) -let draw_6_menu context menu = - draw_back_6 context; - draw_text_6 context menu.options - -(* [draw_7_menu context menu] draws the [menu] - * of size 7 *) -let draw_7_menu context menu = - draw_back_7 context; - draw_text_7 context menu.options - -(* [menu_manager context state] draws a menu - * if is active, otherwise does nothing *) -let menu_manager (context : Html.canvasRenderingContext2D Js.t) state = - if state.menu_active then - match state.current_menu.size with - | 1 -> draw_1_menu context state.current_menu - | 2 -> draw_2_menu context state.current_menu - | 4 -> draw_4_menu context state.current_menu - | 5 -> draw_5_menu context state.current_menu - | 6 -> draw_6_menu context state.current_menu - | 7 -> draw_7_menu context state.current_menu - | _ -> () - else () - -(*********************************************************) -(******************** Draw Health Bar ********************) -(*********************************************************) - -(* [draw_health context health max_health x y] is the health bar - * that apperas under the player. Health bar is calculated using - * the percentage of health remaining out of max_health. x and y - * are coordinates that health bar will be drawn at *) -let draw_health context health max_health x y = - let hp = float_of_int health in - let max_hp = float_of_int max_health in - if (hp = 0.) then () - else if (hp <= max_hp *. 0.125) then - let img = Html.createImg document in - img##.src := js "Sprites/RedHealth.png"; - for i = (x + 1) to (x + 3) do - context##drawImage img (float_of_int i) (float_of_int y +. 1.); - done - else if (hp <= max_hp *. 0.25) then - let img = Html.createImg document in - img##.src := js "Sprites/RedHealth.png"; - for i = (x + 1) to (x + 6) do - context##drawImage img (float_of_int i) (float_of_int y +. 1.); - done - else if (hp <= max_hp *. 0.375) then - let img = Html.createImg document in - img##.src := js "Sprites/YellowHealth.png"; - for i = (x + 1) to (x + 9) do - context##drawImage img (float_of_int i) (float_of_int y +. 1.); - done - else if (hp <= (max_hp *. 0.5)) then - let img = Html.createImg document in - img##.src := js "Sprites/YellowHealth.png"; - for i = (x + 1) to (x + 12) do - context##drawImage img (float_of_int i) (float_of_int y +. 1.); - done - else if (hp <= (max_hp *. 0.625)) then - let img = Html.createImg document in - img##.src := js "Sprites/GreenHealth.png"; - for i = (x + 1) to (x + 15) do - context##drawImage img (float_of_int i) (float_of_int y +. 1.); - done - else if (hp <= (max_hp *. 0.75)) then - let img = Html.createImg document in - img##.src := js "Sprites/GreenHealth.png"; - for i = (x + 1) to (x + 18) do - context##drawImage img (float_of_int i) (float_of_int y +. 1.); - done - else if (hp <= (max_hp *. 0.875)) then - let img = Html.createImg document in - img##.src := js "Sprites/GreenHealth.png"; - for i = (x + 1) to (x + 21) do - context##drawImage img (float_of_int i) (float_of_int y +. 1.); - done - else - let img = Html.createImg document in - img##.src := js "Sprites/GreenHealth.png"; - for i = (x + 1) to (x + 24) do - context##drawImage img (float_of_int i) (float_of_int y +. 1.); - done - -(* [draw_healthbar context chr_list] draws a health - * bar for all the characters inside [chr_list]. The - * health bar will appear under the player and is - * either red, yellow, or green depending on the amount of - * health left *) -let rec draw_healthbar context chr_list = - match chr_list with - | [] -> () - | chr::t -> - let (x,y) = chr.location in - let x' = x * 26 + 3 in - let y' = y * 26 + 23 in - let (health, max_health) = chr.health in - let img = Html.createImg document in - img##.src := js "Sprites/HealthBar.png"; - context##drawImage img (float_of_int x') (float_of_int y'); - draw_health context health max_health x' y'; - draw_healthbar context t - - - -(*********************************************************) -(****************** Draw Arrow Functions *****************) -(*********************************************************) - -(* [draw_menu_arrow context state] draws the blue right - * facing error pointing to the current selection on a - * menu. Arrow is also animated using sync global reference*) -let draw_menu_arrow context state = - let img = Html.createImg document in - img##.src := js "Sprites/arrow.png"; - if state.menu_active then - match state.menu_cursor with - | 0 -> begin - match ((!sync)) with - | true -> context##drawImage img 271. 32. - | false -> context##drawImage img 273. 32. - end - | 1 -> begin - match ((!sync)) with - | true -> context##drawImage img 271. 58. - | false -> context##drawImage img 273. 58. - end - | 2 -> begin - match ((!sync)) with - | true -> context##drawImage img 271. 84. - | false -> context##drawImage img 273. 84. - end - | 3 -> begin - match ((!sync)) with - | true -> context##drawImage img 271. 110. - | false -> context##drawImage img 273. 110. - end - | 4 -> begin - match ((!sync)) with - | true -> context##drawImage img 271. 136. - | false -> context##drawImage img 273. 136. - end - | 5 -> begin - match ((!sync)) with - | true -> context##drawImage img 271. 162. - | false -> context##drawImage img 273. 162. - end - | 6 -> begin - match ((!sync)) with - | true -> context##drawImage img 271. 188. - | false -> context##drawImage img 273. 188. - end - | 7 -> begin - match ((!sync)) with - | true -> context##drawImage img 271. 214. - | false -> context##drawImage img 273. 214. - end - | _ -> () - else () - -(*********************************************************) -(***************** Draw Dijsktra Squares *****************) -(*********************************************************) - -(* [draw_dijkstra_blue context tile_lst] draws the blue - * moveable squares when in 'MoveSelect'. The blue tiles - * in [tile_list] are made transparent and dispaly the - * moveable range of the player *) -let rec draw_dijsktra_blue (context : Html.canvasRenderingContext2D Js.t) tile_lst = - match tile_lst with - | [] -> () - | (x,y)::t -> - let img = Html.createImg document in - img##.src := js "Sprites/blue_test.png"; - context##.globalAlpha := 0.6; - context##drawImage img (float_of_int x *. 26.) (float_of_int y *. 26.); - draw_dijsktra_blue context t - -(* [draw_dijsktra_red context tile_list] draws the red - * squares around the blue moveable squares. *) -let rec draw_dijsktra_red (context : Html.canvasRenderingContext2D Js.t) tile_lst = - match tile_lst with - | [] -> () - | (x,y)::t -> - let img = Html.createImg document in - img##.src := js "Sprites/red.png"; - context##.globalAlpha := 0.6; - context##drawImage img (float_of_int x *. 26.) (float_of_int y *. 26.); - draw_dijsktra_red context t - -(* [draw_dijkstra context st] draws the blue and red squares - * when in the 'MoveSelect' stage. The tile lists of the blue and - * and red squares are stored inside of state's active_unit *) -let draw_dijsktra (context : Html.canvasRenderingContext2D Js.t) st = - match st.active_unit with - | None -> () - | Some chr -> - match chr.stage with - | MoveSelect -> - draw_dijsktra_blue context chr.movement; - draw_dijsktra_red context chr.attackable - | _ -> () - - -(*********************************************************) -(****************** Draw is player done ******************) -(*********************************************************) - -(* [draw_is_player_done context active_unit] draws a gray square - * under a player that has just finished its turn *) -let rec draw_is_player_done context lst = - match lst with - |[] -> () - |chr::t -> if chr.stage = Done then - let (x,y) = chr.location in - let img = Html.createImg document in - img##.src := js "Sprites/Gray.png"; - context##drawImage img (float_of_int x *. 26.) (float_of_int y *. 26.); - draw_is_player_done context t - else draw_is_player_done context t - -(*********************************************************) -(****************** Draw Attack Squares *****************) -(*********************************************************) - -(* [draw_attack_helper context lst] is draws the attack squares - * given a list [lst] of squares *) -let rec draw_attack_helper context lst = - match lst with - | [] -> () - | (x,y)::t -> - let img = Html.createImg document in - img##.src := js "Sprites/red.png"; - context##.globalAlpha := 0.6; - context##drawImage img (float_of_int x *. 26.) (float_of_int y *. 26.); - draw_attack_helper context t - -(* [draw_attack_sqaures context active_unit] draws the attack - * squares of the active_unit if the active unit is a player and - * if that player is currently in the 'AttackSelect' stage. *) -let draw_attack_squares (context : Html.canvasRenderingContext2D Js.t) active_unit= - match active_unit with - | Some chr -> - if chr.stage = AttackSelect then - let tile_lst = attack_range chr in - draw_attack_helper context tile_lst - else () - | _-> () - - -(*********************************************************) -(********************* Draw Side Bar *********************) -(*********************************************************) - -(* [find_drawpoint_name context name] finds the correct x - * value to display the string [name]. This allows [name] - * to be centered on the sidebar *) -let find_drawpoint_name context name = - let len = String.length name in - let x = 455. in (* Default val *) - if len < 4 then x - else if len = 4 then x -. 6. - else if len = 5 then x -. 8. - else if len = 6 then x -. 10. - else if len = 7 then x -. 14. - else if len = 8 then x -. 18. - else if len = 9 then x -. 22. - else if len = 10 then x -. 26. - else if len = 11 then x -. 30. - else if len = 12 then x -. 34. - else if len = 13 then x -. 38. - else if len = 14 then x -. 42. - else if len = 15 then x -. 46. - else if len = 16 then x -. 50. - else if len = 17 then x -. 54. - else 390. - -(* [draw_sidebar_back context] draws the background for - * the side bar *) -let draw_sidebar_back context = - for i = 15 to 20 do - for j = 0 to 14 do - let img = Html.createImg document in - img##.src := js "Sprites/sidebarback.png"; - context##drawImage img (float_of_int i *. 26.) (float_of_int j *. 26.) - done - done - -(* [draw_sidebar_title context state] draws the last characters - * name on the side bar *) -let draw_sidebar_title context state = - match state.last_character with - | Some chr -> - context##.strokeStyle := (js "white"); - context##.font := js "16px sans-serif"; - let x = find_drawpoint_name context (chr.name) in - context##.fillStyle := (js "white"); - context##fillText (js (chr.name)) x 26.; - | None -> () - -(* [draw_lyn_face context] draws lyn face on the sidebar if - * lyn was the last character *) -let draw_face context img_src = - let img = Html.createImg document in - img##.src := img_src; - context##drawImage img 416. 52. - -(* [draw_lyn_face context] draws lyn face on the sidebar if - * lyn was the last character *) -let draw_face_archer context img_src = - let img = Html.createImg document in - img##.src := img_src; - context##drawImage img 400. 52. - -(* [draw_lyn_face context] draws lyn face on the sidebar if - * lyn was the last character *) -let draw_face_mage context img_src = - let img = Html.createImg document in - img##.src := img_src; - context##drawImage img 440. 52. - -(* [draw_lyn_face context] draws lyn face on the sidebar if - * lyn was the last character *) -let draw_face_boss context img_src = - let img = Html.createImg document in - img##.src := img_src; - context##drawImage img 403. 52. - - -(* [draw_sidebar_face context state] draws the face of the - * last character *) -let draw_sidebar_face context state = - match state.last_character with - | Some chr -> begin - match chr.name with - | "Lyn" -> draw_face context (js "Sprites/lyn.png") - | "Hector" -> draw_face context (js "Sprites/Hector.png") - | "Erk" -> draw_face context (js "Sprites/Erk.png") - | "Mage" -> draw_face_mage context (js "Sprites/Mage.png") - | "Mage Boss" -> draw_face_boss context (js "Sprites/MageBoss.png") - | "Archer" -> draw_face_archer context (js "Sprites/Archer.png") - | "Melee" -> draw_face_archer context (js "Sprites/Melee.png") - | "Melee Boss" -> draw_face_boss context (js "Sprites/MeleeBoss.png") - | _ -> () - end - | None -> () - -(* [draw_sidebar_stats context state] draws all the stats for last character - * on the sidebar. The stats drawn are based on the fields of the character - * type. *) -let draw_sidebar_stats context state = - match state.last_character with - | Some chr -> - let hp = (string_of_int (fst chr.health)) ^ "/" ^ (string_of_int (snd chr.health)) in - let hp_x = find_drawpoint_name context ("health :" ^ hp) in - context##.strokeStyle := (js "white"); - context##.font := js "16px sans-serif"; - context##.fillStyle := (js "white"); - context##fillText (js "Stats") 447. 195.; - context##fillText (js ("level : " ^ string_of_int (chr.level))) 392. 215.; - context##fillText (js ("exp : " ^ string_of_int (chr.exp))) 392. 235.; - context##fillText (js ("health : " ^ hp)) hp_x 45.; - context##fillText (js ("str : " ^ string_of_int (chr.str))) 392. 255.; - context##fillText (js ("mag : " ^ string_of_int (chr.mag))) 392. 275.; - context##fillText (js ("def : " ^ string_of_int (chr.def))) 392. 295.; - context##fillText (js ("spd : " ^ string_of_int (chr.spd))) 392. 315.; - context##fillText (js ("res : " ^ string_of_int (chr.res))) 392. 335.; - context##fillText (js ("skl : " ^ string_of_int (chr.skl))) 392. 355.; - context##fillText (js ("lck : " ^ string_of_int (chr.lck))) 475. 215.; - context##fillText (js ("mov : " ^ string_of_int (chr.mov))) 475. 235.; - context##fillText (js ("hit : " ^ string_of_int (chr.hit))) 475. 255.; - context##fillText (js ("atk : " ^ string_of_int (chr.atk))) 475. 275.; - context##fillText (js ("crit : " ^ string_of_int (chr.crit))) 475. 295.; - context##fillText (js ("avd : " ^ string_of_int (chr.avoid))) 475. 315. - | None -> () - -(* [draw_sidebar context state] Draws the side bar which - * contains information of the last character, such as name, - * face, health, and other stats *) -let draw_sidebar context state = - draw_sidebar_back context; - draw_sidebar_title context state; - draw_sidebar_face context state; - draw_sidebar_stats context state - - -(*********************************************************) -(******************** Draw Attack Menu *******************) -(*********************************************************) - -(* [draw_attack_back context] draws the background for - * the attack menu *) -let draw_attack_back context = - let x = 229. in - let y = 304. in - let rec ys x y = - if x = 385. then () - else - let img = Html.createImg document in - img##.src := js "Sprites/databackground.png"; - context##drawImage img x y; - if y = 356. then ys (x+.26.) 304. else ys x (y+.26.) in - ys x y - -(* [draw_player_stats context player enemy] draws the stats of - * the [player] and [enemy] on the attack background *) -let draw_player_stats (context : Html.canvasRenderingContext2D Js.t) player enemy = - context##.font := js "13px sans-serif"; - let hp = (string_of_int (fst (player.health))) ^ "/" ^ (string_of_int (snd (player.health))) in - let hp_enm = (string_of_int (fst (enemy.health))) ^ "/" ^ (string_of_int (snd (enemy.health))) in - let player_damage = damage player enemy in - let enemy_damage = damage enemy player in - context##.fillStyle := (js "white"); - context##fillText (js (player.name)) 235. 320.; - context##fillText (js ("Hp: " ^ hp)) 235. 340.; - context##fillText (js ("Dam: " ^ (string_of_int player_damage))) 235. 360.; - context##fillText (js (enemy.name)) 320. 320.; - context##fillText (js ("Hp: " ^ hp_enm)) 320. 340.; - context##fillText (js ("Dam: " ^ (string_of_int enemy_damage))) 320. 360. - -(* [draw_attack_menu context state] draws the attack menu - * which shows the user the health of the current player and - * enemy as well as the damage each will do to each other. - * The attack 'menu' is only drawn when the active_unit - * is in 'AttackSelect' and when the confirm menu is also - * up *) -let draw_attack_menu (context : Html.canvasRenderingContext2D Js.t) state = - match state.active_unit with - | Some chr -> begin - match chr.stage, state.active_tile.c with - | AttackSelect, Some enemy -> - if state.current_menu <> confirm_menu then () - else - begin - draw_attack_back context; - context##.strokeStyle := (js "white"); - context##strokeRect 229. 304. 160. 82.; - draw_player_stats context chr enemy; - context##.font := js "12px sans-serif" - end - | _,_-> () - end - | None -> () - - -(*********************************************************) -(******************** Draw Inventory *********************) -(*********************************************************) - -(* [draw_inv_back context] draws the background of the inv *) -let draw_inv_back context = - let x = 0. in - let y = 390. in - let rec ys x y = - if x = 546. then () - else - let img = Html.createImg document in - img##.src := js "Sprites/sidebarback.png"; - context##drawImage img x y; - if y = 468. then ys (x+.26.) 390. else ys x (y+.26.) in - ys x y - -(* [draw_inventory context state] draws the inventory - * on the bottom of the screen with pictures/text associated - * with each item in the inventory *) -let draw_inventory context state = - draw_inv_back context - -(*********************************************************) -(********************** Draw Enemies *********************) -(*********************************************************) - -(* [draw_boss context enemy] draws the boss - * [enemy] on the gui. Also accounts for animation *) -let draw_boss context enemy = - match ((!sync)) with - | true -> - let img = Html.createImg document in - let (x,y) = enemy.location in - img##.src := js "Sprites/EnemySprites/Enemy_Boss1_Alert.png"; - context##drawImage_full img 18. 16. 26. 26. (float_of_int x *. 26.) (float_of_int y *. 26.) 25. 22. - | false -> - let img = Html.createImg document in - let (x,y) = enemy.location in - img##.src := js "Sprites/EnemySprites/Enemy_Boss1_Passive.png"; - context##drawImage_full img 16. 8. 26. 26. (float_of_int x *. 26. +. 3.) (float_of_int y *. 26. -. 3.) 25. 28. - -(* [draw_swordsman context enemy] draws the swordsman - * [enemy] on the gui. Also accounts for animation *) -let draw_swordsman context enemy = - match ((!sync)) with - | true -> - let img = Html.createImg document in - let (x,y) = enemy.location in - img##.src := js "Sprites/EnemySprites/Enemy_Swordsman_N.png"; - context##drawImage_full img 20. 1. 20. 40. (float_of_int x *. 26. +. 6.) (float_of_int y *. 26. -. 10.) 25. 40. - | false -> - let img = Html.createImg document in - let (x,y) = enemy.location in - img##.src := js "Sprites/EnemySprites/Enemy_Swordsman_S.png"; - context##drawImage_full img 17. 21. 20. 20. (float_of_int x *. 26. +. 6.) (float_of_int y *. 26.) 25. 28. - - -(* [draw_mage context enemy] draws the mage sprite - * [enemy] on the [context] *) -let draw_mage context enemy = - match ((!sync)) with - | true -> - let img = Html.createImg document in - let (x,y) = enemy.location in - img##.src := js "Sprites/EnemySprites/Enemy_Mage.png"; - context##drawImage_full img 21. 10. 26. 36. (float_of_int x *. 26. +. 6.) (float_of_int y *. 26.) 25. 28. - | false -> - let img = Html.createImg document in - let (x,y) = enemy.location in - img##.src := js "Sprites/EnemySprites/Enemy_Mage2.png"; - context##drawImage_full img 21. 11. 26. 36. (float_of_int x *. 26. +. 6.) (float_of_int y *. 26.) 25. 26. - -(* [draw_mage_boss context enemy] draws the mage boss sprite - * [enemy] on the [context] *) -let draw_mage_boss context enemy = - match ((!sync)) with - | true -> - let img = Html.createImg document in - let (x,y) = enemy.location in - img##.src := js "Sprites/EnemySprites/Mage_Boss.png"; - context##drawImage_full img 7. 8. 32. 36. (float_of_int x *. 26.) (float_of_int y *. 26.) 25. 28. - | false -> - let img = Html.createImg document in - let (x,y) = enemy.location in - img##.src := js "Sprites/EnemySprites/Mage_Boss2.png"; - context##drawImage_full img 15. 8. 32. 36. (float_of_int x *. 26.) (float_of_int y *. 26.) 25. 26. - -(* [draw_enemies_helper context enemy_lst] takes a - * list of enemies [enemy_lst] and draws the proper - * sprite corresponding to the name of all the enemies - * in the list *) -let rec draw_enemies_helper context enemy_lst = - match enemy_lst with - | [] -> () - | enemy::t -> - match enemy.name with - | "Archer" -> - draw_archer context enemy; - draw_enemies_helper context t - | "Melee Boss" -> - draw_boss context enemy; - draw_enemies_helper context t - | "Melee" -> - draw_swordsman context enemy; - draw_enemies_helper context t - | "Mage" -> - draw_mage context enemy; - draw_enemies_helper context t - | "Mage Boss" -> - draw_mage_boss context enemy; - draw_enemies_helper context t - | _ -> () - -(* [draw_enemies context state] draws the enemy sprites on - * the map. *) -let draw_enemies context state = - draw_enemies_helper context state.enemies - -(*********************************************************) -(****************** Draw win/loose screen ****************) -(*********************************************************) - -(* [draw_win_screen context] draws the win screen if - * the player has won *) -let draw_win_screen (context : Html.canvasRenderingContext2D Js.t) = - context##.fillStyle := (js "black"); - context##fillRect 0. 0. canvas_width canvas_height; - context##.strokeStyle := (js "white"); - context##.fillStyle := (js "white"); - context##.font := js "60px Times New Roman"; - context##fillText (js "YOU WIN!") 130. 120.; - context##fillText (js "Thanks for Playing!") 40. 200. - -(* [draw_lose_screen context] draws the lose screen if - * the player has won *) -let draw_lose_screen (context : Html.canvasRenderingContext2D Js.t) = - context##.fillStyle := (js "black"); - context##fillRect 0. 0. canvas_width canvas_height; - context##.strokeStyle := (js "white"); - context##.fillStyle := (js "white"); - context##.font := js "60px Times New Roman"; - context##fillText (js "Sorry, you lost...") 90. 100.; - context##fillText (js "Thanks for Playing!") 40. 170.; - context##.font := js "30px Times New Roman"; - context##fillText (js "To play again just refresh the page!") 70. 230. - -(*********************************************************) -(***************** Draw transition screen ****************) -(*********************************************************) - -(* [draw_transition_screen context state] draws the transition - * screen on the [context]. The transitions screen occurs - * between rounds when switching between Map1 and Map2. It - * also features a timer that counts down from 10 *) -let draw_transition_screen (context : Html.canvasRenderingContext2D Js.t) state = - if !transition < 0 then - state.round <- false - else - let timer = !transition / 100 in - context##.fillStyle := (js "black"); - context##fillRect 0. 0. canvas_width canvas_height; - context##.strokeStyle := (js "white"); - context##.fillStyle := (js "white"); - context##.font := js "50px Times New Roman"; - context##fillText (js "You Beat Round 1!") 90. 120.; - context##fillText (js "Round two is starting in:") 22. 200.; - context##fillText (js (string_of_int timer)) 260. 270. - - -(*********************************************************) -(****************** Draw Welcome Screen ******************) -(*********************************************************) - -(* [draw_welcome_screen context] draws the welcome screen - * that will be displayed at the beginning of the game when - * the html window is first loaded. This window will display - * information about the game and directions *) -let draw_welcome_screen context = - context##.fillStyle := (js "black"); - context##fillRect 0. 0. canvas_width canvas_height; - context##.fillStyle := (js "white"); - context##.strokeStyle := (js "white"); - context##.font := js "50px Times New Roman"; - context##.fillStyle := (js "Solid"); - context##fillText (js "WELCOME TO") 90. 50.; - let img = Html.createImg document in - img##.src := js "Sprites/FireEmblem.png"; - context##drawImage img 80. 70.; - context##.font := js "20px Times New Roman"; - context##fillText (js "How To Play:") 10. 140.; - context##.font := js "15px Times New Roman"; - context##fillText (js "The goal of the game is to move your players (in blue) to the enemies using the") 30. 160.; - context##fillText (js "'Z' key to select the player. When a player is selected, blue and red tiles will appear") 30. 175.; - context##fillText (js "on the screen. Blue tiles are moveable tiles. After you moved you can either attack") 30. 190.; - context##fillText (js "which will show more red tiles that represent attack range, use an item, visit a ") 30. 205.; - context##fillText (js "a village, open a chest, trade with a another player, or wait which will end that ") 30. 220.; - context##fillText (js "players turn. To deselect press 'X'. 'A' teleports the cursor to the current active") 30. 235.; - context##fillText (js "player. Once all players finish their turns, click on an empty square and click 'END' ") 30. 250.; - context##fillText (js "to end the players turn. Then the AI will attack, which will end the AI turn") 30. 265.; - context##.font := js "20px Times New Roman"; - context##fillText (js "Controls:") 10. 285.; - context##.font := js "15px Times New Roman"; - let img = Html.createImg document in - img##.src := js "Sprites/ArrowKeys.png"; - context##drawImage img 10. 280.; - let img = Html.createImg document in - context##.font := js "15px Times New Roman"; - context##fillText (js "The Arrow Keys move the") 95. 310.; - context##fillText (js "cursor around the map") 95. 325.; - context##fillText (js "and menu") 95. 340.; - img##.src := js "Sprites/Z.png"; - context##drawImage img 40. 340.; - context##fillText (js "The Z Key selects units") 95. 360.; - context##fillText (js "and options on the menus") 95. 375.; - let img = Html.createImg document in - img##.src := js "Sprites/X.png"; - context##drawImage img 270. 300.; - context##fillText (js "The X Keys deselects units") 330. 310.; - context##fillText (js "and options on the menus") 330. 325.; - let img = Html.createImg document in - img##.src := js "Sprites/A.png"; - context##drawImage img 270. 340.; - context##fillText (js "The A Keys moves the cursor") 330. 350.; - context##fillText (js "to the player whose turn it") 330. 365.; - context##fillText (js "currently is") 330. 380.; - context##fillText (js "Press Z, X, A, or arrow keys to play game!") 135. 125. - - -(*********************************************************) -(****************** Draw State Functions *****************) -(*********************************************************) - -(* [draw_state] draws the the current [state] on the [context]. - * Also has a side affect of updating the global variable clock, - * transition, and transition start *) -let draw_state (context: Html.canvasRenderingContext2D Js.t) state = - context##clearRect 0. 0. canvas_width canvas_height; - match state.welcome, state.round, state.won, state.lose with - | true, _, _, _ -> - draw_welcome_screen context; - | false, true, _, _ -> - transition_start:= true; - draw_transition_screen context state; - clock (); - transition_start:= false; - | false, false, true, false-> - draw_win_screen context; - | false, false, false, true -> - draw_lose_screen context; - | _, _, _, _-> - draw_map context state; - draw_dijsktra context state; - draw_attack_squares context state.active_unit; - context##.globalAlpha := 1.; - draw_is_player_done context state.player; - draw_player context state.player; - draw_enemies context state; - draw_cursor context state.active_tile; - draw_healthbar context state.player; - draw_healthbar context state.enemies; - menu_manager context state; - draw_menu_arrow context state; - draw_sidebar context state; - draw_attack_menu context state; - (* draw_inventory context state; *) - clock (); +open Types +open State +open Interactions +open Js_of_ocaml + +let canvas_width = 546. + +let canvas_height = 390. + +module Html = Dom_html + +let js = Js.string + +let document = Html.document + +let clock = ref 1 + +let sync = ref true + +let transition = ref 1000 + +let transition_start = ref false + +(*********************************************************) +(***************** Map Drawing Functions *****************) +(*********************************************************) + +(* [tile_to_img_mapping obj] returns the image source + * as a Js.string directiory location of the + * associated tile *) +let tile_to_img_mapping (tile : tile) = + match tile.tile_type with + | Grass -> js "Sprites/grass.png" + | Tree -> js "Sprites/tree.png" + | Crack -> js "Sprites/Crack.png" + | Bridge -> js "Sprites/Bridge.png" + | Bush -> js "Sprites/Bush.png" + | Darkbush -> js "Sprites/Darkbush.png" + | Water1 -> js "Sprites/Water1.png" + | Water2 -> js "Sprites/Water2.png" + | Water3 -> js "Sprites/Water3.png" + | Water4 -> js "Sprites/Water4.png" + | Water5 -> js "Sprites/Water5.png" + | Water6 -> js "Sprites/Water6.png" + | Water7 -> js "Sprites/Water7.png" + | Water8 -> js "Sprites/Water8.png" + | Water9 -> js "Sprites/Water9.png" + | Water10 -> js "Sprites/Water10.png" + | Wall1 -> js "Sprites/Wall1.png" + | Wall2 -> js "Sprites/Wall2.png" + | Wall3 -> js "Sprites/Wall3.png" + | Wall4 -> js "Sprites/Wall4.png" + | Wall5 -> js "Sprites/Wall5.png" + | Wall6 -> js "Sprites/Wall6.png" + | Castle1 -> js "Sprites/Map2/castle1.png" + | Castle2 -> js "Sprites/Map2/castle2.png" + | Castle3 -> js "Sprites/Map2/castle3.png" + | Castle4 -> js "Sprites/Map2/castle4.png" + | Castle5 -> js "Sprites/Map2/castle5.png" + | Castle6 -> js "Sprites/Map2/castle6.png" + | Castle7 -> js "Sprites/Map2/castle7.png" + | Castle8 -> js "Sprites/Map2/castle8.png" + | Castle9 -> js "Sprites/Map2/castle9.png" + | House1 -> js "Sprites/Map2/house1.png" + | House2 -> js "Sprites/Map2/house2.png" + | House3 -> js "Sprites/Map2/house3.png" + | House4 -> js "Sprites/Map2/house4.png" + | House5 -> js "Sprites/Map2/house5.png" + | House6 -> js "Sprites/Map2/house6.png" + | Water11 -> js "Sprites/Map2/Water11.png" + | Water12 -> js "Sprites/Map2/Water12.png" + | Chesttile -> js "Sprites/Map2/chest.png" + +(* [draw_tiles map] draws each of the tiles of the state's current + * active map *) +let draw_map (context : Html.canvasRenderingContext2D Js.t) state = + context##.fillStyle := js "black"; + context##fillRect 0. 0. canvas_width canvas_height; + let draw_tiles (grid : tile array array) = + for i = 0 to 14 do + for j = 0 to 14 do + let tile = grid.(i).(j) in + let x = fst tile.coordinate in + let y = snd tile.coordinate in + let img_src = tile_to_img_mapping tile in + let img = Html.createImg document in + img##.src := img_src; + context##drawImage img (26. *. float_of_int x) (26. *. float_of_int y) + done + done + in + draw_tiles state.act_map.grid + +(*********************************************************) +(**************** Cursor Drawing Functions ***************) +(*********************************************************) + +(* [clock ()] updates the clock at every loop of the game. + * Every 15 "time" units, sync is negated which represents the + * static movement of the cursor and players *) +let clock () = + clock := if !clock < 35 then !clock + 1 else 1; + transition := + if !transition >= 0 && !transition_start = true then !transition - 2 + else !transition; + let x1 = !clock mod 35 in + (* bounds *) + match x1 with 0 -> sync := not !sync | _ -> () + +(* [draw_cursor context tile] draws the cursor (big) on the + * canvas given the integer location defined in tile *) +let draw_cursor_big (context : Html.canvasRenderingContext2D Js.t) tile = + let x, y = tile.coordinate in + let img = Html.createImg document in + img##.src := js "Sprites/CursorLarge.png"; + context##drawImage img (26. *. float_of_int x) (26. *. float_of_int y) + +(* [draw_cursor context tile] draws the cursor (small) on the + * canvas given the integer location defined in tile *) +let draw_cursor_small (context : Html.canvasRenderingContext2D Js.t) tile = + let x, y = tile.coordinate in + let img = Html.createImg document in + img##.src := js "Sprites/CursorSmall.png"; + context##drawImage img (26. *. float_of_int x) (26. *. float_of_int y) + +(* [draw_cursor context tile] chooses to draw a big cursor or small + * cursor based on the current synchornization reference (sync) and + * then draws that cursor on the coordinate defined by tile *) +let draw_cursor (context : Html.canvasRenderingContext2D Js.t) tile = + match !sync with + | true -> draw_cursor_small context tile + | false -> draw_cursor_big context tile + +(*********************************************************) +(**************** Sprite Drawing Functions ***************) +(*********************************************************) + +(* [testf context] is a debugging function *) +let testf context = + let img = Html.createImg document in + img##.src := js "Sprites/databackground.png"; + context##drawImage img 0. 0. + +(* [draw_sprite] draws the sprite located at (sx,sy) with + * sw width and sh height inside the spritesheet and + * projects it onto the canvas at location (x,y) *) +let draw_sprite img_src context (sx, sy) (sw, sh) (x, y) = + let img = Html.createImg document in + img##.src := img_src; + context##drawImage_full img sx sy sw sh x y 25. 25. + +(* [draw_sprite] draws the sprite located at (sx,sy) with + * sw width and sh height inside the spritesheet and + * projects it onto the canvas at location (x,y) *) +let draw_sprite_hector img_src context (sx, sy) (sw, sh) (x, y) = + let img = Html.createImg document in + img##.src := img_src; + context##drawImage_full img sx sy sw sh x y 30. 25. + +(* [draw_lyn context character] draws the proper sprite configuration + * for the character lyn based on the character's direction and stage + * fields. Also accounts for animation by using the sync gloal + * reference which allows switching between sprites *) +let draw_lyn (context : Html.canvasRenderingContext2D Js.t) character = + let img = js "Sprites/lynsheet.png" in + match character.direction with + | South -> ( + match character.stage with + | Ready | MoveDone | AttackSelect | TradeSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (417., 400.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (457., 399.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | MoveSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (463., 419.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 6., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (420., 420.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 6., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | Done when character.is_attacking = true -> ( + match !sync with + | true -> + let sprite_coordinate = (463., 419.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 6., (26. *. float_of_int y) +. 6.) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + moved_forward := true + | false -> + let sprite_coordinate = (420., 420.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 6., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + if !moved_forward = true then ( + moved_forward := false; + attacking := false; + character.is_attacking <- false) + else ()) + | Done when character.is_attacking = false -> ( + match !sync with + | true -> + let sprite_coordinate = (417., 400.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (457., 399.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | Done -> ()) + | East -> ( + match character.stage with + | Ready | MoveDone | AttackSelect | TradeSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (417., 400.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (457., 399.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | MoveSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (418., 442.) in + let sprite_wxl = (16., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 0., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (441., 442.) in + let sprite_wxl = (16., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 0., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | Done when character.is_attacking = true -> ( + match !sync with + | true -> + let sprite_coordinate = (418., 442.) in + let sprite_wxl = (16., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 6., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + moved_forward := true + | false -> + let sprite_coordinate = (441., 442.) in + let sprite_wxl = (16., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 0., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + if !moved_forward = true then ( + moved_forward := false; + attacking := false; + character.is_attacking <- false) + else ()) + | Done when character.is_attacking = false -> ( + match !sync with + | true -> + let sprite_coordinate = (417., 400.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (457., 399.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | Done -> ()) + | North -> ( + match character.stage with + | Ready | MoveDone | AttackSelect | TradeSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (417., 400.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (457., 399.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | MoveSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (419., 461.) in + let sprite_wxl = (16., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 0., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (442., 461.) in + let sprite_wxl = (16., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 0., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | Done when character.is_attacking = true -> ( + match !sync with + | false -> + let sprite_coordinate = (419., 461.) in + let sprite_wxl = (16., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 0., (26. *. float_of_int y) -. 6.) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + moved_forward := true + | true -> + let sprite_coordinate = (442., 461.) in + let sprite_wxl = (16., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 0., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + if !moved_forward = true then ( + moved_forward := false; + attacking := false; + character.is_attacking <- false) + else ()) + | Done when character.is_attacking = false -> ( + match !sync with + | true -> + let sprite_coordinate = (417., 400.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (457., 399.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | Done -> ()) + | West -> ( + match character.stage with + | Ready | MoveDone | AttackSelect | TradeSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (417., 400.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (457., 399.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | MoveSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (419., 461.) in + let sprite_wxl = (16., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 0., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (442., 461.) in + let sprite_wxl = (16., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 0., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | Done when character.is_attacking = true -> ( + match !sync with + | false -> + let sprite_coordinate = (419., 461.) in + let sprite_wxl = (16., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 0., (26. *. float_of_int y) -. 6.) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + moved_forward := true + | true -> + let sprite_coordinate = (442., 461.) in + let sprite_wxl = (16., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 6., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + if !moved_forward = true then ( + moved_forward := false; + attacking := false; + character.is_attacking <- false) + else ()) + | Done when character.is_attacking = false -> ( + match !sync with + | true -> + let sprite_coordinate = (417., 400.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (457., 399.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | Done -> ()) + +(* [draw_hector context character] draws the proper sprite configuration + * for the character lyn based on the character's direction and stage + * fields. Also accounts for animation by using the sync gloal + * reference which allows switching between sprites *) +let draw_hector (context : Html.canvasRenderingContext2D Js.t) character = + let img = js "Sprites/PlayerSprites.png" in + match character.direction with + | South -> ( + match character.stage with + | Ready | MoveDone | AttackSelect | TradeSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (224., 280.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate + | false -> + let sprite_coordinate = (224., 312.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate) + | MoveSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (258., 345.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate + | false -> + let sprite_coordinate = (258., 281.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate) + | Done when character.is_attacking = true -> ( + match !sync with + | true -> + let sprite_coordinate = (224., 280.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., (26. *. float_of_int y) +. 6.) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + moved_forward := true + | false -> + let sprite_coordinate = (329., 339.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + if !moved_forward = true then ( + moved_forward := false; + attacking := false; + character.is_attacking <- false) + else ()) + | Done when character.is_attacking = false -> ( + match !sync with + | true -> + let sprite_coordinate = (224., 280.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate + | false -> + let sprite_coordinate = (224., 312.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate) + | Done -> ()) + | East -> ( + match character.stage with + | Ready | MoveDone | AttackSelect | TradeSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (224., 280.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate + | false -> + let sprite_coordinate = (224., 312.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate) + | MoveSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (258., 345.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate + | false -> + let sprite_coordinate = (258., 281.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate) + | Done when character.is_attacking = true -> ( + match !sync with + | true -> + let sprite_coordinate = (224., 280.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 3., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + moved_forward := true + | false -> + let sprite_coordinate = (329., 339.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + if !moved_forward = true then ( + moved_forward := false; + attacking := false; + character.is_attacking <- false) + else ()) + | Done when character.is_attacking = false -> ( + match !sync with + | true -> + let sprite_coordinate = (224., 280.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate + | false -> + let sprite_coordinate = (224., 312.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate) + | Done -> ()) + | North -> ( + match character.stage with + | Ready | MoveDone | AttackSelect | TradeSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (224., 280.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate + | false -> + let sprite_coordinate = (224., 312.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate) + | MoveSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (258., 345.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate + | false -> + let sprite_coordinate = (258., 281.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate) + | Done when character.is_attacking = true -> ( + match !sync with + | true -> + let sprite_coordinate = (224., 280.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., (26. *. float_of_int y) -. 6.) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + moved_forward := true + | false -> + let sprite_coordinate = (329., 339.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + if !moved_forward = true then ( + moved_forward := false; + attacking := false; + character.is_attacking <- false) + else ()) + | Done when character.is_attacking = false -> ( + match !sync with + | true -> + let sprite_coordinate = (224., 280.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate + | false -> + let sprite_coordinate = (224., 312.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate) + | Done -> ()) + | West -> ( + match character.stage with + | Ready | MoveDone | AttackSelect | TradeSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (224., 280.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate + | false -> + let sprite_coordinate = (224., 312.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate) + | MoveSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (258., 345.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate + | false -> + let sprite_coordinate = (258., 281.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate) + | Done when character.is_attacking = true -> ( + match !sync with + | true -> + let sprite_coordinate = (224., 280.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 9., (26. *. float_of_int y) -. 6.) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + moved_forward := true + | false -> + let sprite_coordinate = (329., 339.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + if !moved_forward = true then ( + moved_forward := false; + attacking := false; + character.is_attacking <- false) + else ()) + | Done when character.is_attacking = false -> ( + match !sync with + | true -> + let sprite_coordinate = (224., 280.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate + | false -> + let sprite_coordinate = (224., 312.) in + let sprite_wxl = (22., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 3., 26. *. float_of_int y) + in + draw_sprite_hector img context sprite_coordinate sprite_wxl + coordinate) + | Done -> ()) + +(* [draw_erk context character] draws the proper sprite configuration + * for the character lyn based on the character's direction and stage + * fields. Also accounts for animation by using the sync gloal + * reference which allows switching between sprites *) +let draw_erk (context : Html.canvasRenderingContext2D Js.t) character = + let img = js "Sprites/PlayerSprites.png" in + match character.direction with + | South -> ( + match character.stage with + | Ready | MoveDone | AttackSelect | TradeSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (197., 1907.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (198., 1939.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | MoveSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (262., 1874.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 6., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (263., 1938.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 6., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | Done when character.is_attacking = true -> ( + match !sync with + | true -> + let sprite_coordinate = (325., 1908.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 6., (26. *. float_of_int y) +. 6.) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + moved_forward := true + | false -> + let sprite_coordinate = (198., 1939.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 6., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + if !moved_forward = true then ( + moved_forward := false; + attacking := false; + character.is_attacking <- false) + else ()) + | Done when character.is_attacking = false -> ( + match !sync with + | true -> + let sprite_coordinate = (197., 1907.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (198., 1939.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | Done -> ()) + | East -> ( + match character.stage with + | Ready | MoveDone | AttackSelect | TradeSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (197., 1907.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (198., 1939.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | MoveSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (262., 1874.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 6., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (263., 1938.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 6., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | Done when character.is_attacking = true -> ( + match !sync with + | true -> + let sprite_coordinate = (325., 1908.) in + let sprite_wxl = (16., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 6., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + moved_forward := true + | false -> + let sprite_coordinate = (198., 1939.) in + let sprite_wxl = (16., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 0., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + if !moved_forward = true then ( + moved_forward := false; + attacking := false; + character.is_attacking <- false) + else ()) + | Done when character.is_attacking = false -> ( + match !sync with + | true -> + let sprite_coordinate = (197., 1907.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (198., 1939.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | Done -> ()) + | North -> ( + match character.stage with + | Ready | MoveDone | AttackSelect | TradeSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (197., 1907.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (198., 1939.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | MoveSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (262., 1874.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 6., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (263., 1938.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 6., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | Done when character.is_attacking = true -> ( + match !sync with + | true -> + let sprite_coordinate = (325., 1908.) in + let sprite_wxl = (16., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 0., (26. *. float_of_int y) -. 6.) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + moved_forward := true + | false -> + let sprite_coordinate = (198., 1939.) in + let sprite_wxl = (16., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 0., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + if !moved_forward = true then ( + moved_forward := false; + attacking := false; + character.is_attacking <- false) + else ()) + | Done when character.is_attacking = false -> ( + match !sync with + | true -> + let sprite_coordinate = (197., 1907.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (198., 1939.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | Done -> ()) + | West -> ( + match character.stage with + | Ready | MoveDone | AttackSelect | TradeSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (197., 1907.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (198., 1939.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | MoveSelect -> ( + match !sync with + | true -> + let sprite_coordinate = (262., 1874.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 6., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (263., 1938.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 6., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | Done when character.is_attacking = true -> ( + match !sync with + | true -> + let sprite_coordinate = (325., 1908.) in + let sprite_wxl = (16., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) -. 6., (26. *. float_of_int y) -. 6.) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + moved_forward := true + | false -> + let sprite_coordinate = (198., 1939.) in + let sprite_wxl = (16., 16.) in + let x, y = character.location in + let coordinate = + ((26. *. float_of_int x) +. 0., 26. *. float_of_int y) + in + draw_sprite img context sprite_coordinate sprite_wxl coordinate; + if !moved_forward = true then ( + moved_forward := false; + attacking := false; + character.is_attacking <- false) + else ()) + | Done when character.is_attacking = false -> ( + match !sync with + | true -> + let sprite_coordinate = (197., 1907.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate + | false -> + let sprite_coordinate = (198., 1939.) in + let sprite_wxl = (15., 16.) in + let x, y = character.location in + let coordinate = (26. *. float_of_int x, 26. *. float_of_int y) in + draw_sprite img context sprite_coordinate sprite_wxl coordinate) + | Done -> ()) + +(* [draw_archer context enemy] draws the archer + * [eenmy] on the [context] *) +let draw_archer context enemy = + match !sync with + | true -> + let img = Html.createImg document in + let x, y = enemy.location in + img##.src := js "Sprites/EnemySprites/Enemy_Archer_NE.png"; + context##drawImage_full img 20. 11. 26. 26. + ((float_of_int x *. 26.) +. 6.) + (float_of_int y *. 26.) + 25. 22. + | false -> + let img = Html.createImg document in + let x, y = enemy.location in + img##.src := js "Sprites/EnemySprites/Enemy_Archer_E.png"; + context##drawImage_full img 16. 18. 26. 26. + ((float_of_int x *. 26.) +. 6.) + (float_of_int y *. 26.) + 25. 28. + +(* [draw_player context character_list] draws all the characters inside + * the character_list. [character_list] is a general list of characters + * which may be players, allies, or enemies *) +let rec draw_player (context : Html.canvasRenderingContext2D Js.t) + character_list = + match character_list with + | [] -> () + | h :: t -> ( + match h.name with + | "Lyn" -> + draw_lyn context h; + draw_player context t + | "Erk" -> + draw_erk context h; + draw_player context t + | "Hector" -> + draw_hector context h; + draw_player context t + | "Archer" -> + draw_archer context h; + draw_player context t + | _ -> ()) + +(*********************************************************) +(***************** Menu Drawing Functions ****************) +(*********************************************************) + +(* [draw_back_1 context] draws the background for a + * menu of size 1 *) +let draw_back_1 (context : Html.canvasRenderingContext2D Js.t) = + let x = 281. in + let y = 26. in + let rec ys x y = + if x = 385. then () + else + let img = Html.createImg document in + img##.src := js "Sprites/databackground.png"; + context##drawImage img x y; + if y = 26. then ys (x +. 26.) 26. else ys x (y +. 26.) + in + ys x y + +(* [draw_text_1 context str_arr] draws the outer white + * rectangle around the menu and text in str_arr + * on a menu of size 1 *) +let draw_text_1 (context : Html.canvasRenderingContext2D Js.t) str_arr = + context##.strokeStyle := js "white"; + context##.font := js "16px sans-serif"; + context##strokeRect 280. 26. 110. 30.; + let position = ref 50. in + for i = 0 to Array.length str_arr - 1 do + context##.fillStyle := js "white"; + context##fillText (js str_arr.(i)) 300. !position; + position := !position +. 25. + done + +(* [draw_back_2 context] draws the background for a + * menu of size 2 *) +let draw_back_2 (context : Html.canvasRenderingContext2D Js.t) = + let x = 281. in + let y = 26. in + let rec ys x y = + if x = 385. then () + else + let img = Html.createImg document in + img##.src := js "Sprites/databackground.png"; + context##drawImage img x y; + if y = 52. then ys (x +. 26.) 26. else ys x (y +. 26.) + in + ys x y + +(* [draw_text_2 context str_arr] draws the outer white + * rectangle around the menu and text in str_arr + * on a menu of size 2 *) +let draw_text_2 (context : Html.canvasRenderingContext2D Js.t) str_arr = + context##.strokeStyle := js "white"; + context##.font := js "16px sans-serif"; + context##strokeRect 280. 26. 110. 56.; + let position = ref 50. in + for i = 0 to Array.length str_arr - 1 do + context##.fillStyle := js "white"; + context##fillText (js str_arr.(i)) 300. !position; + position := !position +. 25. + done + +(* [draw_back_4 context] draws the background for a + * menu of size 4 *) +let draw_back_4 (context : Html.canvasRenderingContext2D Js.t) = + let x = 281. in + let y = 26. in + let rec ys x y = + if x = 385. then () + else + let img = Html.createImg document in + img##.src := js "Sprites/databackground.png"; + context##drawImage img x y; + if y = 104. then ys (x +. 26.) 26. else ys x (y +. 26.) + in + ys x y + +(* [draw_text_4 context str_arr] draws the outer white + * rectangle around the menu and text in str_arr + * on a menu of size 4 *) +let draw_text_4 (context : Html.canvasRenderingContext2D Js.t) str_arr = + context##.strokeStyle := js "white"; + context##.font := js "16px sans-serif"; + context##strokeRect 280. 26. 110. 108.; + let position = ref 50. in + for i = 0 to Array.length str_arr - 1 do + context##.fillStyle := js "white"; + context##fillText (js str_arr.(i)) 300. !position; + position := !position +. 25. + done + +(* [draw_back_5 context] draws the background for a + * menu of size 5 *) +let draw_back_5 (context : Html.canvasRenderingContext2D Js.t) = + let x = 281. in + let y = 26. in + let rec ys x y = + if x = 385. then () + else + let img = Html.createImg document in + img##.src := js "Sprites/databackground.png"; + context##drawImage img x y; + if y = 130. then ys (x +. 26.) 26. else ys x (y +. 26.) + in + ys x y + +(* [draw_text_5 context str_arr] draws the outer white + * rectangle around the menu and text in str_arr + * on a menu of size 5 *) +let draw_text_5 (context : Html.canvasRenderingContext2D Js.t) str_arr = + context##.strokeStyle := js "white"; + context##.font := js "16px sans-serif"; + context##strokeRect 280. 26. 110. 134.; + let position = ref 50. in + for i = 0 to Array.length str_arr - 1 do + context##.fillStyle := js "white"; + context##fillText (js str_arr.(i)) 300. !position; + position := !position +. 25. + done + +(* [draw_back_6 context] draws the background for a + * menu of size 6 *) +let draw_back_6 context = + let x = 281. in + let y = 26. in + let rec ys x y = + if x = 385. then () + else + let img = Html.createImg document in + img##.src := js "Sprites/databackground.png"; + context##drawImage img x y; + if y = 156. then ys (x +. 26.) 26. else ys x (y +. 26.) + in + ys x y + +(* [draw_text_6 context str_arr] draws the outer white + * rectangle around the menu and text in str_arr + * on a menu of size 6 *) +let draw_text_6 context str_arr = + context##.strokeStyle := js "white"; + context##.font := js "16px sans-serif"; + context##strokeRect 280. 26. 110. 161.; + let position = ref 50. in + for i = 0 to Array.length str_arr - 1 do + context##.fillStyle := js "white"; + context##fillText (js str_arr.(i)) 300. !position; + position := !position +. 25. + done + +(* [draw_back_7 context] draws the background for a + * menu of size 7 *) +let draw_back_7 context = + let x = 281. in + let y = 26. in + let rec ys x y = + if x = 385. then () + else + let img = Html.createImg document in + img##.src := js "Sprites/databackground.png"; + context##drawImage img x y; + if y = 182. then ys (x +. 26.) 26. else ys x (y +. 26.) + in + ys x y + +(* [draw_text_7 context str_arr] draws the outer white + * rectangle around the menu and text in str_arr + * on a menu of size 7 *) +let draw_text_7 context str_arr = + context##.strokeStyle := js "white"; + context##.font := js "16px sans-serif"; + context##strokeRect 280. 26. 110. 186.; + let position = ref 50. in + for i = 0 to Array.length str_arr - 1 do + context##.fillStyle := js "white"; + context##fillText (js str_arr.(i)) 300. !position; + position := !position +. 25. + done + +(* [draw_1_menu context menu] draws the [menu] + * of size 1 *) +let draw_1_menu context menu = + draw_back_1 context; + draw_text_1 context menu.options + +(* [draw_2_menu context menu] draws the [menu] + * of size 2 *) +let draw_2_menu context menu = + draw_back_2 context; + draw_text_2 context menu.options + +(* [draw_4_menu context menu] draws the [menu] + * of size 4 *) +let draw_4_menu context menu = + draw_back_4 context; + draw_text_4 context menu.options + +(* [draw_5_menu context menu] draws the [menu] + * of size 5 *) +let draw_5_menu context menu = + draw_back_5 context; + draw_text_5 context menu.options + +(* [draw_6_menu context menu] draws the [menu] + * of size 6 *) +let draw_6_menu context menu = + draw_back_6 context; + draw_text_6 context menu.options + +(* [draw_7_menu context menu] draws the [menu] + * of size 7 *) +let draw_7_menu context menu = + draw_back_7 context; + draw_text_7 context menu.options + +(* [menu_manager context state] draws a menu + * if is active, otherwise does nothing *) +let menu_manager (context : Html.canvasRenderingContext2D Js.t) state = + if state.menu_active then + match state.current_menu.size with + | 1 -> draw_1_menu context state.current_menu + | 2 -> draw_2_menu context state.current_menu + | 4 -> draw_4_menu context state.current_menu + | 5 -> draw_5_menu context state.current_menu + | 6 -> draw_6_menu context state.current_menu + | 7 -> draw_7_menu context state.current_menu + | _ -> () + else () + +(*********************************************************) +(******************** Draw Health Bar ********************) +(*********************************************************) + +(* [draw_health context health max_health x y] is the health bar + * that apperas under the player. Health bar is calculated using + * the percentage of health remaining out of max_health. x and y + * are coordinates that health bar will be drawn at *) +let draw_health context health max_health x y = + let hp = float_of_int health in + let max_hp = float_of_int max_health in + if hp = 0. then () + else if hp <= max_hp *. 0.125 then ( + let img = Html.createImg document in + img##.src := js "Sprites/RedHealth.png"; + for i = x + 1 to x + 3 do + context##drawImage img (float_of_int i) (float_of_int y +. 1.) + done) + else if hp <= max_hp *. 0.25 then ( + let img = Html.createImg document in + img##.src := js "Sprites/RedHealth.png"; + for i = x + 1 to x + 6 do + context##drawImage img (float_of_int i) (float_of_int y +. 1.) + done) + else if hp <= max_hp *. 0.375 then ( + let img = Html.createImg document in + img##.src := js "Sprites/YellowHealth.png"; + for i = x + 1 to x + 9 do + context##drawImage img (float_of_int i) (float_of_int y +. 1.) + done) + else if hp <= max_hp *. 0.5 then ( + let img = Html.createImg document in + img##.src := js "Sprites/YellowHealth.png"; + for i = x + 1 to x + 12 do + context##drawImage img (float_of_int i) (float_of_int y +. 1.) + done) + else if hp <= max_hp *. 0.625 then ( + let img = Html.createImg document in + img##.src := js "Sprites/GreenHealth.png"; + for i = x + 1 to x + 15 do + context##drawImage img (float_of_int i) (float_of_int y +. 1.) + done) + else if hp <= max_hp *. 0.75 then ( + let img = Html.createImg document in + img##.src := js "Sprites/GreenHealth.png"; + for i = x + 1 to x + 18 do + context##drawImage img (float_of_int i) (float_of_int y +. 1.) + done) + else if hp <= max_hp *. 0.875 then ( + let img = Html.createImg document in + img##.src := js "Sprites/GreenHealth.png"; + for i = x + 1 to x + 21 do + context##drawImage img (float_of_int i) (float_of_int y +. 1.) + done) + else + let img = Html.createImg document in + img##.src := js "Sprites/GreenHealth.png"; + for i = x + 1 to x + 24 do + context##drawImage img (float_of_int i) (float_of_int y +. 1.) + done + +(* [draw_healthbar context chr_list] draws a health + * bar for all the characters inside [chr_list]. The + * health bar will appear under the player and is + * either red, yellow, or green depending on the amount of + * health left *) +let rec draw_healthbar context chr_list = + match chr_list with + | [] -> () + | chr :: t -> + let x, y = chr.location in + let x' = (x * 26) + 3 in + let y' = (y * 26) + 23 in + let health, max_health = chr.health in + let img = Html.createImg document in + img##.src := js "Sprites/HealthBar.png"; + context##drawImage img (float_of_int x') (float_of_int y'); + draw_health context health max_health x' y'; + draw_healthbar context t + +(*********************************************************) +(****************** Draw Arrow Functions *****************) +(*********************************************************) + +(* [draw_menu_arrow context state] draws the blue right + * facing error pointing to the current selection on a + * menu. Arrow is also animated using sync global reference*) +let draw_menu_arrow context state = + let img = Html.createImg document in + img##.src := js "Sprites/arrow.png"; + if state.menu_active then + match state.menu_cursor with + | 0 -> ( + match !sync with + | true -> context##drawImage img 271. 32. + | false -> context##drawImage img 273. 32.) + | 1 -> ( + match !sync with + | true -> context##drawImage img 271. 58. + | false -> context##drawImage img 273. 58.) + | 2 -> ( + match !sync with + | true -> context##drawImage img 271. 84. + | false -> context##drawImage img 273. 84.) + | 3 -> ( + match !sync with + | true -> context##drawImage img 271. 110. + | false -> context##drawImage img 273. 110.) + | 4 -> ( + match !sync with + | true -> context##drawImage img 271. 136. + | false -> context##drawImage img 273. 136.) + | 5 -> ( + match !sync with + | true -> context##drawImage img 271. 162. + | false -> context##drawImage img 273. 162.) + | 6 -> ( + match !sync with + | true -> context##drawImage img 271. 188. + | false -> context##drawImage img 273. 188.) + | 7 -> ( + match !sync with + | true -> context##drawImage img 271. 214. + | false -> context##drawImage img 273. 214.) + | _ -> () + else () + +(*********************************************************) +(***************** Draw Dijsktra Squares *****************) +(*********************************************************) + +(* [draw_dijkstra_blue context tile_lst] draws the blue + * moveable squares when in 'MoveSelect'. The blue tiles + * in [tile_list] are made transparent and dispaly the + * moveable range of the player *) +let rec draw_dijsktra_blue (context : Html.canvasRenderingContext2D Js.t) + tile_lst = + match tile_lst with + | [] -> () + | (x, y) :: t -> + let img = Html.createImg document in + img##.src := js "Sprites/blue_test.png"; + context##.globalAlpha := 0.6; + context##drawImage img (float_of_int x *. 26.) (float_of_int y *. 26.); + draw_dijsktra_blue context t + +(* [draw_dijsktra_red context tile_list] draws the red + * squares around the blue moveable squares. *) +let rec draw_dijsktra_red (context : Html.canvasRenderingContext2D Js.t) + tile_lst = + match tile_lst with + | [] -> () + | (x, y) :: t -> + let img = Html.createImg document in + img##.src := js "Sprites/red.png"; + context##.globalAlpha := 0.6; + context##drawImage img (float_of_int x *. 26.) (float_of_int y *. 26.); + draw_dijsktra_red context t + +(* [draw_dijkstra context st] draws the blue and red squares + * when in the 'MoveSelect' stage. The tile lists of the blue and + * and red squares are stored inside of state's active_unit *) +let draw_dijsktra (context : Html.canvasRenderingContext2D Js.t) st = + match st.active_unit with + | None -> () + | Some chr -> ( + match chr.stage with + | MoveSelect -> + draw_dijsktra_blue context chr.movement; + draw_dijsktra_red context chr.attackable + | _ -> ()) + +(*********************************************************) +(****************** Draw is player done ******************) +(*********************************************************) + +(* [draw_is_player_done context active_unit] draws a gray square + * under a player that has just finished its turn *) +let rec draw_is_player_done context lst = + match lst with + | [] -> () + | chr :: t -> + if chr.stage = Done then ( + let x, y = chr.location in + let img = Html.createImg document in + img##.src := js "Sprites/Gray.png"; + context##drawImage img (float_of_int x *. 26.) (float_of_int y *. 26.); + draw_is_player_done context t) + else draw_is_player_done context t + +(*********************************************************) +(****************** Draw Attack Squares *****************) +(*********************************************************) + +(* [draw_attack_helper context lst] is draws the attack squares + * given a list [lst] of squares *) +let rec draw_attack_helper context lst = + match lst with + | [] -> () + | (x, y) :: t -> + let img = Html.createImg document in + img##.src := js "Sprites/red.png"; + context##.globalAlpha := 0.6; + context##drawImage img (float_of_int x *. 26.) (float_of_int y *. 26.); + draw_attack_helper context t + +(* [draw_attack_sqaures context active_unit] draws the attack + * squares of the active_unit if the active unit is a player and + * if that player is currently in the 'AttackSelect' stage. *) +let draw_attack_squares (context : Html.canvasRenderingContext2D Js.t) + active_unit = + match active_unit with + | Some chr -> + if chr.stage = AttackSelect then + let tile_lst = attack_range chr in + draw_attack_helper context tile_lst + else () + | _ -> () + +(*********************************************************) +(********************* Draw Side Bar *********************) +(*********************************************************) + +(* [find_drawpoint_name context name] finds the correct x + * value to display the string [name]. This allows [name] + * to be centered on the sidebar *) +let find_drawpoint_name context name = + let len = String.length name in + let x = 455. in + (* Default val *) + if len < 4 then x + else if len = 4 then x -. 6. + else if len = 5 then x -. 8. + else if len = 6 then x -. 10. + else if len = 7 then x -. 14. + else if len = 8 then x -. 18. + else if len = 9 then x -. 22. + else if len = 10 then x -. 26. + else if len = 11 then x -. 30. + else if len = 12 then x -. 34. + else if len = 13 then x -. 38. + else if len = 14 then x -. 42. + else if len = 15 then x -. 46. + else if len = 16 then x -. 50. + else if len = 17 then x -. 54. + else 390. + +(* [draw_sidebar_back context] draws the background for + * the side bar *) +let draw_sidebar_back context = + for i = 15 to 20 do + for j = 0 to 14 do + let img = Html.createImg document in + img##.src := js "Sprites/sidebarback.png"; + context##drawImage img (float_of_int i *. 26.) (float_of_int j *. 26.) + done + done + +(* [draw_sidebar_title context state] draws the last characters + * name on the side bar *) +let draw_sidebar_title context state = + match state.last_character with + | Some chr -> + context##.strokeStyle := js "white"; + context##.font := js "16px sans-serif"; + let x = find_drawpoint_name context chr.name in + context##.fillStyle := js "white"; + context##fillText (js chr.name) x 26. + | None -> () + +(* [draw_lyn_face context] draws lyn face on the sidebar if + * lyn was the last character *) +let draw_face context img_src = + let img = Html.createImg document in + img##.src := img_src; + context##drawImage img 416. 52. + +(* [draw_lyn_face context] draws lyn face on the sidebar if + * lyn was the last character *) +let draw_face_archer context img_src = + let img = Html.createImg document in + img##.src := img_src; + context##drawImage img 400. 52. + +(* [draw_lyn_face context] draws lyn face on the sidebar if + * lyn was the last character *) +let draw_face_mage context img_src = + let img = Html.createImg document in + img##.src := img_src; + context##drawImage img 440. 52. + +(* [draw_lyn_face context] draws lyn face on the sidebar if + * lyn was the last character *) +let draw_face_boss context img_src = + let img = Html.createImg document in + img##.src := img_src; + context##drawImage img 403. 52. + +(* [draw_sidebar_face context state] draws the face of the + * last character *) +let draw_sidebar_face context state = + match state.last_character with + | Some chr -> ( + match chr.name with + | "Lyn" -> draw_face context (js "Sprites/lyn.png") + | "Hector" -> draw_face context (js "Sprites/Hector.png") + | "Erk" -> draw_face context (js "Sprites/Erk.png") + | "Mage" -> draw_face_mage context (js "Sprites/Mage.png") + | "Mage Boss" -> draw_face_boss context (js "Sprites/MageBoss.png") + | "Archer" -> draw_face_archer context (js "Sprites/Archer.png") + | "Melee" -> draw_face_archer context (js "Sprites/Melee.png") + | "Melee Boss" -> draw_face_boss context (js "Sprites/MeleeBoss.png") + | _ -> ()) + | None -> () + +(* [draw_sidebar_stats context state] draws all the stats for last character + * on the sidebar. The stats drawn are based on the fields of the character + * type. *) +let draw_sidebar_stats context state = + match state.last_character with + | Some chr -> + let hp = + string_of_int (fst chr.health) ^ "/" ^ string_of_int (snd chr.health) + in + let hp_x = find_drawpoint_name context ("health :" ^ hp) in + context##.strokeStyle := js "white"; + context##.font := js "16px sans-serif"; + context##.fillStyle := js "white"; + context##fillText (js "Stats") 447. 195.; + context##fillText (js ("level : " ^ string_of_int chr.level)) 392. 215.; + context##fillText (js ("exp : " ^ string_of_int chr.exp)) 392. 235.; + context##fillText (js ("health : " ^ hp)) hp_x 45.; + context##fillText (js ("str : " ^ string_of_int chr.str)) 392. 255.; + context##fillText (js ("mag : " ^ string_of_int chr.mag)) 392. 275.; + context##fillText (js ("def : " ^ string_of_int chr.def)) 392. 295.; + context##fillText (js ("spd : " ^ string_of_int chr.spd)) 392. 315.; + context##fillText (js ("res : " ^ string_of_int chr.res)) 392. 335.; + context##fillText (js ("skl : " ^ string_of_int chr.skl)) 392. 355.; + context##fillText (js ("lck : " ^ string_of_int chr.lck)) 475. 215.; + context##fillText (js ("mov : " ^ string_of_int chr.mov)) 475. 235.; + context##fillText (js ("hit : " ^ string_of_int chr.hit)) 475. 255.; + context##fillText (js ("atk : " ^ string_of_int chr.atk)) 475. 275.; + context##fillText (js ("crit : " ^ string_of_int chr.crit)) 475. 295.; + context##fillText (js ("avd : " ^ string_of_int chr.avoid)) 475. 315. + | None -> () + +(* [draw_sidebar context state] Draws the side bar which + * contains information of the last character, such as name, + * face, health, and other stats *) +let draw_sidebar context state = + draw_sidebar_back context; + draw_sidebar_title context state; + draw_sidebar_face context state; + draw_sidebar_stats context state + +(*********************************************************) +(******************** Draw Attack Menu *******************) +(*********************************************************) + +(* [draw_attack_back context] draws the background for + * the attack menu *) +let draw_attack_back context = + let x = 229. in + let y = 304. in + let rec ys x y = + if x = 385. then () + else + let img = Html.createImg document in + img##.src := js "Sprites/databackground.png"; + context##drawImage img x y; + if y = 356. then ys (x +. 26.) 304. else ys x (y +. 26.) + in + ys x y + +(* [draw_player_stats context player enemy] draws the stats of + * the [player] and [enemy] on the attack background *) +let draw_player_stats (context : Html.canvasRenderingContext2D Js.t) player + enemy = + context##.font := js "13px sans-serif"; + let hp = + string_of_int (fst player.health) ^ "/" ^ string_of_int (snd player.health) + in + let hp_enm = + string_of_int (fst enemy.health) ^ "/" ^ string_of_int (snd enemy.health) + in + let player_damage = damage player enemy in + let enemy_damage = damage enemy player in + context##.fillStyle := js "white"; + context##fillText (js player.name) 235. 320.; + context##fillText (js ("Hp: " ^ hp)) 235. 340.; + context##fillText (js ("Dam: " ^ string_of_int player_damage)) 235. 360.; + context##fillText (js enemy.name) 320. 320.; + context##fillText (js ("Hp: " ^ hp_enm)) 320. 340.; + context##fillText (js ("Dam: " ^ string_of_int enemy_damage)) 320. 360. + +(* [draw_attack_menu context state] draws the attack menu + * which shows the user the health of the current player and + * enemy as well as the damage each will do to each other. + * The attack 'menu' is only drawn when the active_unit + * is in 'AttackSelect' and when the confirm menu is also + * up *) +let draw_attack_menu (context : Html.canvasRenderingContext2D Js.t) state = + match state.active_unit with + | Some chr -> ( + match (chr.stage, state.active_tile.c) with + | AttackSelect, Some enemy -> + if state.current_menu <> confirm_menu then () + else ( + draw_attack_back context; + context##.strokeStyle := js "white"; + context##strokeRect 229. 304. 160. 82.; + draw_player_stats context chr enemy; + context##.font := js "12px sans-serif") + | _, _ -> ()) + | None -> () + +(*********************************************************) +(******************** Draw Inventory *********************) +(*********************************************************) + +(* [draw_inv_back context] draws the background of the inv *) +let draw_inv_back context = + let x = 0. in + let y = 390. in + let rec ys x y = + if x = 546. then () + else + let img = Html.createImg document in + img##.src := js "Sprites/sidebarback.png"; + context##drawImage img x y; + if y = 468. then ys (x +. 26.) 390. else ys x (y +. 26.) + in + ys x y + +(* [draw_inventory context state] draws the inventory + * on the bottom of the screen with pictures/text associated + * with each item in the inventory *) +let draw_inventory context state = draw_inv_back context + +(*********************************************************) +(********************** Draw Enemies *********************) +(*********************************************************) + +(* [draw_boss context enemy] draws the boss + * [enemy] on the gui. Also accounts for animation *) +let draw_boss context enemy = + match !sync with + | true -> + let img = Html.createImg document in + let x, y = enemy.location in + img##.src := js "Sprites/EnemySprites/Enemy_Boss1_Alert.png"; + context##drawImage_full img 18. 16. 26. 26. + (float_of_int x *. 26.) + (float_of_int y *. 26.) + 25. 22. + | false -> + let img = Html.createImg document in + let x, y = enemy.location in + img##.src := js "Sprites/EnemySprites/Enemy_Boss1_Passive.png"; + context##drawImage_full img 16. 8. 26. 26. + ((float_of_int x *. 26.) +. 3.) + ((float_of_int y *. 26.) -. 3.) + 25. 28. + +(* [draw_swordsman context enemy] draws the swordsman + * [enemy] on the gui. Also accounts for animation *) +let draw_swordsman context enemy = + match !sync with + | true -> + let img = Html.createImg document in + let x, y = enemy.location in + img##.src := js "Sprites/EnemySprites/Enemy_Swordsman_N.png"; + context##drawImage_full img 20. 1. 20. 40. + ((float_of_int x *. 26.) +. 6.) + ((float_of_int y *. 26.) -. 10.) + 25. 40. + | false -> + let img = Html.createImg document in + let x, y = enemy.location in + img##.src := js "Sprites/EnemySprites/Enemy_Swordsman_S.png"; + context##drawImage_full img 17. 21. 20. 20. + ((float_of_int x *. 26.) +. 6.) + (float_of_int y *. 26.) + 25. 28. + +(* [draw_mage context enemy] draws the mage sprite + * [enemy] on the [context] *) +let draw_mage context enemy = + match !sync with + | true -> + let img = Html.createImg document in + let x, y = enemy.location in + img##.src := js "Sprites/EnemySprites/Enemy_Mage.png"; + context##drawImage_full img 21. 10. 26. 36. + ((float_of_int x *. 26.) +. 6.) + (float_of_int y *. 26.) + 25. 28. + | false -> + let img = Html.createImg document in + let x, y = enemy.location in + img##.src := js "Sprites/EnemySprites/Enemy_Mage2.png"; + context##drawImage_full img 21. 11. 26. 36. + ((float_of_int x *. 26.) +. 6.) + (float_of_int y *. 26.) + 25. 26. + +(* [draw_mage_boss context enemy] draws the mage boss sprite + * [enemy] on the [context] *) +let draw_mage_boss context enemy = + match !sync with + | true -> + let img = Html.createImg document in + let x, y = enemy.location in + img##.src := js "Sprites/EnemySprites/Mage_Boss.png"; + context##drawImage_full img 7. 8. 32. 36. + (float_of_int x *. 26.) + (float_of_int y *. 26.) + 25. 28. + | false -> + let img = Html.createImg document in + let x, y = enemy.location in + img##.src := js "Sprites/EnemySprites/Mage_Boss2.png"; + context##drawImage_full img 15. 8. 32. 36. + (float_of_int x *. 26.) + (float_of_int y *. 26.) + 25. 26. + +(* [draw_enemies_helper context enemy_lst] takes a + * list of enemies [enemy_lst] and draws the proper + * sprite corresponding to the name of all the enemies + * in the list *) +let rec draw_enemies_helper context enemy_lst = + match enemy_lst with + | [] -> () + | enemy :: t -> ( + match enemy.name with + | "Archer" -> + draw_archer context enemy; + draw_enemies_helper context t + | "Melee Boss" -> + draw_boss context enemy; + draw_enemies_helper context t + | "Melee" -> + draw_swordsman context enemy; + draw_enemies_helper context t + | "Mage" -> + draw_mage context enemy; + draw_enemies_helper context t + | "Mage Boss" -> + draw_mage_boss context enemy; + draw_enemies_helper context t + | _ -> ()) + +(* [draw_enemies context state] draws the enemy sprites on + * the map. *) +let draw_enemies context state = draw_enemies_helper context state.enemies + +(*********************************************************) +(****************** Draw win/loose screen ****************) +(*********************************************************) + +(* [draw_win_screen context] draws the win screen if + * the player has won *) +let draw_win_screen (context : Html.canvasRenderingContext2D Js.t) = + context##.fillStyle := js "black"; + context##fillRect 0. 0. canvas_width canvas_height; + context##.strokeStyle := js "white"; + context##.fillStyle := js "white"; + context##.font := js "60px Times New Roman"; + context##fillText (js "YOU WIN!") 130. 120.; + context##fillText (js "Thanks for Playing!") 40. 200. + +(* [draw_lose_screen context] draws the lose screen if + * the player has won *) +let draw_lose_screen (context : Html.canvasRenderingContext2D Js.t) = + context##.fillStyle := js "black"; + context##fillRect 0. 0. canvas_width canvas_height; + context##.strokeStyle := js "white"; + context##.fillStyle := js "white"; + context##.font := js "60px Times New Roman"; + context##fillText (js "Sorry, you lost...") 90. 100.; + context##fillText (js "Thanks for Playing!") 40. 170.; + context##.font := js "30px Times New Roman"; + context##fillText (js "To play again just refresh the page!") 70. 230. + +(*********************************************************) +(***************** Draw transition screen ****************) +(*********************************************************) + +(* [draw_transition_screen context state] draws the transition + * screen on the [context]. The transitions screen occurs + * between rounds when switching between Map1 and Map2. It + * also features a timer that counts down from 10 *) +let draw_transition_screen (context : Html.canvasRenderingContext2D Js.t) state + = + if !transition < 0 then state.round <- false + else + let timer = !transition / 100 in + context##.fillStyle := js "black"; + context##fillRect 0. 0. canvas_width canvas_height; + context##.strokeStyle := js "white"; + context##.fillStyle := js "white"; + context##.font := js "50px Times New Roman"; + context##fillText (js "You Beat Round 1!") 90. 120.; + context##fillText (js "Round two is starting in:") 22. 200.; + context##fillText (js (string_of_int timer)) 260. 270. + +(*********************************************************) +(****************** Draw Welcome Screen ******************) +(*********************************************************) + +(* [draw_welcome_screen context] draws the welcome screen + * that will be displayed at the beginning of the game when + * the html window is first loaded. This window will display + * information about the game and directions *) +let draw_welcome_screen context = + context##.fillStyle := js "black"; + context##fillRect 0. 0. canvas_width canvas_height; + context##.fillStyle := js "white"; + context##.strokeStyle := js "white"; + context##.font := js "50px Times New Roman"; + context##.fillStyle := js "Solid"; + context##fillText (js "WELCOME TO") 90. 50.; + let img = Html.createImg document in + img##.src := js "Sprites/FireEmblem.png"; + context##drawImage img 80. 70.; + context##.font := js "20px Times New Roman"; + context##fillText (js "How To Play:") 10. 140.; + context##.font := js "15px Times New Roman"; + context##fillText + (js + "The goal of the game is to move your players (in blue) to the enemies \ + using the") + 30. 160.; + context##fillText + (js + "'Z' key to select the player. When a player is selected, blue and red \ + tiles will appear") + 30. 175.; + context##fillText + (js + "on the screen. Blue tiles are moveable tiles. After you moved you can \ + either attack") + 30. 190.; + context##fillText + (js + "which will show more red tiles that represent attack range, use an \ + item, visit a ") + 30. 205.; + context##fillText + (js + "a village, open a chest, trade with a another player, or wait which \ + will end that ") + 30. 220.; + context##fillText + (js + "players turn. To deselect press 'X'. 'A' teleports the cursor to the \ + current active") + 30. 235.; + context##fillText + (js + "player. Once all players finish their turns, click on an empty square \ + and click 'END' ") + 30. 250.; + context##fillText + (js + "to end the players turn. Then the AI will attack, which will end the \ + AI turn") + 30. 265.; + context##.font := js "20px Times New Roman"; + context##fillText (js "Controls:") 10. 285.; + context##.font := js "15px Times New Roman"; + let img = Html.createImg document in + img##.src := js "Sprites/ArrowKeys.png"; + context##drawImage img 10. 280.; + let img = Html.createImg document in + context##.font := js "15px Times New Roman"; + context##fillText (js "The Arrow Keys move the") 95. 310.; + context##fillText (js "cursor around the map") 95. 325.; + context##fillText (js "and menu") 95. 340.; + img##.src := js "Sprites/Z.png"; + context##drawImage img 40. 340.; + context##fillText (js "The Z Key selects units") 95. 360.; + context##fillText (js "and options on the menus") 95. 375.; + let img = Html.createImg document in + img##.src := js "Sprites/X.png"; + context##drawImage img 270. 300.; + context##fillText (js "The X Keys deselects units") 330. 310.; + context##fillText (js "and options on the menus") 330. 325.; + let img = Html.createImg document in + img##.src := js "Sprites/A.png"; + context##drawImage img 270. 340.; + context##fillText (js "The A Keys moves the cursor") 330. 350.; + context##fillText (js "to the player whose turn it") 330. 365.; + context##fillText (js "currently is") 330. 380.; + context##fillText (js "Press Z, X, A, or arrow keys to play game!") 135. 125. + +(*********************************************************) +(****************** Draw State Functions *****************) +(*********************************************************) + +(* [draw_state] draws the the current [state] on the [context]. + * Also has a side affect of updating the global variable clock, + * transition, and transition start *) +let draw_state (context : Html.canvasRenderingContext2D Js.t) state = + context##clearRect 0. 0. canvas_width canvas_height; + match (state.welcome, state.round, state.won, state.lose) with + | true, _, _, _ -> draw_welcome_screen context + | false, true, _, _ -> + transition_start := true; + draw_transition_screen context state; + clock (); + transition_start := false + | false, false, true, false -> draw_win_screen context + | false, false, false, true -> draw_lose_screen context + | _, _, _, _ -> + draw_map context state; + draw_dijsktra context state; + draw_attack_squares context state.active_unit; + context##.globalAlpha := 1.; + draw_is_player_done context state.player; + draw_player context state.player; + draw_enemies context state; + draw_cursor context state.active_tile; + draw_healthbar context state.player; + draw_healthbar context state.enemies; + menu_manager context state; + draw_menu_arrow context state; + draw_sidebar context state; + draw_attack_menu context state; + (* draw_inventory context state; *) + clock () diff --git a/src/gui.mli b/src/gui.mli index 50ed730..2815668 100644 --- a/src/gui.mli +++ b/src/gui.mli @@ -3,10 +3,10 @@ open State open Js_of_ocaml (* drawing canvas width *) -val canvas_width: float +val canvas_width : float (* drawing canvas height *) -val canvas_height: float +val canvas_height : float +val draw_state : Dom_html.canvasRenderingContext2D Js.t -> state -> unit (** [draw_state st] will draw the GUI for [st]*) -val draw_state: Dom_html.canvasRenderingContext2D Js.t -> state -> unit diff --git a/src/interactions.ml b/src/interactions.ml index 2002e69..d014c6f 100644 --- a/src/interactions.ml +++ b/src/interactions.ml @@ -1,7 +1,6 @@ open Types open Characters - (** * Represents the three types of ways 1 round of combat can * resolve. *) @@ -17,7 +16,7 @@ let exp : combatResolutions list ref = ref [] * Represents the order in which combat encounters should be * executed. *) -let combatQ = Queue.create() +let combatQ = Queue.create () (** * [survive d] is a function that checks if the character, [d], @@ -26,8 +25,7 @@ let combatQ = Queue.create() * - d is a valid character * - i is an int *) -let survive (d : character) (i : int) = - i > fst d.health +let survive (d : character) (i : int) = i > fst d.health (** * [penalty_helper p s] is a function that searches a list of @@ -36,11 +34,10 @@ let survive (d : character) (i : int) = * requires: * - p is a (stat * (int * int)) list, but *) -let rec penalty_helper (p: (stat * (int * int)) list) (s:stat) = +let rec penalty_helper (p : (stat * (int * int)) list) (s : stat) = match p with - |[] -> (0,0) - |h::t -> if fst h = s then snd h else - penalty_helper t s + | [] -> (0, 0) + | h :: t -> if fst h = s then snd h else penalty_helper t s (** * [find_penalty a s] is a function that find the penalties for @@ -50,10 +47,8 @@ let rec penalty_helper (p: (stat * (int * int)) list) (s:stat) = * - [a] is a valid character. * - [s] is a valid stat. *) -let find_penalty (a: character) (s:stat) :int * int = - match equipped a with - |None -> (0, 0) - |Some x -> penalty_helper x.penalty s +let find_penalty (a : character) (s : stat) : int * int = + match equipped a with None -> (0, 0) | Some x -> penalty_helper x.penalty s (** * [damage a d] is a function that returns an int that represents @@ -65,10 +60,10 @@ let find_penalty (a: character) (s:stat) :int * int = let damage a d = match equipped a with | None -> 0 - | Some x -> - match x.wtype with - |Tome -> if a.atk - d.res < 0 then 0 else a.atk - d.res - |_ -> if a.atk - d.def < 0 then 0 else a.atk - d.def + | Some x -> ( + match x.wtype with + | Tome -> if a.atk - d.res < 0 then 0 else a.atk - d.res + | _ -> if a.atk - d.def < 0 then 0 else a.atk - d.def) (** * [distance a b] is a function that returns the distance from @@ -78,8 +73,7 @@ let damage a d = * - [b] is a valid character *) let distance a b = - abs (fst a.location - fst b.location) + - abs (snd a.location - snd b.location) + abs (fst a.location - fst b.location) + abs (snd a.location - snd b.location) (** * [in_range a d] is a function that returns whether or not d is @@ -90,9 +84,10 @@ let distance a b = *) let in_range a d = match equipped a with - |None -> false - |Some x -> let l = distance a d in - l >= fst x.range && l <= snd x.range + | None -> false + | Some x -> + let l = distance a d in + l >= fst x.range && l <= snd x.range (** * [kill_xp a d] changes the amount of xp character a has @@ -108,21 +103,19 @@ let kill_xp a d = | 2 -> a.exp <- a.exp + 90 | 3 -> a.exp <- a.exp + 80 | 4 -> a.exp <- a.exp + 70 - | x -> if x > 4 then a.exp <- a.exp + 60 - else a.exp <- a.exp + 100 + | x -> if x > 4 then a.exp <- a.exp + 60 else a.exp <- a.exp + 100 else match a.level - d.level with | -4 -> a.exp <- a.exp + 69 | -3 -> a.exp <- a.exp + 59 | -2 -> a.exp <- a.exp + 50 | -1 -> a.exp <- a.exp + 42 - | 0 -> a.exp <- a.exp + 35 - | 1 -> a.exp <- a.exp + 29 - | 2 -> a.exp <- a.exp + 22 - | 3 -> a.exp <- a.exp + 14 - | 4 -> a.exp <- a.exp + 5 - | x -> if x > 4 then a.exp <- a.exp + 1 - else a.exp <- a.exp + 80 + | 0 -> a.exp <- a.exp + 35 + | 1 -> a.exp <- a.exp + 29 + | 2 -> a.exp <- a.exp + 22 + | 3 -> a.exp <- a.exp + 14 + | 4 -> a.exp <- a.exp + 5 + | x -> if x > 4 then a.exp <- a.exp + 1 else a.exp <- a.exp + 80 (** * [hit_xp a d] changes the amount of xp character a has @@ -138,21 +131,19 @@ let hit_xp a d = | 2 -> a.exp <- a.exp + 36 | 3 -> a.exp <- a.exp + 32 | 4 -> a.exp <- a.exp + 28 - | x -> if x > 4 then a.exp <- a.exp + 24 - else a.exp <- a.exp + 40 + | x -> if x > 4 then a.exp <- a.exp + 24 else a.exp <- a.exp + 40 else match a.level - d.level with | -4 -> a.exp <- a.exp + 33 | -3 -> a.exp <- a.exp + 29 | -2 -> a.exp <- a.exp + 25 | -1 -> a.exp <- a.exp + 21 - | 0 -> a.exp <- a.exp + 17 - | 1 -> a.exp <- a.exp + 13 - | 2 -> a.exp <- a.exp + 9 - | 3 -> a.exp <- a.exp + 5 - | 4 -> a.exp <- a.exp + 1 - | x -> if x > 4 then a.exp <- a.exp + 1 - else a.exp <- a.exp + 37 + | 0 -> a.exp <- a.exp + 17 + | 1 -> a.exp <- a.exp + 13 + | 2 -> a.exp <- a.exp + 9 + | 3 -> a.exp <- a.exp + 5 + | 4 -> a.exp <- a.exp + 1 + | x -> if x > 4 then a.exp <- a.exp + 1 else a.exp <- a.exp + 37 (** * [wexp_level_up c] returns a weapon level 1 higher than c @@ -163,12 +154,12 @@ let hit_xp a d = *) let wexp_level_up c = match c with - |'e' -> 'd' - |'d' -> 'c' - |'c' -> 'b' - |'b' -> 'a' - |'a' -> 's' - |_ -> failwith "wexp_level_up invalid level" + | 'e' -> 'd' + | 'd' -> 'c' + | 'c' -> 'b' + | 'b' -> 'a' + | 'a' -> 's' + | _ -> failwith "wexp_level_up invalid level" (** * [wexp_helper ty lst] is a function that awards the proper @@ -181,13 +172,14 @@ let wexp_level_up c = *) let rec wexp_helper ty lst = match lst with - |[] -> failwith "not in weapon type list" - |(wt, lv, xp)::t -> if wt = ty then - (if lv = 's' then (wt, lv, xp)::t - else if lv = 'a' && (xp + 5 > 100) then (wt, 's', 0)::t - else if xp + 5 > 100 then (wt, wexp_level_up lv, xp + 5 - 100)::t - else (wt, lv, xp+ + 5)::t) - else wexp_helper ty t + | [] -> failwith "not in weapon type list" + | (wt, lv, xp) :: t -> + if wt = ty then + if lv = 's' then (wt, lv, xp) :: t + else if lv = 'a' && xp + 5 > 100 then (wt, 's', 0) :: t + else if xp + 5 > 100 then (wt, wexp_level_up lv, xp + 5 - 100) :: t + else (wt, lv, xp + 5) :: t + else wexp_helper ty t (** * [award_wexp a] is a function that awards a with weapon exp @@ -196,7 +188,8 @@ let rec wexp_helper ty lst = * - [a] is a valid character *) let award_wexp a = - if a.allegiance = Player then a.wlevels <- wexp_helper (extract a.inv.(a.eqp)).wtype a.wlevels + if a.allegiance = Player then + a.wlevels <- wexp_helper (extract a.inv.(a.eqp)).wtype a.wlevels else () (** @@ -208,12 +201,12 @@ let award_wexp a = * - [t] is a valid outcome *) let comp_outcome a t = - match a, t with - |Kill, _ -> a - |_, Kill -> t - |Hit, _ -> a - |_, Hit -> t - |_, _ -> a + match (a, t) with + | Kill, _ -> a + | _, Kill -> t + | Hit, _ -> a + | _, Hit -> t + | _, _ -> a (** * [award_xp a d] awards experience to characters a and d after @@ -225,11 +218,9 @@ let comp_outcome a t = let award_xp a d = let outcome = List.fold_left (fun a v -> comp_outcome a v) Miss !exp in match outcome with - |Kill -> if a.allegiance = Player then - kill_xp a d else kill_xp d a - |Hit -> if a.allegiance = Player then - hit_xp a d else hit_xp d a - |Miss -> () + | Kill -> if a.allegiance = Player then kill_xp a d else kill_xp d a + | Hit -> if a.allegiance = Player then hit_xp a d else hit_xp d a + | Miss -> () (** * [resolveE a d] is a function that resolves the first round of @@ -240,25 +231,23 @@ let award_xp a d = * - [d] is a valid character *) let resolveE a d = - if (a.eqp = -1) then () - else if (get_rng () + get_rng())/2 > a.hit - d.avoid then - a.inv.(a.eqp) <- (use (a.inv.(a.eqp))); - if get_rng () < a.crit - (d.lck * 2) then (update_health d (3 * (damage a d))) - else update_health d (damage a d); - if fst d.health <= 0 || fst a.health <= 0 then - Queue.clear combatQ; - if fst d.health = 0 && a.allegiance = Player then - exp := (Kill :: !exp); - if fst d.health != 0 && a.allegiance = Player then - exp := (Hit :: !exp); - a.inv.(a.eqp) <- (use (a.inv.(a.eqp))) + if a.eqp = -1 then () + else if (get_rng () + get_rng ()) / 2 > a.hit - d.avoid then + a.inv.(a.eqp) <- use a.inv.(a.eqp); + if get_rng () < a.crit - (d.lck * 2) then update_health d (3 * damage a d) + else update_health d (damage a d); + if fst d.health <= 0 || fst a.health <= 0 then Queue.clear combatQ; + if fst d.health = 0 && a.allegiance = Player then exp := Kill :: !exp; + if fst d.health != 0 && a.allegiance = Player then exp := Hit :: !exp; + a.inv.(a.eqp) <- use a.inv.(a.eqp) (** * [resovleQ ()] resolves the entire combatQ. * requires: Nothing actually *) let rec resolveQ () = - if Queue.is_empty combatQ then () else + if Queue.is_empty combatQ then () + else let round = Queue.pop combatQ in resolveE (fst round) (snd round); resolveQ () @@ -289,8 +278,10 @@ let combat a d = award_xp a d; award_wexp a; award_wexp d; - level_up a; update_character a; - level_up d; update_character d + level_up a; + update_character a; + level_up d; + update_character d (** * [heal a t i] is a function that heals a character, t, and @@ -303,13 +294,13 @@ let combat a d = *) let heal a t i = match a.inv.(i) with - |None -> failwith "No staff" - |Some x -> - let heal_amount = - (a.mag + x.mgt) in - a.inv.(i) <- use a.inv.(i); - a.exp <- a.exp + 12; - level_up a; - update_health t heal_amount + | None -> failwith "No staff" + | Some x -> + let heal_amount = -(a.mag + x.mgt) in + a.inv.(i) <- use a.inv.(i); + a.exp <- a.exp + 12; + level_up a; + update_health t heal_amount (** * [consumable a i] is a function that uses a potion to heal @@ -321,10 +312,11 @@ let heal a t i = *) let consumable a i = match a.inv.(i) with - |None -> failwith "No item" - |Some x -> let heal_amount = -(x.mgt) in - a.inv.(i) <- use a.inv.(i); - update_health a heal_amount + | None -> failwith "No item" + | Some x -> + let heal_amount = -x.mgt in + a.inv.(i) <- use a.inv.(i); + update_health a heal_amount (** * [chest c t i] is a fuction that takes an item from a chest. @@ -338,9 +330,11 @@ let consumable a i = *) let chest c t i = match t with - |Chest (Some x) -> c.inv.(i) <- use c.inv.(i); add_item c x - |Chest (None) -> failwith "empty chest" - |_ -> failwith "Opening nonchest" + | Chest (Some x) -> + c.inv.(i) <- use c.inv.(i); + add_item c x + | Chest None -> failwith "empty chest" + | _ -> failwith "Opening nonchest" (** * [door c t i] is a function that opens a door. @@ -349,8 +343,7 @@ let chest c t i = * - [t] is a valid tile with a door on it * - [i] is a the index of the key used to open the door *) -let door c t i = - if t = Door then c.inv.(i) <- use c.inv.(i) +let door c t i = if t = Door then c.inv.(i) <- use c.inv.(i) (** * [village c t] is a function that visits a village @@ -363,9 +356,9 @@ let door c t i = *) let village c t = match t with - |Village (Some x) -> add_item c x - |Village (None) -> failwith "visited village" - |_ -> failwith "visiting nonvillage" + | Village (Some x) -> add_item c x + | Village None -> failwith "visited village" + | _ -> failwith "visiting nonvillage" (** * [trade c1 c2 i1 i2] is a function that swaps and item, i1, diff --git a/src/interactions.mli b/src/interactions.mli index c02365f..de4e9eb 100644 --- a/src/interactions.mli +++ b/src/interactions.mli @@ -1,27 +1,27 @@ -open Types - -(**Calculates how much damamge one character does to another*) -val damage : character -> character -> int - -(** handles all combat procedures*) -val combat : character -> character -> unit - -(** heals a character *) -val heal : character -> character -> int -> unit - -(** consumable takes a character and returns that character with its stats - * accordingly. -*) -val consumable : character -> int -> unit - -(** loot a chest.*) -val chest : character -> terrain -> int -> unit - -(** open a door.*) -val door : character -> terrain -> int -> unit - -(** visits a village*) -val village : character -> terrain -> unit - -(** trades two items between two characters*) -val trade : character -> character -> int -> int -> unit +open Types + +val damage : character -> character -> int +(**Calculates how much damamge one character does to another*) + +val combat : character -> character -> unit +(** handles all combat procedures*) + +val heal : character -> character -> int -> unit +(** heals a character *) + +val consumable : character -> int -> unit +(** consumable takes a character and returns that character with its stats + * accordingly. +*) + +val chest : character -> terrain -> int -> unit +(** loot a chest.*) + +val door : character -> terrain -> int -> unit +(** open a door.*) + +val village : character -> terrain -> unit +(** visits a village*) + +val trade : character -> character -> int -> int -> unit +(** trades two items between two characters*) diff --git a/src/main.ml b/src/main.ml index 3d6c3dd..d28acf0 100644 --- a/src/main.ml +++ b/src/main.ml @@ -1,100 +1,120 @@ -open Gui -open State -open Types -open Room -open Command -open Charactermaker -open Js_of_ocaml - -module Html = Dom_html -let js = Js.string (* partial function, takes in string *) -let document = Html.document - -(* NOTE: Change this section to make it less similar to Zoldas *) -(************************ DOM HELPERS ************************) - -(* [fail] is a failure/exception handler *) -let fail = fun _ -> assert false - -(* [get_element_by_id id] gets a DOM element by its id *) -let get_element_by_id id = - Js.Opt.get (Html.document##getElementById (js id)) fail - -(* [append_text e s] appends string s to element e *) -let append_text e s = Dom.appendChild e (document##createTextNode (js s)) - -let init_state = - let p = [make_lyn (14, 4);make_hector (13, 3); make_erk (12, 2)] in - let e = [make_archer (3, 5); make_archer (2, 7); make_swordsman (5, 8); make_mage (3, 10); make_meleeboss (1, 13)] in - let x = - { - player = p; - enemies = e; - lose = false; - won = false; - round = false; - welcome = true; - active_tile = {coordinate = (5,5); ground = Plain; tile_type = Grass;c=None}; - active_unit = None; - active_item = -1; - act_map = add_init_characters (List.rev_append p e) Room.map1; - current_menu = unit_menu; - menu_active = false; - menu_cursor = 0; - last_character = None; - } in x|>set_init_ch_movement x.player|>set_init_ch_movement x.enemies|>set_act_tile - -let state = ref init_state -(* [main ()] is begins game execution by first building and designing - * the html page and designing and subsequently calling the REPL to - * start execution using the game engine *) -let main () = - let gui = get_element_by_id "gui" in - let body = get_element_by_id "body" in - let logo = Html.createImg document in - let p1 = Html.createP document in - let p2 = Html.createP document in - let p3 = Html.createP document in - let canvas = Html.createCanvas document in - gui##.style##.textAlign := js "center"; - body##.style##.backgroundImage := js "url('Sprites/background.png')"; - body##.style##.backgroundRepeat := js "no-repeat"; - logo##.src := js "Sprites/Logo.png"; - gui##.style##.cssText := js "font-size:16px"; - gui##.style##.textAlign := js "center"; - canvas##.width := int_of_float Gui.canvas_width; - canvas##.height := int_of_float Gui.canvas_height; - append_text p1 "Welcome to Fire Emblem! Some stuff about the game ..."; - append_text p2 "Developed by: Frank Rodriguez, Albert Tsao, Darren Tsai, and Ray Gu"; - append_text p3 "for our 3110 final project. Thanks for playing!"; - Dom.appendChild gui logo; - Dom.appendChild gui p1; - Dom.appendChild gui canvas; - Dom.appendChild gui p2; - Dom.appendChild gui p3; - let context = canvas##getContext (Html._2d_) in - - (* Add event listeners to the HTML for key press and key - * lift events. *) - let _ = Html.addEventListener - document Html.Event.keydown (Html.handler Command.keydown) - Js._true in - let game_loop context bol = - let rec loop () = - state := State.do' !state; - Gui.draw_state context !state; - Html.window##requestAnimationFrame( - Js.wrap_callback (fun (t:float) -> loop ()) - ) |> ignore - in loop () - in game_loop context false - - -(* Begin the game *) -let _ = main () - - -module Int_set = Set.Make (struct - type t = int - let compare = compare - end) +open Gui +open State +open Types +open Room +open Command +open Charactermaker +open Js_of_ocaml +module Html = Dom_html + +let js = Js.string (* partial function, takes in string *) + +let document = Html.document + +(* NOTE: Change this section to make it less similar to Zoldas *) +(************************ DOM HELPERS ************************) + +(* [fail] is a failure/exception handler *) +let fail _ = assert false + +(* [get_element_by_id id] gets a DOM element by its id *) +let get_element_by_id id = + Js.Opt.get (Html.document##getElementById (js id)) fail + +(* [append_text e s] appends string s to element e *) +let append_text e s = Dom.appendChild e (document##createTextNode (js s)) + +let init_state = + let p = [ make_lyn (14, 4); make_hector (13, 3); make_erk (12, 2) ] in + let e = + [ + make_archer (3, 5); + make_archer (2, 7); + make_swordsman (5, 8); + make_mage (3, 10); + make_meleeboss (1, 13); + ] + in + let x = + { + player = p; + enemies = e; + lose = false; + won = false; + round = false; + welcome = true; + active_tile = + { coordinate = (5, 5); ground = Plain; tile_type = Grass; c = None }; + active_unit = None; + active_item = -1; + act_map = add_init_characters (List.rev_append p e) Room.map1; + current_menu = unit_menu; + menu_active = false; + menu_cursor = 0; + last_character = None; + } + in + x + |> set_init_ch_movement x.player + |> set_init_ch_movement x.enemies + |> set_act_tile + +let state = ref init_state + +(* [main ()] is begins game execution by first building and designing + * the html page and designing and subsequently calling the REPL to + * start execution using the game engine *) +let main () = + let gui = get_element_by_id "gui" in + let body = get_element_by_id "body" in + let logo = Html.createImg document in + let p1 = Html.createP document in + let p2 = Html.createP document in + let p3 = Html.createP document in + let canvas = Html.createCanvas document in + gui##.style##.textAlign := js "center"; + body##.style##.backgroundImage := js "url('Sprites/background.png')"; + body##.style##.backgroundRepeat := js "no-repeat"; + logo##.src := js "Sprites/Logo.png"; + gui##.style##.cssText := js "font-size:16px"; + gui##.style##.textAlign := js "center"; + canvas##.width := int_of_float Gui.canvas_width; + canvas##.height := int_of_float Gui.canvas_height; + append_text p1 "Welcome to Fire Emblem! Some stuff about the game ..."; + append_text p2 + "Developed by: Frank Rodriguez, Albert Tsao, Darren Tsai, and Ray Gu"; + append_text p3 "for our 3110 final project. Thanks for playing!"; + Dom.appendChild gui logo; + Dom.appendChild gui p1; + Dom.appendChild gui canvas; + Dom.appendChild gui p2; + Dom.appendChild gui p3; + let context = canvas##getContext Html._2d_ in + + (* Add event listeners to the HTML for key press and key + * lift events. *) + let _ = + Html.addEventListener document Html.Event.keydown + (Html.handler Command.keydown) + Js._true + in + let game_loop context bol = + let rec loop () = + state := State.do' !state; + Gui.draw_state context !state; + Html.window##requestAnimationFrame + (Js.wrap_callback (fun (t : float) -> loop ())) + |> ignore + in + loop () + in + game_loop context false + +(* Begin the game *) +let _ = main () + +module Int_set = Set.Make (struct + type t = int + + let compare = compare +end) diff --git a/src/room.ml b/src/room.ml index 6660080..47d3568 100644 --- a/src/room.ml +++ b/src/room.ml @@ -1,608 +1,855 @@ -open Types - -let bigfreakingsword = - { - iname = "B. F. Sword"; - wtype = Sword; - mgt = 12; - acc = 85; - crit = 15; - range = (1,1); - uses = 40; - cost = 0; - sell = 0; - level = 'd'; - users = []; - effective = []; - penalty = []; - } - -let temp_item = - { - iname = "Armads"; - wtype = Axe; - mgt = 16; - acc = 70; - crit = 5; - range = (1,2); - uses = 40; - cost = 0; - sell = 0; - level = 'd'; - users = []; - effective = []; - penalty = []; - } - - -let map1 = { - number=1; - width = 15; - length = 15; - grid = [| - (*first column*) - [| - {coordinate = ( 0, 0); ground = Wall; tile_type = Wall1;c=None}; - {coordinate = ( 0, 1); ground = Wall; tile_type = Wall6;c=None}; - {coordinate = ( 0, 2); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 0, 3); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 0, 4); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 0, 5); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 0, 6); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 0, 7); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 0, 8); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (0, 9); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (0, 10); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (0, 11); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (0, 12); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (0, 13); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (0, 14); ground = Forest; tile_type = Tree;c=None}; - |]; - (*second column*) - [| - {coordinate = ( 1, 0); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 1, 1); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 1, 2); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 1, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 1, 4); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 1, 5); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 1, 6); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 1, 7); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 1, 8); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (1, 9); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (1, 10); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (1, 11); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (1, 12); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (1, 13); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (1, 14); ground = Forest; tile_type = Tree;c=None}; - |]; - (*third column*) - [| - {coordinate = ( 2, 0); ground = Wall; tile_type = Wall2;c=None}; - {coordinate = ( 2, 1); ground = Wall; tile_type = Wall6;c=None}; - {coordinate = ( 2, 2); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 2, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 2, 4); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 2, 5); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 2, 6); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 2, 7); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 2, 8); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (2, 9); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (2, 10); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (2, 11); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (2, 12); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (2, 13); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (2, 14); ground = Plain; tile_type = Grass;c=None}; - |]; - - (*fourth column*) - [| - {coordinate = ( 3, 0); ground = Wall; tile_type = Wall3;c=None}; - {coordinate = ( 3, 1); ground = Wall; tile_type = Wall6;c=None}; - {coordinate = ( 3, 2); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 3, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 3, 4); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 3, 5); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 3, 6); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 3, 7); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 3, 8); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (3, 9); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (3, 10); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (3, 11); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (3, 12); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (3, 13); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (3, 14); ground = Plain; tile_type = Grass;c=None}; - |]; - - (*fifth column*) - [| - {coordinate = ( 4, 0); ground = Wall; tile_type = Wall4;c=None}; - {coordinate = ( 4, 1); ground = Wall; tile_type = Wall5;c=None}; - {coordinate = ( 4, 2); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 4, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 4, 4); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 4, 5); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 4, 6); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 4, 7); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (4, 8); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (4, 9); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (4, 10); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (4, 11); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (4, 12); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (4, 13); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (4, 14); ground = Plain; tile_type = Grass;c=None}; - |]; - - (*sixth column*) - [| - {coordinate = ( 5, 0); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 5, 1); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 5, 2); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 5, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 5, 4); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 5, 5); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 5, 6); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 5, 7); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (5, 8); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (5, 9); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (5, 10); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (5, 11); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (5, 12); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (5, 13); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (5, 14); ground = Forest; tile_type = Tree;c=None}; - |]; - - (*seventh column*) - [| - {coordinate = ( 6, 0); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 6, 1); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 6, 2); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 6, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 6, 4); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 6, 5); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 6, 6); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 6, 7); ground = Plain; tile_type = Tree;c=None}; - {coordinate = (6, 8); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (6, 9); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (6, 10); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (6, 11); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (6, 12); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (6, 13); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (6, 14); ground = Plain; tile_type = Grass;c=None}; - |]; - (*eigth column*) - [| - {coordinate = ( 7, 0); ground = Peaks; tile_type = Bush;c=None}; - {coordinate = ( 7, 1); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 7, 2); ground = Wall; tile_type = Crack;c=None}; - {coordinate = ( 7, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 7, 4); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 7, 5); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 7, 6); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 7, 7); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (7, 8); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (7, 9); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (7, 10); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (7, 11); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (7, 12); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (7, 13); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (7, 14); ground = Plain; tile_type = Grass;c=None}; - |]; - (*9th column*) - [| - {coordinate = ( 8, 0); ground = Peaks; tile_type = Bush;c=None}; - {coordinate = ( 8, 1); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 8, 2); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 8, 3); ground = Wall; tile_type = Crack;c=None}; - {coordinate = ( 8, 4); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 8, 5); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 8, 6); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 8, 7); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (8, 8); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (8, 9); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (8, 10); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (8, 11); ground = Ocean; tile_type = Water8;c=None}; - {coordinate = (8, 12); ground = Ocean; tile_type = Water10;c=None}; - {coordinate = (8, 13); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (8, 14); ground = Plain; tile_type = Grass;c=None}; - |]; - (*10th column*) - - [| - {coordinate = ( 9, 0); ground = Peaks; tile_type = Bush;c=None}; - {coordinate = ( 9, 1); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 9, 2); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 9, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 9, 4); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 9, 5); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 9, 6); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 9, 7); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (9, 8); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (9, 9); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (9, 10); ground = Ocean; tile_type = Water8;c=None}; - {coordinate = (9, 11); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (9, 12); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (9, 13); ground = Ocean; tile_type = Water10;c=None}; - {coordinate = (9, 14); ground = Plain; tile_type = Grass;c=None}; - |]; - - (*11th column*) - [| - {coordinate = ( 10, 0); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 10, 1); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 10, 2); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 10, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 10, 4); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 10, 5); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 10, 6); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 10, 7); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (10, 8); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (10, 9); ground = Ocean; tile_type = Water8;c=None}; - {coordinate = (10, 10); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (10, 11); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (10, 12); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (10, 13); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (10, 14); ground = Ocean; tile_type = Water10;c=None}; - |]; - (*12th column*) - [| - {coordinate = ( 11, 0); ground = Ocean; tile_type = Water1;c=None}; - {coordinate = ( 11, 1); ground = Ocean; tile_type = Water2;c=None}; - {coordinate = ( 11, 2); ground = Plain; tile_type = Bridge;c=None}; - {coordinate = ( 11, 3); ground = Ocean; tile_type = Water2;c=None}; - {coordinate = ( 11, 4); ground = Ocean; tile_type = Water3;c=None}; - {coordinate = ( 11, 5); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 11, 6); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 11, 7); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (11, 8); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (11, 9); ground = Ocean; tile_type = Water9;c=None}; - {coordinate = (11, 10); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (11, 11); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (11, 12); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (11, 13); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (11, 14); ground = Ocean; tile_type = Water7;c=None}; - |]; - - (*13th column*) - [| - {coordinate = ( 12, 0); ground = Mountain; tile_type = Darkbush;c=None}; - {coordinate = ( 12, 1); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 12, 2); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 12, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 12, 4); ground = Ocean; tile_type = Water4;c=None}; - {coordinate = ( 12, 5); ground = Plain; tile_type = Bridge;c=None}; - {coordinate = ( 12, 6); ground = Ocean; tile_type = Water3;c=None}; - {coordinate = ( 12, 7); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (12, 8); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (12, 9); ground = Ocean; tile_type = Water8;c=None}; - {coordinate = (12, 10); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (12, 11); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (12, 12); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (12, 13); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (12, 14); ground = Ocean; tile_type = Water7;c=None}; - |]; - (*14th column*) - [| - {coordinate = ( 13, 0); ground = Mountain; tile_type = Darkbush;c=None}; - {coordinate = ( 13, 1); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 13, 2); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 13, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 13, 4); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 13, 5); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 13, 6); ground = Ocean; tile_type = Water4;c=None}; - {coordinate = ( 13, 7); ground = Ocean; tile_type = Water1;c=None}; - {coordinate = (13, 8); ground = Ocean; tile_type = Water5;c=None}; - {coordinate = ( 13, 9); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (13, 10); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (13, 11); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (13, 12); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (13, 13); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (13, 14); ground = Ocean; tile_type = Water7;c=None}; - |]; - - (*15th column*) - [| - {coordinate = ( 14, 0); ground = Mountain; tile_type = Darkbush;c=None}; - {coordinate = ( 14, 1); ground = Mountain; tile_type = Darkbush;c=None}; - {coordinate = ( 14, 2); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 14, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 14, 4); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 14, 5); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 14, 6); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 14, 7); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (14, 8); ground = Ocean; tile_type = Water6;c=None}; - {coordinate = ( 14, 9); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (14, 10); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (14, 11); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (14, 12); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (14, 13); ground = Ocean; tile_type = Water7;c=None}; - {coordinate = (14, 14); ground = Ocean; tile_type = Water7;c=None}; - |] - |] -} - -let map2 = { - number=2; - width = 15; - length = 15; - grid = [| - (*first column*) - [| - {coordinate = ( 0, 0); ground = Mountain; tile_type = Darkbush;c=None}; - {coordinate = ( 0, 1); ground = Mountain; tile_type = Darkbush;c=None}; - {coordinate = ( 0, 2); ground = Mountain; tile_type = Darkbush;c=None}; - {coordinate = ( 0, 3); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 0, 4); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 0, 5); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 0, 6); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 0, 7); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 0, 8); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (0, 9); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (0, 10); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (0, 11); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (0, 12); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (0, 13); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (0, 14); ground = Forest; tile_type = Tree;c=None}; - |]; - (*second column*) - [| - {coordinate = ( 1, 0); ground = Mountain; tile_type = Darkbush;c=None}; - {coordinate = ( 1, 1); ground = Mountain; tile_type = Darkbush;c=None}; - {coordinate = ( 1, 2); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 1, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 1, 4); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 1, 5); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 1, 6); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 1, 7); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 1, 8); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (1, 9); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (1, 10); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (1, 11); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (1, 12); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (1, 13); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (1, 14); ground = Forest; tile_type = Tree;c=None}; - |]; - (*third column*) - [| - {coordinate = ( 2, 0); ground = Mountain; tile_type = Darkbush;c=None}; - {coordinate = ( 2, 1); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 2, 2); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 2, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 2, 4); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 2, 5); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 2, 6); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 2, 7); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 2, 8); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (2, 9); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (2, 10); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (2, 11); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (2, 12); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (2, 13); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (2, 14); ground = Plain; tile_type = Grass;c=None}; - |]; - - (*fourth column*) - [| - {coordinate = ( 3, 0); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 3, 1); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 3, 2); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 3, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 3, 4); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 3, 5); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 3, 6); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 3, 7); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 3, 8); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (3, 9); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (3, 10); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (3, 11); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (3, 12); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (3, 13); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (3, 14); ground = Plain; tile_type = Grass;c=None}; - |]; - - (*fifth column*) - [| - {coordinate = ( 4, 0); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 4, 1); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 4, 2); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 4, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 4, 4); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 4, 5); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 4, 6); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 4, 7); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (4, 8); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (4, 9); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (4, 10); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (4, 11); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (4, 12); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (4, 13); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (4, 14); ground = Plain; tile_type = Grass;c=None}; - |]; - - (*sixth column*) - [| - {coordinate = ( 5, 0); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 5, 1); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 5, 2); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 5, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 5, 4); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 5, 5); ground = Wall; tile_type = Castle1;c=None}; - {coordinate = ( 5, 6); ground = Wall; tile_type = Castle4;c=None}; - {coordinate = ( 5, 7); ground = Wall; tile_type = Castle7;c=None}; - {coordinate = (5, 8); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (5, 9); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (5, 10); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (5, 11); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (5, 12); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (5, 13); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (5, 14); ground = Forest; tile_type = Tree;c=None}; - |]; - - (*seventh column*) - [| - {coordinate = ( 6, 0); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 6, 1); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 6, 2); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 6, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 6, 4); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 6, 5); ground = Wall; tile_type = Castle2;c=None}; - {coordinate = ( 6, 6); ground = Wall; tile_type = Castle4;c=None}; - {coordinate = ( 6, 7); ground = Wall; tile_type = Castle8;c=None}; - {coordinate = (6, 8); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (6, 9); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (6, 10); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (6, 11); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (6, 12); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (6, 13); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (6, 14); ground = Plain; tile_type = Grass;c=None}; - |]; - (*eigth column*) - [| - {coordinate = ( 7, 0); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 7, 1); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 7, 2); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 7, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 7, 4); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 7, 5); ground = Wall; tile_type = Castle3;c=None}; - {coordinate = ( 7, 6); ground = Wall; tile_type = Castle6;c=None}; - {coordinate = ( 7, 7); ground = Wall; tile_type = Castle9;c=None}; - {coordinate = (7, 8); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (7, 9); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (7, 10); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (7, 11); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (7, 12); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (7, 13); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (7, 14); ground = Plain; tile_type = Grass;c=None}; - |]; - (*9th column*) - [| - {coordinate = ( 8, 0); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 8, 1); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 8, 2); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 8, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 8, 4); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 8, 5); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 8, 6); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 8, 7); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (8, 8); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (8, 9); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (8, 10); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (8, 11); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (8, 12); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (8, 13); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (8, 14); ground = Ocean; tile_type = Water11;c=None}; - |]; - (*10th column*) - - [| - {coordinate = ( 9, 0); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 9, 1); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 9, 2); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 9, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 9, 4); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 9, 5); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 9, 6); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 9, 7); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (9, 8); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (9, 9); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (9, 10); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (9, 11); ground = Ocean; tile_type = Water11;c=None}; - {coordinate = (9, 12); ground = Ocean; tile_type = Water2;c=None}; - {coordinate = (9, 13); ground = Plain; tile_type = Bridge;c=None}; - {coordinate = (9, 14); ground = Ocean; tile_type = Water12;c=None}; - |]; - - (*11th column*) - [| - {coordinate = ( 10, 0); ground = Plain; tile_type = Tree;c=None}; - {coordinate = ( 10, 1); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 10, 2); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 10, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 10, 4); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 10, 5); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 10, 6); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 10, 7); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (10, 8); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (10, 9); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (10, 10); ground = Ocean; tile_type = Water11;c=None}; - {coordinate = (10, 11); ground = Ocean; tile_type = Water12;c=None}; - {coordinate = (10, 12); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (10, 13); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (10, 14); ground = Plain; tile_type = Grass;c=None}; - |]; - (*12th column*) - [| - {coordinate = ( 11, 0); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 11, 1); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 11, 2); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 11, 3); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 11, 4); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 11, 5); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 11, 6); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 11, 7); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (11, 8); ground = Ocean; tile_type = Water11;c=None}; - {coordinate = (11, 9); ground = Plain; tile_type = Bridge;c=None}; - {coordinate = (11, 10); ground = Ocean; tile_type = Water12;c=None}; - {coordinate = (11, 11); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (11, 12); ground = Wall; tile_type = House1;c=None}; - {coordinate = (11, 13); ground = Wall; tile_type = House4;c=None}; - {coordinate = (11, 14); ground = Plain; tile_type = Grass;c=None}; - |]; - - (*13th column*) - [| - {coordinate = ( 12, 0); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 12, 1); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 12, 2); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 12, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 12, 4); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 12, 5); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 12, 6); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 12, 7); ground = Ocean; tile_type = Water11;c=None}; - {coordinate = (12, 8); ground = Ocean; tile_type = Water12;c=None}; - {coordinate = (12, 9); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (12, 10); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (12, 11); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (12, 12); ground = Wall; tile_type = House2;c=None}; - {coordinate = (12, 13); ground = Village (Some (temp_item)); tile_type = House5;c=None}; - {coordinate = (12, 14); ground = Plain; tile_type = Grass;c=None}; - |]; - (*14th column*) - [| - {coordinate = ( 13, 0); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 13, 1); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 13, 2); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 13, 3); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 13, 4); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 13, 5); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 13, 6); ground = Ocean; tile_type = Water11;c=None}; - {coordinate = ( 13, 7); ground = Ocean; tile_type = Water12;c=None}; - {coordinate = (13, 8); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 13, 9); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (13, 10); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (13, 11); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (13, 12); ground = Wall; tile_type = House3;c=None}; - {coordinate = (13, 13); ground = Wall; tile_type = House6;c=None}; - {coordinate = (13, 14); ground = Peaks; tile_type = Bush;c=None}; - |]; - - (*15th column*) - [| - {coordinate = ( 14, 0); ground = Chest (Some bigfreakingsword); tile_type = Chesttile;c=None}; - {coordinate = ( 14, 1); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 14, 2); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 14, 3); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 14, 4); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 14, 5); ground = Ocean; tile_type = Water11;c=None}; - {coordinate = ( 14, 6); ground = Ocean; tile_type = Water12;c=None}; - {coordinate = ( 14, 7); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (14, 8); ground = Forest; tile_type = Tree;c=None}; - {coordinate = ( 14, 9); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (14, 10); ground = Forest; tile_type = Tree;c=None}; - {coordinate = (14, 11); ground = Plain; tile_type = Grass;c=None}; - {coordinate = (14, 12); ground = Peaks; tile_type = Bush;c=None}; - {coordinate = (14, 13); ground = Peaks; tile_type = Bush;c=None}; - {coordinate = (14, 14); ground = Peaks; tile_type = Bush;c=None}; - |] - |] -} +open Types + +let bigfreakingsword = + { + iname = "B. F. Sword"; + wtype = Sword; + mgt = 12; + acc = 85; + crit = 15; + range = (1, 1); + uses = 40; + cost = 0; + sell = 0; + level = 'd'; + users = []; + effective = []; + penalty = []; + } + +let temp_item = + { + iname = "Armads"; + wtype = Axe; + mgt = 16; + acc = 70; + crit = 5; + range = (1, 2); + uses = 40; + cost = 0; + sell = 0; + level = 'd'; + users = []; + effective = []; + penalty = []; + } + +let map1 = + { + number = 1; + width = 15; + length = 15; + grid = + [| + (*first column*) + [| + { coordinate = (0, 0); ground = Wall; tile_type = Wall1; c = None }; + { coordinate = (0, 1); ground = Wall; tile_type = Wall6; c = None }; + { coordinate = (0, 2); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (0, 3); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (0, 4); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (0, 5); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (0, 6); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (0, 7); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (0, 8); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (0, 9); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (0, 10); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (0, 11); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (0, 12); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (0, 13); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (0, 14); ground = Forest; tile_type = Tree; c = None }; + |]; + (*second column*) + [| + { coordinate = (1, 0); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 1); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 2); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 4); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 5); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 6); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 7); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 8); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 9); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (1, 10); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 11); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 12); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 13); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (1, 14); ground = Forest; tile_type = Tree; c = None }; + |]; + (*third column*) + [| + { coordinate = (2, 0); ground = Wall; tile_type = Wall2; c = None }; + { coordinate = (2, 1); ground = Wall; tile_type = Wall6; c = None }; + { coordinate = (2, 2); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 4); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (2, 5); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 6); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (2, 7); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 8); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 9); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 10); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 11); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 12); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 13); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 14); ground = Plain; tile_type = Grass; c = None }; + |]; + (*fourth column*) + [| + { coordinate = (3, 0); ground = Wall; tile_type = Wall3; c = None }; + { coordinate = (3, 1); ground = Wall; tile_type = Wall6; c = None }; + { coordinate = (3, 2); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (3, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (3, 4); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (3, 5); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (3, 6); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (3, 7); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (3, 8); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (3, 9); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (3, 10); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (3, 11); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (3, 12); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (3, 13); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (3, 14); ground = Plain; tile_type = Grass; c = None }; + |]; + (*fifth column*) + [| + { coordinate = (4, 0); ground = Wall; tile_type = Wall4; c = None }; + { coordinate = (4, 1); ground = Wall; tile_type = Wall5; c = None }; + { coordinate = (4, 2); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (4, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (4, 4); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (4, 5); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (4, 6); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (4, 7); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (4, 8); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (4, 9); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (4, 10); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (4, 11); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (4, 12); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (4, 13); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (4, 14); ground = Plain; tile_type = Grass; c = None }; + |]; + (*sixth column*) + [| + { coordinate = (5, 0); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (5, 1); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (5, 2); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (5, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (5, 4); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (5, 5); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (5, 6); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (5, 7); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (5, 8); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (5, 9); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (5, 10); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (5, 11); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (5, 12); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (5, 13); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (5, 14); ground = Forest; tile_type = Tree; c = None }; + |]; + (*seventh column*) + [| + { coordinate = (6, 0); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (6, 1); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (6, 2); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (6, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (6, 4); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (6, 5); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (6, 6); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (6, 7); ground = Plain; tile_type = Tree; c = None }; + { coordinate = (6, 8); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (6, 9); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (6, 10); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (6, 11); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (6, 12); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (6, 13); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (6, 14); ground = Plain; tile_type = Grass; c = None }; + |]; + (*eigth column*) + [| + { coordinate = (7, 0); ground = Peaks; tile_type = Bush; c = None }; + { coordinate = (7, 1); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (7, 2); ground = Wall; tile_type = Crack; c = None }; + { coordinate = (7, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (7, 4); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (7, 5); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (7, 6); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (7, 7); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (7, 8); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (7, 9); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (7, 10); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (7, 11); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (7, 12); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (7, 13); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (7, 14); ground = Plain; tile_type = Grass; c = None }; + |]; + (*9th column*) + [| + { coordinate = (8, 0); ground = Peaks; tile_type = Bush; c = None }; + { coordinate = (8, 1); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (8, 2); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (8, 3); ground = Wall; tile_type = Crack; c = None }; + { coordinate = (8, 4); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (8, 5); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (8, 6); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (8, 7); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (8, 8); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (8, 9); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (8, 10); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (8, 11); ground = Ocean; tile_type = Water8; c = None }; + { + coordinate = (8, 12); + ground = Ocean; + tile_type = Water10; + c = None; + }; + { coordinate = (8, 13); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (8, 14); ground = Plain; tile_type = Grass; c = None }; + |]; + (*10th column*) + [| + { coordinate = (9, 0); ground = Peaks; tile_type = Bush; c = None }; + { coordinate = (9, 1); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (9, 2); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (9, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (9, 4); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (9, 5); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (9, 6); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (9, 7); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (9, 8); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (9, 9); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (9, 10); ground = Ocean; tile_type = Water8; c = None }; + { coordinate = (9, 11); ground = Ocean; tile_type = Water7; c = None }; + { coordinate = (9, 12); ground = Ocean; tile_type = Water7; c = None }; + { + coordinate = (9, 13); + ground = Ocean; + tile_type = Water10; + c = None; + }; + { coordinate = (9, 14); ground = Plain; tile_type = Grass; c = None }; + |]; + (*11th column*) + [| + { coordinate = (10, 0); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (10, 1); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (10, 2); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (10, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (10, 4); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (10, 5); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (10, 6); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (10, 7); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (10, 8); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (10, 9); ground = Ocean; tile_type = Water8; c = None }; + { + coordinate = (10, 10); + ground = Ocean; + tile_type = Water7; + c = None; + }; + { + coordinate = (10, 11); + ground = Ocean; + tile_type = Water7; + c = None; + }; + { + coordinate = (10, 12); + ground = Ocean; + tile_type = Water7; + c = None; + }; + { + coordinate = (10, 13); + ground = Ocean; + tile_type = Water7; + c = None; + }; + { + coordinate = (10, 14); + ground = Ocean; + tile_type = Water10; + c = None; + }; + |]; + (*12th column*) + [| + { coordinate = (11, 0); ground = Ocean; tile_type = Water1; c = None }; + { coordinate = (11, 1); ground = Ocean; tile_type = Water2; c = None }; + { coordinate = (11, 2); ground = Plain; tile_type = Bridge; c = None }; + { coordinate = (11, 3); ground = Ocean; tile_type = Water2; c = None }; + { coordinate = (11, 4); ground = Ocean; tile_type = Water3; c = None }; + { coordinate = (11, 5); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (11, 6); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (11, 7); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (11, 8); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (11, 9); ground = Ocean; tile_type = Water9; c = None }; + { + coordinate = (11, 10); + ground = Ocean; + tile_type = Water7; + c = None; + }; + { + coordinate = (11, 11); + ground = Ocean; + tile_type = Water7; + c = None; + }; + { + coordinate = (11, 12); + ground = Ocean; + tile_type = Water7; + c = None; + }; + { + coordinate = (11, 13); + ground = Ocean; + tile_type = Water7; + c = None; + }; + { + coordinate = (11, 14); + ground = Ocean; + tile_type = Water7; + c = None; + }; + |]; + (*13th column*) + [| + { + coordinate = (12, 0); + ground = Mountain; + tile_type = Darkbush; + c = None; + }; + { coordinate = (12, 1); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (12, 2); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (12, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (12, 4); ground = Ocean; tile_type = Water4; c = None }; + { coordinate = (12, 5); ground = Plain; tile_type = Bridge; c = None }; + { coordinate = (12, 6); ground = Ocean; tile_type = Water3; c = None }; + { coordinate = (12, 7); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (12, 8); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (12, 9); ground = Ocean; tile_type = Water8; c = None }; + { + coordinate = (12, 10); + ground = Ocean; + tile_type = Water7; + c = None; + }; + { + coordinate = (12, 11); + ground = Ocean; + tile_type = Water7; + c = None; + }; + { + coordinate = (12, 12); + ground = Ocean; + tile_type = Water7; + c = None; + }; + { + coordinate = (12, 13); + ground = Ocean; + tile_type = Water7; + c = None; + }; + { + coordinate = (12, 14); + ground = Ocean; + tile_type = Water7; + c = None; + }; + |]; + (*14th column*) + [| + { + coordinate = (13, 0); + ground = Mountain; + tile_type = Darkbush; + c = None; + }; + { coordinate = (13, 1); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (13, 2); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (13, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (13, 4); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (13, 5); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (13, 6); ground = Ocean; tile_type = Water4; c = None }; + { coordinate = (13, 7); ground = Ocean; tile_type = Water1; c = None }; + { coordinate = (13, 8); ground = Ocean; tile_type = Water5; c = None }; + { coordinate = (13, 9); ground = Ocean; tile_type = Water7; c = None }; + { + coordinate = (13, 10); + ground = Ocean; + tile_type = Water7; + c = None; + }; + { + coordinate = (13, 11); + ground = Ocean; + tile_type = Water7; + c = None; + }; + { + coordinate = (13, 12); + ground = Ocean; + tile_type = Water7; + c = None; + }; + { + coordinate = (13, 13); + ground = Ocean; + tile_type = Water7; + c = None; + }; + { + coordinate = (13, 14); + ground = Ocean; + tile_type = Water7; + c = None; + }; + |]; + (*15th column*) + [| + { + coordinate = (14, 0); + ground = Mountain; + tile_type = Darkbush; + c = None; + }; + { + coordinate = (14, 1); + ground = Mountain; + tile_type = Darkbush; + c = None; + }; + { coordinate = (14, 2); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (14, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (14, 4); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (14, 5); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (14, 6); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (14, 7); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (14, 8); ground = Ocean; tile_type = Water6; c = None }; + { coordinate = (14, 9); ground = Ocean; tile_type = Water7; c = None }; + { + coordinate = (14, 10); + ground = Ocean; + tile_type = Water7; + c = None; + }; + { + coordinate = (14, 11); + ground = Ocean; + tile_type = Water7; + c = None; + }; + { + coordinate = (14, 12); + ground = Ocean; + tile_type = Water7; + c = None; + }; + { + coordinate = (14, 13); + ground = Ocean; + tile_type = Water7; + c = None; + }; + { + coordinate = (14, 14); + ground = Ocean; + tile_type = Water7; + c = None; + }; + |]; + |]; + } + +let map2 = + { + number = 2; + width = 15; + length = 15; + grid = + [| + (*first column*) + [| + { + coordinate = (0, 0); + ground = Mountain; + tile_type = Darkbush; + c = None; + }; + { + coordinate = (0, 1); + ground = Mountain; + tile_type = Darkbush; + c = None; + }; + { + coordinate = (0, 2); + ground = Mountain; + tile_type = Darkbush; + c = None; + }; + { coordinate = (0, 3); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (0, 4); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (0, 5); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (0, 6); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (0, 7); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (0, 8); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (0, 9); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (0, 10); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (0, 11); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (0, 12); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (0, 13); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (0, 14); ground = Forest; tile_type = Tree; c = None }; + |]; + (*second column*) + [| + { + coordinate = (1, 0); + ground = Mountain; + tile_type = Darkbush; + c = None; + }; + { + coordinate = (1, 1); + ground = Mountain; + tile_type = Darkbush; + c = None; + }; + { coordinate = (1, 2); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 4); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 5); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 6); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 7); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 8); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 9); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (1, 10); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 11); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 12); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 13); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (1, 14); ground = Forest; tile_type = Tree; c = None }; + |]; + (*third column*) + [| + { + coordinate = (2, 0); + ground = Mountain; + tile_type = Darkbush; + c = None; + }; + { coordinate = (2, 1); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 2); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 4); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (2, 5); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 6); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (2, 7); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 8); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 9); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 10); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 11); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 12); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 13); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 14); ground = Plain; tile_type = Grass; c = None }; + |]; + (*fourth column*) + [| + { coordinate = (3, 0); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (3, 1); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (3, 2); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (3, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (3, 4); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (3, 5); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (3, 6); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (3, 7); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (3, 8); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (3, 9); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (3, 10); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (3, 11); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (3, 12); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (3, 13); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (3, 14); ground = Plain; tile_type = Grass; c = None }; + |]; + (*fifth column*) + [| + { coordinate = (4, 0); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (4, 1); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (4, 2); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (4, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (4, 4); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (4, 5); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (4, 6); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (4, 7); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (4, 8); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (4, 9); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (4, 10); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (4, 11); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (4, 12); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (4, 13); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (4, 14); ground = Plain; tile_type = Grass; c = None }; + |]; + (*sixth column*) + [| + { coordinate = (5, 0); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (5, 1); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (5, 2); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (5, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (5, 4); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (5, 5); ground = Wall; tile_type = Castle1; c = None }; + { coordinate = (5, 6); ground = Wall; tile_type = Castle4; c = None }; + { coordinate = (5, 7); ground = Wall; tile_type = Castle7; c = None }; + { coordinate = (5, 8); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (5, 9); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (5, 10); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (5, 11); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (5, 12); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (5, 13); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (5, 14); ground = Forest; tile_type = Tree; c = None }; + |]; + (*seventh column*) + [| + { coordinate = (6, 0); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (6, 1); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (6, 2); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (6, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (6, 4); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (6, 5); ground = Wall; tile_type = Castle2; c = None }; + { coordinate = (6, 6); ground = Wall; tile_type = Castle4; c = None }; + { coordinate = (6, 7); ground = Wall; tile_type = Castle8; c = None }; + { coordinate = (6, 8); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (6, 9); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (6, 10); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (6, 11); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (6, 12); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (6, 13); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (6, 14); ground = Plain; tile_type = Grass; c = None }; + |]; + (*eigth column*) + [| + { coordinate = (7, 0); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (7, 1); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (7, 2); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (7, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (7, 4); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (7, 5); ground = Wall; tile_type = Castle3; c = None }; + { coordinate = (7, 6); ground = Wall; tile_type = Castle6; c = None }; + { coordinate = (7, 7); ground = Wall; tile_type = Castle9; c = None }; + { coordinate = (7, 8); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (7, 9); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (7, 10); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (7, 11); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (7, 12); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (7, 13); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (7, 14); ground = Plain; tile_type = Grass; c = None }; + |]; + (*9th column*) + [| + { coordinate = (8, 0); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (8, 1); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (8, 2); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (8, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (8, 4); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (8, 5); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (8, 6); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (8, 7); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (8, 8); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (8, 9); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (8, 10); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (8, 11); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (8, 12); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (8, 13); ground = Plain; tile_type = Grass; c = None }; + { + coordinate = (8, 14); + ground = Ocean; + tile_type = Water11; + c = None; + }; + |]; + (*10th column*) + [| + { coordinate = (9, 0); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (9, 1); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (9, 2); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (9, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (9, 4); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (9, 5); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (9, 6); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (9, 7); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (9, 8); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (9, 9); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (9, 10); ground = Plain; tile_type = Grass; c = None }; + { + coordinate = (9, 11); + ground = Ocean; + tile_type = Water11; + c = None; + }; + { coordinate = (9, 12); ground = Ocean; tile_type = Water2; c = None }; + { coordinate = (9, 13); ground = Plain; tile_type = Bridge; c = None }; + { + coordinate = (9, 14); + ground = Ocean; + tile_type = Water12; + c = None; + }; + |]; + (*11th column*) + [| + { coordinate = (10, 0); ground = Plain; tile_type = Tree; c = None }; + { coordinate = (10, 1); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (10, 2); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (10, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (10, 4); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (10, 5); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (10, 6); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (10, 7); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (10, 8); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (10, 9); ground = Plain; tile_type = Grass; c = None }; + { + coordinate = (10, 10); + ground = Ocean; + tile_type = Water11; + c = None; + }; + { + coordinate = (10, 11); + ground = Ocean; + tile_type = Water12; + c = None; + }; + { coordinate = (10, 12); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (10, 13); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (10, 14); ground = Plain; tile_type = Grass; c = None }; + |]; + (*12th column*) + [| + { coordinate = (11, 0); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (11, 1); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (11, 2); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (11, 3); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (11, 4); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (11, 5); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (11, 6); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (11, 7); ground = Plain; tile_type = Grass; c = None }; + { + coordinate = (11, 8); + ground = Ocean; + tile_type = Water11; + c = None; + }; + { coordinate = (11, 9); ground = Plain; tile_type = Bridge; c = None }; + { + coordinate = (11, 10); + ground = Ocean; + tile_type = Water12; + c = None; + }; + { coordinate = (11, 11); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (11, 12); ground = Wall; tile_type = House1; c = None }; + { coordinate = (11, 13); ground = Wall; tile_type = House4; c = None }; + { coordinate = (11, 14); ground = Plain; tile_type = Grass; c = None }; + |]; + (*13th column*) + [| + { coordinate = (12, 0); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (12, 1); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (12, 2); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (12, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (12, 4); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (12, 5); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (12, 6); ground = Forest; tile_type = Tree; c = None }; + { + coordinate = (12, 7); + ground = Ocean; + tile_type = Water11; + c = None; + }; + { + coordinate = (12, 8); + ground = Ocean; + tile_type = Water12; + c = None; + }; + { coordinate = (12, 9); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (12, 10); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (12, 11); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (12, 12); ground = Wall; tile_type = House2; c = None }; + { + coordinate = (12, 13); + ground = Village (Some temp_item); + tile_type = House5; + c = None; + }; + { coordinate = (12, 14); ground = Plain; tile_type = Grass; c = None }; + |]; + (*14th column*) + [| + { coordinate = (13, 0); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (13, 1); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (13, 2); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (13, 3); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (13, 4); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (13, 5); ground = Forest; tile_type = Tree; c = None }; + { + coordinate = (13, 6); + ground = Ocean; + tile_type = Water11; + c = None; + }; + { + coordinate = (13, 7); + ground = Ocean; + tile_type = Water12; + c = None; + }; + { coordinate = (13, 8); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (13, 9); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (13, 10); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (13, 11); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (13, 12); ground = Wall; tile_type = House3; c = None }; + { coordinate = (13, 13); ground = Wall; tile_type = House6; c = None }; + { coordinate = (13, 14); ground = Peaks; tile_type = Bush; c = None }; + |]; + (*15th column*) + [| + { + coordinate = (14, 0); + ground = Chest (Some bigfreakingsword); + tile_type = Chesttile; + c = None; + }; + { coordinate = (14, 1); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (14, 2); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (14, 3); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (14, 4); ground = Forest; tile_type = Tree; c = None }; + { + coordinate = (14, 5); + ground = Ocean; + tile_type = Water11; + c = None; + }; + { + coordinate = (14, 6); + ground = Ocean; + tile_type = Water12; + c = None; + }; + { coordinate = (14, 7); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (14, 8); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (14, 9); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (14, 10); ground = Forest; tile_type = Tree; c = None }; + { coordinate = (14, 11); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (14, 12); ground = Peaks; tile_type = Bush; c = None }; + { coordinate = (14, 13); ground = Peaks; tile_type = Bush; c = None }; + { coordinate = (14, 14); ground = Peaks; tile_type = Bush; c = None }; + |]; + |]; + } diff --git a/src/state.mli b/src/state.mli index dc47494..a5f6b8d 100644 --- a/src/state.mli +++ b/src/state.mli @@ -1,15 +1,13 @@ open Types open Interactions -val unit_menu: menu +val unit_menu : menu + val confirm_menu : menu -(** - * The type of the state of the game -*) type state = { player : character list; - enemies: character list; + enemies : character list; won : bool; lose : bool; mutable round : bool; @@ -23,38 +21,37 @@ type state = { menu_cursor : int; last_character : character option; } +(** + * The type of the state of the game +*) +val attack_range : character -> (int * int) list (** * Finds the attack range of a character *) -val attack_range : character -> (int * int) list - +val add_init_characters : character list -> map -> map (**[add_init_characters plst map] adds the characters in [plst] to [map]. *requires: * -[plst] is a list of characters * -[map] is the current map *) -val add_init_characters: character list -> map -> map - +val set_act_tile : state -> state (**[sea_act_tile st] sets the active_tile field of [st] to be *on one of the players in the player list in [st]. Also, sets *the last_character field to be that player. *requires: * -[st] is the current state *) -val set_act_tile: state -> state - +val set_init_ch_movement : character list -> state -> state (**[set_init_ch_movement plst st] sets the movement field appropriately for *each character in [plst]. *requires: * -[plst] is a list of characters * -[st] is the current state *) -val set_init_ch_movement: character list -> state -> state - -(**[do' act st] returns the state after an input action [act]*) val do' : state -> state +(**[do' act st] returns the state after an input action [act]*) diff --git a/test/test_state.ml b/test/test_state.ml index 785fc92..d4f94ea 100644 --- a/test/test_state.ml +++ b/test/test_state.ml @@ -5,37 +5,37 @@ open Ai let test = { - number=3; + number = 3; width = 3; length = 3; grid = [| [| - {coordinate = ( 0, 0); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 1, 0); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 2, 0); ground = Plain; tile_type = Grass;c=None}; + { coordinate = (0, 0); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 0); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 0); ground = Plain; tile_type = Grass; c = None }; |]; [| - {coordinate = ( 0, 1); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 1, 1); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 2, 1); ground = Plain; tile_type = Grass;c=None}; + { coordinate = (0, 1); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 1); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 1); ground = Plain; tile_type = Grass; c = None }; |]; [| - {coordinate = ( 0, 2); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 1, 2); ground = Plain; tile_type = Grass;c=None}; - {coordinate = ( 2, 2); ground = Plain; tile_type = Grass;c=None}; - |] - - |] + { coordinate = (0, 2); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (1, 2); ground = Plain; tile_type = Grass; c = None }; + { coordinate = (2, 2); ground = Plain; tile_type = Grass; c = None }; + |]; + |]; } + let temp_item = { - iname = "xd"; + iname = "xd"; wtype = Sword; mgt = 0; acc = 0; crit = 0; - range = (2,4); + range = (2, 4); uses = 5; cost = 0; sell = 0; @@ -44,14 +44,15 @@ let temp_item = effective = []; penalty = []; } + let temp_item2 = { - iname = "temp2"; + iname = "temp2"; wtype = Sword; mgt = 0; acc = 0; crit = 0; - range = (1,1); + range = (1, 1); uses = 5; cost = 0; sell = 0; @@ -62,54 +63,54 @@ let temp_item2 = } let temp_character = - { - name = "Lyn"; - stage= Ready; - class' = Paladin; - growths = []; - caps = []; - level = 0; - exp = 0; - health = (3,10); - allegiance = Player; - str = 25; - mag = 0; - def = 0; - spd = 0; - res = 0; - skl = 0; - lck = 0; - mov = 3; - con = 0; - aid = 0; - hit = 0; - atk = 25; - crit = 0; - avoid = 15; - inv = [|Some temp_item;None;None;None;None|]; - eqp = 0; - ability = []; - supports = []; - wlevels = [(Sword,'a',0)]; - ai = BossHunt; - behave = Hard; - location= (0,2); - movement= []; - attackable = []; - direction= South; - is_attacking=false; - } + { + name = "Lyn"; + stage = Ready; + class' = Paladin; + growths = []; + caps = []; + level = 0; + exp = 0; + health = (3, 10); + allegiance = Player; + str = 25; + mag = 0; + def = 0; + spd = 0; + res = 0; + skl = 0; + lck = 0; + mov = 3; + con = 0; + aid = 0; + hit = 0; + atk = 25; + crit = 0; + avoid = 15; + inv = [| Some temp_item; None; None; None; None |]; + eqp = 0; + ability = []; + supports = []; + wlevels = [ (Sword, 'a', 0) ]; + ai = BossHunt; + behave = Hard; + location = (0, 2); + movement = []; + attackable = []; + direction = South; + is_attacking = false; + } let enemy_1 = { name = "Mage Boss"; - stage= Ready; + stage = Ready; class' = Paladin; growths = []; caps = []; level = 0; exp = 0; - health = (7,10); + health = (7, 10); allegiance = Enemy; str = 0; mag = 0; @@ -125,23 +126,23 @@ let enemy_1 = atk = 0; crit = 0; avoid = 15; - inv = [|Some temp_item2;None;None;None;None|]; + inv = [| Some temp_item2; None; None; None; None |]; eqp = 0; ability = []; supports = []; - wlevels = [(Sword,'e',0)]; + wlevels = [ (Sword, 'e', 0) ]; ai = BossHunt; behave = Insane; - location= (2,2); - movement= []; + location = (2, 2); + movement = []; attackable = []; - direction= South; - is_attacking=false + direction = South; + is_attacking = false; } let init_state = - let p = [temp_character] in - let e = [enemy_1] in + let p = [ temp_character ] in + let e = [ enemy_1 ] in let x = { player = p; @@ -150,7 +151,8 @@ let init_state = won = false; round = false; welcome = true; - active_tile = {coordinate = (1,1); ground = Plain; tile_type = Grass;c=None}; + active_tile = + { coordinate = (1, 1); ground = Plain; tile_type = Grass; c = None }; active_unit = None; active_item = -1; act_map = add_init_characters (List.rev_append p e) test; @@ -159,22 +161,35 @@ let init_state = menu_active = false; menu_cursor = 0; last_character = None; - } in x|>set_init_ch_movement x.player|>set_init_ch_movement x.enemies|>set_act_tile + } + in + x + |> set_init_ch_movement x.player + |> set_init_ch_movement x.enemies + |> set_act_tile let st = init_state -let tests = [ - "not_win">:: (fun _ -> assert_equal false st.won); - "not_transition">:: (fun _ -> assert_equal false st.round); - "menu_cursor 0">:: (fun _ -> assert_equal 0 st.menu_cursor); - "test_player">:: (fun _ -> assert_equal None (st.active_unit)); - "enemy_move">:: (fun _ -> assert_equal false ((1, 2) = - (step st.enemies st.player st.act_map; - enemy_1.location))); - "enemy_move">:: (fun _ -> assert_equal false (step st.enemies st.player st.act_map; - fst enemy_1.health = snd enemy_1.health)); - "step_test">:: (fun _ -> assert_equal () (step st.enemies st.player st.act_map)) -] -let suite = - "FE state test suite">::: tests +let tests = + [ + ("not_win" >:: fun _ -> assert_equal false st.won); + ("not_transition" >:: fun _ -> assert_equal false st.round); + ("menu_cursor 0" >:: fun _ -> assert_equal 0 st.menu_cursor); + ("test_player" >:: fun _ -> assert_equal None st.active_unit); + ( "enemy_move" >:: fun _ -> + assert_equal false + ((1, 2) + = + (step st.enemies st.player st.act_map; + enemy_1.location)) ); + ( "enemy_move" >:: fun _ -> + assert_equal false + (step st.enemies st.player st.act_map; + fst enemy_1.health = snd enemy_1.health) ); + ( "step_test" >:: fun _ -> + assert_equal () (step st.enemies st.player st.act_map) ); + ] + +let suite = "FE state test suite" >::: tests + let _ = run_test_tt_main suite