diff --git a/TODO.md b/TODO.md index 038d82f..b7f45ab 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,7 @@ 1. Power ups - * 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 + * spawn a new random piece powerup 2. Visual polish + * a visual / title in the left sidebar * multiple square tiles to add variation * make the help text indicate (flash, etc.) * visual indications when damage is done but a unit isn't killed @@ -9,7 +9,10 @@ 3. Sound effects * on hit, especially when the unit isn't killed * if possible, a small bit of background music -4. New units +4. Gameplay additions: + * powerups: change movement type, remove pawn's attack and movement restrictions + * new units + * choose difference board sizes 5. Further visual polish * animate the piece making the attack, and returning to it's spot diff --git a/assets/export/powerup.png b/assets/export/powerup.png new file mode 100644 index 0000000..af1391c Binary files /dev/null and b/assets/export/powerup.png differ diff --git a/src/Game.gd b/src/Game.gd index 60d2151..e8c5fe2 100644 --- a/src/Game.gd +++ b/src/Game.gd @@ -261,6 +261,7 @@ func _ready(): get_node("/root/Game/EndMenu/VBoxContainer/Fail Game").connect("pressed", self, "_on_fail_game") get_node("/root/Game/EndMenu/VBoxContainer/Win Game").connect("pressed", self, "_on_win_game") get_node("/root/Game/PanelRight/VBox/PieceInfo").connect("stat_change_requested", self, "_on_piece_stat_change_requested") + get_node("/root/Game/PanelRight/VBox/PieceInfo/Vbox/Powerup").connect("pressed", self, "try_spawn_powerup") reset_game_state() func _on_piece_stat_change_requested(piece, attribute, value): @@ -308,6 +309,7 @@ func reset_game_state(): "y": y, "piece": null, "reinforcement": null, + "powerup": null, } y += 1 x += 1 @@ -535,6 +537,8 @@ func _process(delta): target_square = square square['piece'] = null target_square['piece'] = self.ai_piece + if target_square['powerup'] != null: + apply_powerup_to_piece(target_square) self.ai_piece.set_position(Vector2(target_square['x']*128, target_square['y']*128)) self.ai_piece.at_spawn = false self.ai_target = null @@ -608,6 +612,7 @@ func _physics_process(delta): dest_square['piece'].queue_free() square['piece'].kills += 1 get_node("PanelRight/VBox/PieceInfo").set_piece_info(square['piece']) + self.try_spawn_powerup() var c = self.rng.randi() % 100 var index_to_play = null for idx in self.on_ai_lose_piece.keys(): @@ -624,6 +629,8 @@ func _physics_process(delta): dest_square = square square['piece'] = null dest_square['piece'] = piece + if dest_square['powerup'] != null: + apply_powerup_to_piece(dest_square) piece.set_position(Vector2(dest_square['x']*128, dest_square['y']*128)) piece.at_spawn = false self._on_phase_end() @@ -671,3 +678,86 @@ func _on_StopThat_finished(): func _on_SkipTurnButton_pressed(): self._on_phase_end() + +var available_powerups = { + 55: { + "attribute": "health", + "value": "increase", + "description": "Increase health", + }, + 65: { + "attribute": "damage", + "value": "increase", + "description": "Increase damage", + }, + 75: { + "attribute": "speed", + "value": "increase", + "description": "Increase speed", + }, + 85: { + "attribute": "jump", + "value": "set_true", + "description": "Allow unit to jump", + }, + 95: { + "attribute": "special", + "value": "spawn_unit", + "description": "Spawn a new piece", + } + # @TODO remove attack_only from pawn + # @TODO choose a new movement pattern +} +func try_spawn_powerup(): + print('blah') + var try = 0 + var i = null + var sq = null + while try < 10: + i = self.rng.randi() % (self.height * self.width) + sq = self.board_squares[Vector2(i % self.width, floor(i / self.height))] + if sq['piece'] == null and sq['powerup'] == null: + break + try += 1 + if sq == null: + print("Failed to spawn powerup after 10 tries") + return + i = null + var c = self.rng.randi() % 100 + print("Chance: ", c) + for k in self.available_powerups.keys(): + if c >= k: + i = k + if i == null: + return + print("Attempting to spawn powerup: ", self.available_powerups[i], " at square ", sq) + var powerup = ResourceLoader.load("res://src/Powerup.tscn").instance() + powerup.initialize( + self.available_powerups[i]['attribute'], + self.available_powerups[i]['value'], + self.available_powerups[i]['description'] + ) + powerup.add_to_group("powerups") + var pf = get_node("/root/Game/MarginContainer/Playfield") + pf.add_child(powerup) + # @TODO Set position + powerup.set_position(Vector2( + sq['x'] * 128, + sq['y'] * 128 + )) + sq['powerup'] = powerup + # @TODO Play a sound when a powerup spawns + +func apply_powerup_to_piece(square): + print("Applying powerup ", square['powerup'], " to piece ", square['piece']) + # @TODO Play a sound + if square['powerup'].target_attribute == "special": + print("Special powerups not implemented yet") + else: + if square['powerup'].target_value == "increase": + var value = square['piece'].get(square['powerup'].target_attribute) + 1 + square['piece'].set(square['powerup'].target_attribute, value) + if square['piece'] == self.selected_piece: + get_node("/root/Game/PanelRight/VBox/PieceInfo").set_piece_info(square['piece']) + square['powerup'].queue_free() + square['powerup'] = null diff --git a/src/PieceDetails.tscn b/src/PieceDetails.tscn index 14b3fe5..e28259e 100644 --- a/src/PieceDetails.tscn +++ b/src/PieceDetails.tscn @@ -145,6 +145,12 @@ margin_top = 455.0 margin_right = 190.0 margin_bottom = 495.0 text = "Jump" + +[node name="Powerup" type="Button" parent="Vbox"] +margin_top = 499.0 +margin_right = 190.0 +margin_bottom = 519.0 +text = "Spawn powerup" [connection signal="pressed" from="Vbox/UpMovement" to="." method="_on_UpMovement_pressed"] [connection signal="pressed" from="Vbox/UpHealth" to="." method="_on_UpHealth_pressed"] [connection signal="pressed" from="Vbox/UpDamage" to="." method="_on_UpDamage_pressed"] diff --git a/src/Powerup.gd b/src/Powerup.gd new file mode 100644 index 0000000..700fa23 --- /dev/null +++ b/src/Powerup.gd @@ -0,0 +1,20 @@ +extends Node2D + +var target_attribute +var target_value +# Declare member variables here. Examples: +# var a = 2 +# var b = "text" + +func initialize(attribute, value, text): + self.target_attribute = attribute + self.target_value = value + get_node("Control").set_tooltip(text) +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +#func _process(delta): +# pass diff --git a/src/Powerup.tscn b/src/Powerup.tscn new file mode 100644 index 0000000..8b39779 --- /dev/null +++ b/src/Powerup.tscn @@ -0,0 +1,32 @@ +[gd_scene load_steps=5 format=2] + +[ext_resource path="res://src/black_hilight_2px.tres" type="Material" id=1] +[ext_resource path="res://assets/export/powerup.png" type="Texture" id=2] +[ext_resource path="res://src/Powerup.gd" type="Script" id=3] + +[sub_resource type="RectangleShape2D" id=1] + +[node name="Node2D" type="Node2D"] +modulate = Color( 0.270588, 0.858824, 0.792157, 1 ) +material = ExtResource( 1 ) +script = ExtResource( 3 ) + +[node name="Sprite" type="Sprite" parent="."] +material = ExtResource( 1 ) +texture = ExtResource( 2 ) + +[node name="Area2D" type="Area2D" parent="."] +scale = Vector2( 3, 3 ) + +[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"] +shape = SubResource( 1 ) + +[node name="Control" type="Control" parent="."] +margin_left = -27.0 +margin_top = -28.0 +margin_right = 27.0 +margin_bottom = 28.0 +hint_tooltip = "Powerup" +__meta__ = { +"_edit_use_anchors_": false +}