From dc4c8275bf7fe7b22783b5ed366e3eb9c0b83a5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Zurcher?= Date: Sun, 19 Jul 2020 21:48:21 +0200 Subject: implement range Of Influence --- Hex.gd | 14 +++++++++++++- HexBoard.gd | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ Piece.gd | 11 +++++++++++ Tile.gd | 15 +++++++++++++++ Unit.gd | 12 ++++++++++++ 5 files changed, 106 insertions(+), 1 deletion(-) diff --git a/Hex.gd b/Hex.gd index 1e343b7..77b867e 100644 --- a/Hex.gd +++ b/Hex.gd @@ -37,7 +37,19 @@ func height() -> int: return 0 func elevation() -> int: - if type == 2: return 2 + if type == 2: return 3 + return 0 + +func range_modifier(category : int) -> int: + return (1 if type == 2 else 0) + +func attack_modifier(category : int, orientation : int) -> int: + return (2 if type == 1 else 0) + +func defense_value(category : int, orientation : int) -> int: + if type == 0: return 2 + elif type == 1: return 1 + elif type == 2: return 1 return 0 func block_los(from : Tile, to : Tile, d : float, dt : float) -> bool: diff --git a/HexBoard.gd b/HexBoard.gd index 0bc6fa1..ab52dd6 100644 --- a/HexBoard.gd +++ b/HexBoard.gd @@ -92,6 +92,36 @@ func opposite(o : int) -> int: if o <= Orientation.NW: return o << 4 return o >> 4 +# return the Orientation given to distant Tiles +# Orientation is combined in case of diagonals +func distant_orientation(from : Tile, to : Tile) -> int: + var a : float = rad2deg((to.position - from.position).angle()) + if a < 0: a += 360 + a = int(a * 10) / 10.0 + for k in angles.keys(): + var z : int = angles[k] + if a >= (z + 30 - DEGREE_ADJ) and a <= (z + 30 + DEGREE_ADJ): + # diagonal + var p : int = k >> 1 + if p == 0: p = Orientation.SE + if not angles.has(p): return k | p >> 1 # v : N S and not v : W E + else: return (k | p) + elif (z == 30 and (a < DEGREE_ADJ or a > 360 - DEGREE_ADJ)): + return Orientation.NE | Orientation.SE + elif a >= (z - 30) and a <= (z + 30): + return k + if angles.has(Orientation.E) and a > 330 and a <= 360: + return Orientation.E + return -1 + +# return the opposite of a possibly combined given Orientation +func distant_opposite(o : int) -> int: + var r : int = 0 + for k in angles.keys(): + if (k & o) == k: + r |= opposite(k) + return r + # return the key of a given col;row coordinate func key(coords : Vector2) -> int: if not is_on_map(coords): return -1 @@ -468,3 +498,28 @@ func shortest_path(piece : Piece, from : Tile, to : Tile, tiles : Array) -> int t = t.parent tiles.push_front(from) return tiles.size() + +func range_of_influence(piece : Piece, from : Tile, category : int, tiles : Array) -> int: + tiles.clear() + var max_range : int = piece.max_range_of_fire(category, from) + if not is_on_map(from.coords): return 0 + var tmp : Array = [] + search_count += 1 + from.search_count = search_count + stack.push_back(from) + while(not stack.empty()): + var src : Tile = stack.pop_back() + # warning-ignore:return_value_discarded + build_adjacents(src.coords) + for dst in adjacents: + if not dst.on_board: continue + if dst.search_count == search_count: continue + dst.search_count = search_count + var d : int = int(distance(from.coords, dst.coords, false)) + if d > max_range: continue + if line_of_sight(from.coords, dst.coords, tmp).x != -1: continue + var o : int = distant_orientation(from, dst) + dst.f = piece.volume_of_fire(category, d, from, o, dst, distant_opposite(o)) + stack.push_back(dst) + tiles.append(dst) + return tiles.size() diff --git a/Piece.gd b/Piece.gd index 1a9e357..8725cc2 100644 --- a/Piece.gd +++ b/Piece.gd @@ -22,3 +22,14 @@ func move_cost(src : Tile, dst : Tile, orientation : int) -> int: func at_least_one_tile(dst : Tile) -> bool: print("Piece#at_least_one_tile() must be overriden in a subclass") return true + +# the maximum range of fire with a given category of weapon +func max_range_of_fire(category : int, from : Tile) -> int: + print("Piece#max_range_of_fire() must be overriden in a subclass") + return 0 + +# the projected volume of fire with a given category of weapon at a given distance, +# out of a given Tile with a given orientation, into a given Tile with a given orientation +func volume_of_fire(category : int, distance : int, src : Tile, src_o : int, dst : Tile, dst_o : int) -> int: + print("Piece#volume_of_fire() must be overriden in a subclass") + return -1 # out of range diff --git a/Tile.gd b/Tile.gd index a3285e5..bee8b6a 100644 --- a/Tile.gd +++ b/Tile.gd @@ -35,6 +35,21 @@ func block_los(from : Tile, to : Tile, d : float, dt : float) -> bool: print("Tile#block_los() must be overriden in a subclass") return false +# range value modifier when firing out of this tile with a given category of weapon +func range_modifier(category : int) -> int: + print("Tile#range_modifier() must be overriden in a subclass") + return 0 + +# attack value modifier when firing out of this tile with a given category of weapon with a given orientation +func attack_modifier(category : int, orientation : int) -> int: + print("Tile#attack_modifier() must be overriden in a subclass") + return 0 + +# defense value provided by this tile against a given category of weapon incoming from a given orientation +func defense_value(category : int, orientation : int) -> int: + print("Tile#defense_value() must be overriden in a subclass") + return 0 + func enable_overlay(i :int, v : bool) -> void: get_child(i).visible = v if v: visible = true diff --git a/Unit.gd b/Unit.gd index e699f61..0b67053 100644 --- a/Unit.gd +++ b/Unit.gd @@ -11,3 +11,15 @@ func road_march_bonus() -> int: func move_cost(src : Tile, dst : Tile, orientation : int) -> int: return (1 if (src.has_road(orientation) and dst.type != 3) else dst.cost()) + +func max_range_of_fire(category : int, from : Tile) -> int: + return 6 + from.range_modifier(category) + +func volume_of_fire(category : int, distance : int, src : Tile, src_o : int, dst : Tile, dst_o : int) -> int: + var fp : int = 10 + if distance > 6: return -1 + elif distance > 4: fp = 4 + elif distance > 2: fp = 7 + fp -= src.attack_modifier(category, src_o) + fp -= dst.defense_value(category, dst_o) + return fp -- cgit v1.1-2-g2b99