summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJérémy Zurcher <jeremy@asynk.ch>2020-07-19 21:48:21 +0200
committerJérémy Zurcher <jeremy@asynk.ch>2020-07-19 21:48:21 +0200
commitdc4c8275bf7fe7b22783b5ed366e3eb9c0b83a5b (patch)
treed8304166c647f39b564d078bf085bb31a45bc21b
parentfcfcddfdae168cd42491210528ff51f476b4dfb8 (diff)
downloadgodot-hexgrid-dc4c8275bf7fe7b22783b5ed366e3eb9c0b83a5b.zip
godot-hexgrid-dc4c8275bf7fe7b22783b5ed366e3eb9c0b83a5b.tar.gz
implement range Of Influence
-rw-r--r--Hex.gd14
-rw-r--r--HexBoard.gd55
-rw-r--r--Piece.gd11
-rw-r--r--Tile.gd15
-rw-r--r--Unit.gd12
5 files changed, 106 insertions, 1 deletions
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