Add enemy respawns
This commit is contained in:
parent
911bceb750
commit
d22224a818
14
TODO.md
14
TODO.md
|
@ -1,22 +1,18 @@
|
||||||
1. Enemy respawns
|
1. Power ups
|
||||||
* every now and again, the opponents has new units that spawn
|
|
||||||
* indicator to show respawn is nearing
|
|
||||||
* is it all the missing units, or a chance for each?
|
|
||||||
2. Power ups
|
|
||||||
* a chance of having power ups spawn on an random unoccupied square when a unit dies
|
* a chance of having power ups spawn on an random unoccupied square when a unit dies
|
||||||
* +health, +attack, +speed, +jump, (pawn only) remove "attack_only", spawn a new (random?) piece, change movement type
|
* +health, +attack, +speed, +jump, (pawn only) remove "attack_only", spawn a new (random?) piece, change movement type
|
||||||
* then the enemy respawns units, their new units are stronger
|
* then the enemy respawns units, their new units are stronger
|
||||||
* support for pieces with multiple hit points
|
* support for pieces with multiple hit points
|
||||||
* unit info panel
|
* unit info panel
|
||||||
3. Visual polish
|
2. Visual polish
|
||||||
* clean up tile borders
|
* clean up tile borders
|
||||||
* multiple square tiles to add variation
|
* multiple square tiles to add variation
|
||||||
* make the help text indicate (flash, etc.)
|
* make the help text indicate (flash, etc.)
|
||||||
4. Sound effects
|
3. Sound effects
|
||||||
* on hit
|
* on hit
|
||||||
* on piece lost
|
* on piece lost
|
||||||
* on piece kill
|
* on piece kill
|
||||||
* on opponent victory
|
* on opponent victory
|
||||||
* if possible, a small bit of background music
|
* if possible, a small bit of background music
|
||||||
5. Further visual polish
|
4. Further visual polish
|
||||||
6. New units
|
5. New units
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 892 B After Width: | Height: | Size: 891 B |
97
src/Game.gd
97
src/Game.gd
|
@ -32,6 +32,9 @@ var flash_help = null
|
||||||
var rng = null
|
var rng = null
|
||||||
var ai_target = null
|
var ai_target = null
|
||||||
var ai_piece = null
|
var ai_piece = null
|
||||||
|
var reinforcements = null
|
||||||
|
var reinforcements_size = 0
|
||||||
|
var reinforcements_coords = []
|
||||||
|
|
||||||
const piece_types = {
|
const piece_types = {
|
||||||
"pawn": "res://src/pieces/Pawn.tscn",
|
"pawn": "res://src/pieces/Pawn.tscn",
|
||||||
|
@ -165,7 +168,7 @@ func _on_piece_click(piece, event):
|
||||||
if piece == null:
|
if piece == null:
|
||||||
self.selected_piece = null
|
self.selected_piece = null
|
||||||
return
|
return
|
||||||
print("Selected piece: ", piece)
|
#print("Selected piece: ", piece)
|
||||||
if piece.is_in_group("player"):
|
if piece.is_in_group("player"):
|
||||||
piece.get_node("Body").set_modulate(Color(0, 1, 0, 1))
|
piece.get_node("Body").set_modulate(Color(0, 1, 0, 1))
|
||||||
else:
|
else:
|
||||||
|
@ -278,7 +281,8 @@ func reset_game_state():
|
||||||
self.board_squares[Vector2(x, y)] = {
|
self.board_squares[Vector2(x, y)] = {
|
||||||
"x": x,
|
"x": x,
|
||||||
"y": y,
|
"y": y,
|
||||||
"piece": null
|
"piece": null,
|
||||||
|
"reinforcement": null,
|
||||||
}
|
}
|
||||||
y += 1
|
y += 1
|
||||||
x += 1
|
x += 1
|
||||||
|
@ -321,13 +325,97 @@ func _on_phase_end():
|
||||||
self.current_state += 1;
|
self.current_state += 1;
|
||||||
if not self.current_state in self.states.keys():
|
if not self.current_state in self.states.keys():
|
||||||
self.current_state = 0
|
self.current_state = 0
|
||||||
self.turn += 1
|
|
||||||
self._on_new_turn()
|
self._on_new_turn()
|
||||||
get_node("TopBar/Bottom/Instruction").set_text(
|
get_node("TopBar/Bottom/Instruction").set_text(
|
||||||
self.states[self.current_state]["description"] + " - " + self.states[self.current_state]["directive"]
|
self.states[self.current_state]["description"] + " - " + self.states[self.current_state]["directive"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func choose_reinforcements(size, opponent: bool = true, at_spawn = true):
|
||||||
|
var min_square = 0
|
||||||
|
var max_square = (self.height * self.width) - 1
|
||||||
|
if at_spawn:
|
||||||
|
max_square = (self.width)*2 - 1
|
||||||
|
var range_size = max_square - min_square
|
||||||
|
var arrival_coords = []
|
||||||
|
var n = 0
|
||||||
|
while n < size:
|
||||||
|
var try = 0
|
||||||
|
var square_index = 0
|
||||||
|
var square = null
|
||||||
|
while try < 10:
|
||||||
|
# Try to get an unoccupied square
|
||||||
|
square_index = self.rng.randi() % range_size
|
||||||
|
var square_coord = Vector2(
|
||||||
|
floor(square_index % self.width), floor(square_index / self.width)
|
||||||
|
)
|
||||||
|
if at_spawn and not opponent:
|
||||||
|
square_coord.y += self.height - 2
|
||||||
|
square = self.board_squares[square_coord]
|
||||||
|
if square['piece'] == null and square['reinforcement'] == null:
|
||||||
|
# unoccupied, we'll take it
|
||||||
|
arrival_coords.append(square_coord)
|
||||||
|
var types = self.piece_types.keys()
|
||||||
|
square['reinforcement'] = types[self.rng.randi()%types.size()]
|
||||||
|
break
|
||||||
|
# occupied, try again
|
||||||
|
square = null
|
||||||
|
try += 1
|
||||||
|
if square == null:
|
||||||
|
print("Failed to find a spot to spawn reinforcement")
|
||||||
|
n += 1
|
||||||
|
return arrival_coords
|
||||||
|
|
||||||
func _on_new_turn():
|
func _on_new_turn():
|
||||||
|
self.turn += 1
|
||||||
|
var just_spawned = false
|
||||||
|
if self.reinforcements != null:
|
||||||
|
var pf = get_node("/root/Game/MarginContainer/Playfield")
|
||||||
|
self.reinforcements -= 1
|
||||||
|
if self.reinforcements == 1:
|
||||||
|
# decide on what will arrive
|
||||||
|
self.reinforcements_coords = choose_reinforcements(self.reinforcements_size)
|
||||||
|
# show the player where they will arrive
|
||||||
|
for coord in self.reinforcements_coords:
|
||||||
|
pf.squares[coord].get_ref().set_reinforcement(self.board_squares[coord]['reinforcement'])
|
||||||
|
print("Reinforcement at coord ", coord, ": ", self.board_squares[coord]['reinforcement'])
|
||||||
|
get_node("BottomBar/Help").set_text("Reinforcement arrival locations analyzed")
|
||||||
|
self.flash_help = 3
|
||||||
|
elif self.reinforcements == 0:
|
||||||
|
# spawn them
|
||||||
|
for coord in self.reinforcements_coords:
|
||||||
|
pf.squares[coord].get_ref().set_reinforcement(null)
|
||||||
|
var square = self.board_squares[coord]
|
||||||
|
if square['piece'] == null:
|
||||||
|
new_piece(square['reinforcement'], "opponent", coord)
|
||||||
|
else:
|
||||||
|
print("Reinforcement arrival at ", coord, " blocked by piece!")
|
||||||
|
get_node("BottomBar/Help").set_text("Reinforcement at " + str(coord) + " telefragged.")
|
||||||
|
self.flash_help = 2
|
||||||
|
square['reinforcement'] = null
|
||||||
|
just_spawned = true
|
||||||
|
self.reinforcements = null
|
||||||
|
self.reinforcements_size = 0
|
||||||
|
self.reinforcements_coords = []
|
||||||
|
|
||||||
|
# Check for reinforcements
|
||||||
|
var opponent_pieces = get_tree().get_nodes_in_group("opponent")
|
||||||
|
# @TODO hardcoded value for number of pieces a side should have on the board
|
||||||
|
# If they are less than 1/4 strength ensure that reinforcements are queued
|
||||||
|
if opponent_pieces.size() <= 3 and self.reinforcements == null:
|
||||||
|
self.reinforcements = 2 # 2 turns away
|
||||||
|
self.reinforcements_size = 4
|
||||||
|
get_node("BottomBar/Help").set_text("Multiple opponent reinforcements detected inbound")
|
||||||
|
self.flash_help = 3
|
||||||
|
if self.reinforcements == null and not just_spawned:
|
||||||
|
var chance = lerp(0, 50, 1 - float(opponent_pieces.size())/16.0)
|
||||||
|
var i = self.rng.randi() % 100
|
||||||
|
print("Roll for reinforcements ", i, " < ", chance)
|
||||||
|
if i < chance:
|
||||||
|
self.reinforcements = 2
|
||||||
|
self.reinforcements_size = 1
|
||||||
|
get_node("BottomBar/Help").set_text("Inbound opponent reinforcements detected")
|
||||||
|
self.flash_help = 3
|
||||||
|
|
||||||
get_node("TopBar/Top/HBoxContainer/Turn").set_text(str(self.turn))
|
get_node("TopBar/Top/HBoxContainer/Turn").set_text(str(self.turn))
|
||||||
|
|
||||||
func _reset_help():
|
func _reset_help():
|
||||||
|
@ -341,7 +429,8 @@ func _process(delta):
|
||||||
else:
|
else:
|
||||||
self._reset_help()
|
self._reset_help()
|
||||||
self.flash_help = null
|
self.flash_help = null
|
||||||
if get_tree().get_nodes_in_group("opponent").empty() or get_tree().get_nodes_in_group("player").empty():
|
var opponent_pieces = get_tree().get_nodes_in_group("opponent")
|
||||||
|
if opponent_pieces.empty() or get_tree().get_nodes_in_group("player").empty():
|
||||||
# The game is over
|
# The game is over
|
||||||
self.current_state = 99
|
self.current_state = 99
|
||||||
var player_victory = false
|
var player_victory = false
|
||||||
|
|
|
@ -40,7 +40,7 @@ func _input(event):
|
||||||
get_tree().set_input_as_handled()
|
get_tree().set_input_as_handled()
|
||||||
else:
|
else:
|
||||||
if self.last_click != null and self.last_click <= CLICK_THRESHOLD:
|
if self.last_click != null and self.last_click <= CLICK_THRESHOLD:
|
||||||
print("Click: ", self, event)
|
#print("Click: ", self, event)
|
||||||
emit_signal("click", self, event)
|
emit_signal("click", self, event)
|
||||||
# Work-around bug where only the last signal is connected
|
# Work-around bug where only the last signal is connected
|
||||||
# to the Game
|
# to the Game
|
||||||
|
@ -52,7 +52,7 @@ func _input(event):
|
||||||
get_tree().set_input_as_handled()
|
get_tree().set_input_as_handled()
|
||||||
if not event.pressed and self.hold_started:
|
if not event.pressed and self.hold_started:
|
||||||
emit_signal("hold_stop", self, event)
|
emit_signal("hold_stop", self, event)
|
||||||
print("Hold stop", self, " ", event)
|
#print("Hold stop", self, " ", event)
|
||||||
self.cancel_hold()
|
self.cancel_hold()
|
||||||
get_tree().set_input_as_handled()
|
get_tree().set_input_as_handled()
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ func _process(delta):
|
||||||
self.last_click += delta
|
self.last_click += delta
|
||||||
if not self.hold_started and self.last_click >= self.CLICK_THRESHOLD:
|
if not self.hold_started and self.last_click >= self.CLICK_THRESHOLD:
|
||||||
self.hold_started = true;
|
self.hold_started = true;
|
||||||
print("Hold start", self, " ", null)
|
#print("Hold start", self, " ", null)
|
||||||
emit_signal("hold_start", self, null)
|
emit_signal("hold_start", self, null)
|
||||||
if self.hold_started:
|
if self.hold_started:
|
||||||
self.set_global_position(get_viewport().get_mouse_position())
|
self.set_global_position(get_viewport().get_mouse_position())
|
||||||
|
|
|
@ -29,6 +29,7 @@ func initialize(width: int = 8, height: int = 8):
|
||||||
# @TODO any tweaks to the node by calling custom function initialize()
|
# @TODO any tweaks to the node by calling custom function initialize()
|
||||||
instance.translate(Vector2(128*i, 128*j))
|
instance.translate(Vector2(128*i, 128*j))
|
||||||
self.squares[Vector2(i, j)] = weakref(instance)
|
self.squares[Vector2(i, j)] = weakref(instance)
|
||||||
|
instance.get_node("Control").set_tooltip(str(Vector2(i, j)))
|
||||||
add_child(instance)
|
add_child(instance)
|
||||||
j += 1
|
j += 1
|
||||||
i += 1
|
i += 1
|
||||||
|
|
|
@ -5,11 +5,41 @@ class_name Square
|
||||||
# var a = 2
|
# var a = 2
|
||||||
# var b = "text"
|
# var b = "text"
|
||||||
|
|
||||||
|
var reinforcement = null
|
||||||
|
var timer = 0
|
||||||
|
const FLASH_FREQUENCY = 2 # seconds
|
||||||
|
const FLASH_MIN = Color(1, 0.75, 0.75, 1)
|
||||||
|
const FLASH_MAX = Color(1, 0.5, 0.5, 1)
|
||||||
|
const DEFAULT_BODY = Color(1, 1, 1, 1)
|
||||||
# Called when the node enters the scene tree for the first time.
|
# Called when the node enters the scene tree for the first time.
|
||||||
func _ready():
|
func _ready():
|
||||||
pass # Replace with function body.
|
pass # Replace with function body.
|
||||||
|
|
||||||
|
func set_reinforcement(reinforcement):
|
||||||
|
self.reinforcement = reinforcement
|
||||||
|
self.timer = 0
|
||||||
|
print("Set reinforcement on ", self, " : ", reinforcement)
|
||||||
|
if reinforcement == null:
|
||||||
|
get_node("Body").set_modulate(DEFAULT_BODY)
|
||||||
|
get_node("Control").set_tooltip("")
|
||||||
|
else:
|
||||||
|
get_node("Control").set_tooltip("Arriving unit: " + reinforcement)
|
||||||
|
|
||||||
|
func _process(delta):
|
||||||
|
if self.reinforcement != null:
|
||||||
|
self.timer += delta
|
||||||
|
if self.timer >= FLASH_FREQUENCY*2:
|
||||||
|
self.timer = 0
|
||||||
|
if self.timer >= FLASH_FREQUENCY:
|
||||||
|
# Going from dark to light
|
||||||
|
get_node("Body").set_modulate(
|
||||||
|
lerp(FLASH_MIN, FLASH_MAX, 1-((self.timer-FLASH_FREQUENCY)/FLASH_FREQUENCY))
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Going from light to dark
|
||||||
|
get_node("Body").set_modulate(
|
||||||
|
lerp(FLASH_MIN, FLASH_MAX, self.timer / FLASH_FREQUENCY)
|
||||||
|
)
|
||||||
|
|
||||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||||
#func _process(delta):
|
#func _process(delta):
|
||||||
|
|
|
@ -19,6 +19,16 @@ modulate = Color( 0.12549, 0.0980392, 0.0980392, 1 )
|
||||||
texture = ExtResource( 1 )
|
texture = ExtResource( 1 )
|
||||||
|
|
||||||
[node name="Area2D" type="Area2D" parent="."]
|
[node name="Area2D" type="Area2D" parent="."]
|
||||||
|
visible = false
|
||||||
|
|
||||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"]
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"]
|
||||||
|
visible = false
|
||||||
shape = SubResource( 1 )
|
shape = SubResource( 1 )
|
||||||
|
|
||||||
|
[node name="Control" type="Control" parent="."]
|
||||||
|
margin_right = 40.0
|
||||||
|
margin_bottom = 40.0
|
||||||
|
hint_tooltip = "Square"
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue