Slot na rakiety
This commit is contained in:
parent
897123c7c8
commit
0c9f812cfe
@ -1,4 +1,4 @@
|
|||||||
[gd_resource type="Resource" script_class="ItemAffixDatabase" load_steps=13 format=3]
|
[gd_resource type="Resource" script_class="ItemAffixDatabase" load_steps=14 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/items/item_affix_database.gd" id="1_database"]
|
[ext_resource type="Script" path="res://scripts/items/item_affix_database.gd" id="1_database"]
|
||||||
[ext_resource type="Script" path="res://scripts/items/item_affix_definition.gd" id="2_type"]
|
[ext_resource type="Script" path="res://scripts/items/item_affix_definition.gd" id="2_type"]
|
||||||
@ -13,6 +13,8 @@
|
|||||||
[ext_resource type="Resource" path="res://resources/items/affixes/critical_chance_percent.tres" id="11_affix"]
|
[ext_resource type="Resource" path="res://resources/items/affixes/critical_chance_percent.tres" id="11_affix"]
|
||||||
[ext_resource type="Resource" path="res://resources/items/affixes/critical_damage_percent.tres" id="12_affix"]
|
[ext_resource type="Resource" path="res://resources/items/affixes/critical_damage_percent.tres" id="12_affix"]
|
||||||
|
|
||||||
|
[ext_resource type="Resource" path="res://resources/items/affixes/missile_cooldown.tres" id="13_affix"]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
script = ExtResource("1_database")
|
script = ExtResource("1_database")
|
||||||
affixes = Array[ExtResource("2_type")]([ExtResource("3_affix"), ExtResource("4_affix"), ExtResource("5_affix"), ExtResource("6_affix"), ExtResource("7_affix"), ExtResource("8_affix"), ExtResource("9_affix"), ExtResource("10_affix"), ExtResource("11_affix"), ExtResource("12_affix")])
|
affixes = Array[ExtResource("2_type")]([ExtResource("3_affix"), ExtResource("4_affix"), ExtResource("5_affix"), ExtResource("6_affix"), ExtResource("7_affix"), ExtResource("8_affix"), ExtResource("9_affix"), ExtResource("10_affix"), ExtResource("11_affix"), ExtResource("12_affix"), ExtResource("13_affix")])
|
||||||
|
|||||||
13
resources/items/affixes/missile_cooldown.tres
Normal file
13
resources/items/affixes/missile_cooldown.tres
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[gd_resource type="Resource" script_class="ItemAffixDefinition" load_steps=2 format=3]
|
||||||
|
[ext_resource type="Script" path="res://scripts/items/item_affix_definition.gd" id="1_affix"]
|
||||||
|
[resource]
|
||||||
|
script = ExtResource("1_affix")
|
||||||
|
affix_id = "missile_cooldown"
|
||||||
|
display_name = "Skrócenie cooldownu rakiet"
|
||||||
|
stat_key = "missile_cooldown_reduction"
|
||||||
|
unit = "s"
|
||||||
|
category_mask = 63
|
||||||
|
minimum_value_level_1 = 0.1
|
||||||
|
maximum_value_level_1 = 0.15
|
||||||
|
minimum_value_level_1000 = 1.0
|
||||||
|
maximum_value_level_1000 = 2.0
|
||||||
@ -5,8 +5,8 @@
|
|||||||
[resource]
|
[resource]
|
||||||
script = ExtResource("1_definition")
|
script = ExtResource("1_definition")
|
||||||
item_id = "engine_extension"
|
item_id = "engine_extension"
|
||||||
display_name = "Moduł silnika"
|
display_name = "Ulepszony silnik"
|
||||||
description = "Pasywny moduł zwiększający prędkość maksymalną."
|
description = "Pasywny moduł prędkości. Na poziomie 1 bonus wynosi 1–5 px/s i rośnie wraz z poziomem przedmiotu."
|
||||||
primary_stat = "max_speed"
|
primary_stat = "max_speed"
|
||||||
primary_value = 40.0
|
primary_value = 3.0
|
||||||
stat_suffix = " px/s"
|
stat_suffix = " px/s"
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
[resource]
|
[resource]
|
||||||
script = ExtResource("1_definition")
|
script = ExtResource("1_definition")
|
||||||
item_id = "missile_launcher"
|
item_id = "missile_launcher"
|
||||||
display_name = "Wyrzutnia rakiet"
|
display_name = "Wyrzutnia rakiet naprowadzanych"
|
||||||
category = 0
|
category = 0
|
||||||
description = "Wystrzeliwuje naprowadzaną rakietę z eksplozją obszarową. Cooldown: 5 s."
|
description = "Wystrzeliwuje naprowadzaną rakietę z eksplozją obszarową. Cooldown: 5 s."
|
||||||
primary_stat = "damage"
|
primary_stat = "damage"
|
||||||
@ -16,7 +16,7 @@ fire_interval = 5.0
|
|||||||
weapon_cooldown = 5.0
|
weapon_cooldown = 5.0
|
||||||
projectile_speed = 400.0
|
projectile_speed = 400.0
|
||||||
weapon_range = 1000.0
|
weapon_range = 1000.0
|
||||||
energy_cost = 25.0
|
energy_cost = 0.0
|
||||||
damage_lower_roll_min = 45
|
damage_lower_roll_min = 45
|
||||||
damage_lower_roll_max = 58
|
damage_lower_roll_max = 58
|
||||||
damage_spread_roll_min = 5
|
damage_spread_roll_min = 5
|
||||||
|
|||||||
@ -1,13 +0,0 @@
|
|||||||
[gd_resource type="Resource" script_class="ItemDefinition" load_steps=2 format=3]
|
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1_definition"]
|
|
||||||
|
|
||||||
[resource]
|
|
||||||
script = ExtResource("1_definition")
|
|
||||||
item_id = "tuned_thrusters"
|
|
||||||
display_name = "Dostrojone silniki"
|
|
||||||
category = 4
|
|
||||||
description = "Ulepszone dysze zwiększające prędkość maksymalną statku o 20 px/s."
|
|
||||||
primary_stat = "max_speed"
|
|
||||||
primary_value = 20.0
|
|
||||||
stat_suffix = " px/s"
|
|
||||||
22
resources/items/unguided_missile.tres
Normal file
22
resources/items/unguided_missile.tres
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
[gd_resource type="Resource" script_class="ItemDefinition" load_steps=2 format=3]
|
||||||
|
[ext_resource type="Script" path="res://scripts/items/item_definition.gd" id="1_definition"]
|
||||||
|
[resource]
|
||||||
|
script = ExtResource("1_definition")
|
||||||
|
item_id = "unguided_missile"
|
||||||
|
display_name = "Wyrzutnia rakiet niekierowanych"
|
||||||
|
category = 0
|
||||||
|
description = "Wystrzeliwuje rakietę prosto w kierunku celownika. Większe obrażenia i eksplozja obszarowa. Zużywa amunicję rakietową."
|
||||||
|
primary_stat = "damage"
|
||||||
|
primary_value = 110.0
|
||||||
|
stat_suffix = " DMG"
|
||||||
|
weapon_kind = 3
|
||||||
|
missile_homing = false
|
||||||
|
fire_interval = 5.0
|
||||||
|
weapon_cooldown = 5.0
|
||||||
|
projectile_speed = 480.0
|
||||||
|
weapon_range = 1000.0
|
||||||
|
energy_cost = 0.0
|
||||||
|
damage_lower_roll_min = 90
|
||||||
|
damage_lower_roll_max = 116
|
||||||
|
damage_spread_roll_min = 10
|
||||||
|
damage_spread_roll_max = 24
|
||||||
@ -77,6 +77,16 @@ slot_kind = "weapon"
|
|||||||
slot_index = 1
|
slot_index = 1
|
||||||
overlay_slot = true
|
overlay_slot = true
|
||||||
|
|
||||||
|
[node name="Missile" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_left = 108.0
|
||||||
|
offset_top = 260.0
|
||||||
|
offset_right = 198.0
|
||||||
|
offset_bottom = 304.0
|
||||||
|
slot_kind = "weapon"
|
||||||
|
slot_index = 2
|
||||||
|
overlay_slot = true
|
||||||
|
|
||||||
[node name="Module1" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
[node name="Module1" parent="Contents/EquipmentLayout" instance=ExtResource("2_slot")]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 0.0
|
offset_left = 0.0
|
||||||
|
|||||||
@ -74,7 +74,7 @@ func _process(_delta: float) -> void:
|
|||||||
W: ciąg S: hamulec / wsteczny
|
W: ciąg S: hamulec / wsteczny
|
||||||
Tab: mini boost (+100%% prędkości, 20 energii/s)
|
Tab: mini boost (+100%% prędkości, 20 energii/s)
|
||||||
Q / E: strafe A / D: obrót
|
Q / E: strafe A / D: obrót
|
||||||
LPM / PPM: broń 1 / broń 2
|
LPM / PPM: broń 1 / broń 2 · ŚPM: rakieta
|
||||||
1–6: aktywne rozszerzenia
|
1–6: aktywne rozszerzenia
|
||||||
|
|
||||||
UKŁAD: %d · PLANETY: %d
|
UKŁAD: %d · PLANETY: %d
|
||||||
|
|||||||
@ -14,10 +14,14 @@ var _laser_lines: Array[Line2D] = []
|
|||||||
var _fire_buttons_down := [false, false]
|
var _fire_buttons_down := [false, false]
|
||||||
var _fire_just_pressed := [false, false]
|
var _fire_just_pressed := [false, false]
|
||||||
var _drag_fire_blocked := false
|
var _drag_fire_blocked := false
|
||||||
|
var missile_cooldown_remaining := 0.0
|
||||||
|
var missile_cooldown_duration := 5.0
|
||||||
|
var _missile_just_pressed := false
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
_ensure_input_action(&"ship_fire_primary", MOUSE_BUTTON_LEFT)
|
_ensure_input_action(&"ship_fire_primary", MOUSE_BUTTON_LEFT)
|
||||||
_ensure_input_action(&"ship_fire_secondary", MOUSE_BUTTON_RIGHT)
|
_ensure_input_action(&"ship_fire_secondary", MOUSE_BUTTON_RIGHT)
|
||||||
|
_ensure_input_action(&"ship_fire_missile", MOUSE_BUTTON_MIDDLE)
|
||||||
for slot_index in 2:
|
for slot_index in 2:
|
||||||
var beam := Line2D.new()
|
var beam := Line2D.new()
|
||||||
beam.width = 4.0
|
beam.width = 4.0
|
||||||
@ -41,6 +45,9 @@ func _unhandled_input(event: InputEvent) -> void:
|
|||||||
if ship.get_viewport().gui_is_dragging() or _drag_fire_blocked:
|
if ship.get_viewport().gui_is_dragging() or _drag_fire_blocked:
|
||||||
return
|
return
|
||||||
var slot_index := -1
|
var slot_index := -1
|
||||||
|
if event.button_index == MOUSE_BUTTON_MIDDLE:
|
||||||
|
_missile_just_pressed = event.pressed
|
||||||
|
return
|
||||||
if event.button_index == MOUSE_BUTTON_LEFT:
|
if event.button_index == MOUSE_BUTTON_LEFT:
|
||||||
slot_index = 0
|
slot_index = 0
|
||||||
elif event.button_index == MOUSE_BUTTON_RIGHT:
|
elif event.button_index == MOUSE_BUTTON_RIGHT:
|
||||||
@ -52,9 +59,11 @@ func _unhandled_input(event: InputEvent) -> void:
|
|||||||
_fire_just_pressed[slot_index] = true
|
_fire_just_pressed[slot_index] = true
|
||||||
|
|
||||||
func _physics_process(delta: float) -> void:
|
func _physics_process(delta: float) -> void:
|
||||||
|
missile_cooldown_remaining = maxf(0.0, missile_cooldown_remaining - delta)
|
||||||
if ship.get_viewport().gui_is_dragging():
|
if ship.get_viewport().gui_is_dragging():
|
||||||
_drag_fire_blocked = true
|
_drag_fire_blocked = true
|
||||||
if _drag_fire_blocked:
|
if _drag_fire_blocked:
|
||||||
|
_missile_just_pressed = false
|
||||||
for index in 2:
|
for index in 2:
|
||||||
_fire_buttons_down[index] = false
|
_fire_buttons_down[index] = false
|
||||||
_fire_just_pressed[index] = false
|
_fire_just_pressed[index] = false
|
||||||
@ -66,10 +75,14 @@ func _physics_process(delta: float) -> void:
|
|||||||
_drag_fire_blocked = false
|
_drag_fire_blocked = false
|
||||||
return
|
return
|
||||||
if bool(ship.get("_is_destroyed")) or bool(ship.get("is_docked")):
|
if bool(ship.get("_is_destroyed")) or bool(ship.get("is_docked")):
|
||||||
|
_missile_just_pressed = false
|
||||||
for line in _laser_lines:
|
for line in _laser_lines:
|
||||||
line.visible = false
|
line.visible = false
|
||||||
return
|
return
|
||||||
var mouse_over_ui := ship.get_viewport().gui_get_hovered_control() != null
|
var mouse_over_ui := ship.get_viewport().gui_get_hovered_control() != null
|
||||||
|
if not mouse_over_ui and (Input.is_action_just_pressed("ship_fire_missile") or _missile_just_pressed):
|
||||||
|
try_fire_missile()
|
||||||
|
_missile_just_pressed = false
|
||||||
for slot_index in 2:
|
for slot_index in 2:
|
||||||
_shot_timers[slot_index] = maxf(0.0, _shot_timers[slot_index] - delta)
|
_shot_timers[slot_index] = maxf(0.0, _shot_timers[slot_index] - delta)
|
||||||
_laser_pulse_timers[slot_index] = maxf(0.0, _laser_pulse_timers[slot_index] - delta)
|
_laser_pulse_timers[slot_index] = maxf(0.0, _laser_pulse_timers[slot_index] - delta)
|
||||||
@ -99,13 +112,7 @@ func _physics_process(delta: float) -> void:
|
|||||||
_laser_lines[slot_index].visible = _laser_pulse_timers[slot_index] > 0.0
|
_laser_lines[slot_index].visible = _laser_pulse_timers[slot_index] > 0.0
|
||||||
_fire_laser(slot_index, item)
|
_fire_laser(slot_index, item)
|
||||||
ItemDefinition.WeaponKind.MISSILE:
|
ItemDefinition.WeaponKind.MISSILE:
|
||||||
if (
|
pass # Rockets fire exclusively from slot 3.
|
||||||
is_just_pressed
|
|
||||||
and _shot_timers[slot_index] <= 0.0
|
|
||||||
and _consume_energy(item.get_energy_cost())
|
|
||||||
):
|
|
||||||
_fire_projectile(item)
|
|
||||||
_shot_timers[slot_index] = definition.weapon_cooldown
|
|
||||||
_:
|
_:
|
||||||
if _shot_timers[slot_index] <= 0.0 and _consume_shot_resource(item):
|
if _shot_timers[slot_index] <= 0.0 and _consume_shot_resource(item):
|
||||||
_fire_projectile(item)
|
_fire_projectile(item)
|
||||||
@ -113,6 +120,20 @@ func _physics_process(delta: float) -> void:
|
|||||||
for slot_index in 2:
|
for slot_index in 2:
|
||||||
_fire_just_pressed[slot_index] = false
|
_fire_just_pressed[slot_index] = false
|
||||||
|
|
||||||
|
func try_fire_missile() -> bool:
|
||||||
|
if missile_cooldown_remaining > 0.0 or bool(ship.get("_is_destroyed")) or bool(ship.get("is_docked")):
|
||||||
|
return false
|
||||||
|
var item := inventory.get_item("weapon", ShipInventory.MISSILE_SLOT)
|
||||||
|
if item == null or item.definition.weapon_kind != ItemDefinition.WeaponKind.MISSILE:
|
||||||
|
return false
|
||||||
|
if inventory.missile_ammunition <= 0:
|
||||||
|
return false
|
||||||
|
missile_cooldown_duration = inventory.get_missile_cooldown(item)
|
||||||
|
_fire_projectile(item)
|
||||||
|
missile_cooldown_remaining = missile_cooldown_duration
|
||||||
|
inventory.consume_missile()
|
||||||
|
return true
|
||||||
|
|
||||||
func _fire_projectile(item: ItemInstance) -> void:
|
func _fire_projectile(item: ItemInstance) -> void:
|
||||||
var definition := item.definition
|
var definition := item.definition
|
||||||
var hit: Dictionary = ship.call("roll_weapon_hit", item)
|
var hit: Dictionary = ship.call("roll_weapon_hit", item)
|
||||||
@ -131,6 +152,7 @@ func _fire_projectile(item: ItemInstance) -> void:
|
|||||||
bool(hit["critical"])
|
bool(hit["critical"])
|
||||||
)
|
)
|
||||||
ship.get_parent().add_child(projectile)
|
ship.get_parent().add_child(projectile)
|
||||||
|
projectile.set("missile_homing", definition.missile_homing)
|
||||||
WEAPON_AUDIO_SCRIPT.play(ship.get_parent(), muzzle_position, definition.weapon_kind)
|
WEAPON_AUDIO_SCRIPT.play(ship.get_parent(), muzzle_position, definition.weapon_kind)
|
||||||
|
|
||||||
func _fire_laser(slot_index: int, item: ItemInstance) -> void:
|
func _fire_laser(slot_index: int, item: ItemInstance) -> void:
|
||||||
|
|||||||
@ -11,6 +11,7 @@ var is_critical := false
|
|||||||
var max_range := 800.0
|
var max_range := 800.0
|
||||||
var weapon_kind := ItemDefinition.WeaponKind.PLASMA
|
var weapon_kind := ItemDefinition.WeaponKind.PLASMA
|
||||||
var homing_target: Node2D
|
var homing_target: Node2D
|
||||||
|
var missile_homing := true
|
||||||
var homing_turn_acceleration := 2.3
|
var homing_turn_acceleration := 2.3
|
||||||
var homing_max_turn_speed := 1.7
|
var homing_max_turn_speed := 1.7
|
||||||
var missile_steering_acceleration := 520.0
|
var missile_steering_acceleration := 520.0
|
||||||
@ -58,7 +59,7 @@ func configure(
|
|||||||
|
|
||||||
func _physics_process(delta: float) -> void:
|
func _physics_process(delta: float) -> void:
|
||||||
var travel_velocity := direction * projectile_speed
|
var travel_velocity := direction * projectile_speed
|
||||||
if weapon_kind == ItemDefinition.WeaponKind.MISSILE:
|
if weapon_kind == ItemDefinition.WeaponKind.MISSILE and missile_homing:
|
||||||
_flight_time += delta
|
_flight_time += delta
|
||||||
if not is_instance_valid(homing_target):
|
if not is_instance_valid(homing_target):
|
||||||
_has_locked_target = false
|
_has_locked_target = false
|
||||||
|
|||||||
@ -5,7 +5,7 @@ class_name ItemAffixDefinition
|
|||||||
@export var display_name: String = ""
|
@export var display_name: String = ""
|
||||||
@export_multiline var description: String = ""
|
@export_multiline var description: String = ""
|
||||||
@export var stat_key: String = ""
|
@export var stat_key: String = ""
|
||||||
@export_enum("%", "pkt", "/s", "px/s") var unit: String = "%"
|
@export_enum("%", "pkt", "/s", "px/s", "s") var unit: String = "%"
|
||||||
@export var enabled: bool = true
|
@export var enabled: bool = true
|
||||||
@export_range(0.0, 1000.0, 0.1) var selection_weight: float = 1.0
|
@export_range(0.0, 1000.0, 0.1) var selection_weight: float = 1.0
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,7 @@ enum WeaponKind { PLASMA, MACHINE_GUN, LASER, MISSILE }
|
|||||||
@export var weapon_kind: WeaponKind = WeaponKind.PLASMA
|
@export var weapon_kind: WeaponKind = WeaponKind.PLASMA
|
||||||
@export var fire_interval: float = 0.25
|
@export var fire_interval: float = 0.25
|
||||||
@export var weapon_cooldown: float = 0.0
|
@export var weapon_cooldown: float = 0.0
|
||||||
|
@export var missile_homing: bool = true
|
||||||
@export var laser_pulse_duration: float = 0.08
|
@export var laser_pulse_duration: float = 0.08
|
||||||
@export var projectile_speed: float = 0.0
|
@export var projectile_speed: float = 0.0
|
||||||
@export var weapon_range: float = 0.0
|
@export var weapon_range: float = 0.0
|
||||||
|
|||||||
@ -5,11 +5,11 @@ const DEFINITIONS := [
|
|||||||
preload("res://resources/items/beam_laser.tres"),
|
preload("res://resources/items/beam_laser.tres"),
|
||||||
preload("res://resources/items/machine_gun.tres"),
|
preload("res://resources/items/machine_gun.tres"),
|
||||||
preload("res://resources/items/missile_launcher.tres"),
|
preload("res://resources/items/missile_launcher.tres"),
|
||||||
|
preload("res://resources/items/unguided_missile.tres"),
|
||||||
preload("res://resources/items/reinforced_shield.tres"),
|
preload("res://resources/items/reinforced_shield.tres"),
|
||||||
preload("res://resources/items/hull_plating.tres"),
|
preload("res://resources/items/hull_plating.tres"),
|
||||||
preload("res://resources/items/compact_generator.tres"),
|
preload("res://resources/items/compact_generator.tres"),
|
||||||
preload("res://resources/items/engine_extension.tres"),
|
preload("res://resources/items/engine_extension.tres"),
|
||||||
preload("res://resources/items/tuned_thrusters.tres"),
|
|
||||||
preload("res://resources/items/shield_recharger.tres"),
|
preload("res://resources/items/shield_recharger.tres"),
|
||||||
preload("res://resources/items/afterburner.tres"),
|
preload("res://resources/items/afterburner.tres"),
|
||||||
preload("res://resources/items/shield_charge.tres"),
|
preload("res://resources/items/shield_charge.tres"),
|
||||||
@ -26,6 +26,8 @@ static func generate_for_definition(definition: ItemDefinition, level: int, enem
|
|||||||
item.item_level = clampi(level, 1, 1000)
|
item.item_level = clampi(level, 1, 1000)
|
||||||
var scale_factor := 1.0 + 0.05 * (item.item_level - 1)
|
var scale_factor := 1.0 + 0.05 * (item.item_level - 1)
|
||||||
item.primary_value_override = item.definition.primary_value * scale_factor * randf_range(0.8, 1.2)
|
item.primary_value_override = item.definition.primary_value * scale_factor * randf_range(0.8, 1.2)
|
||||||
|
if definition.primary_stat == "max_speed":
|
||||||
|
item.primary_value_override = randf_range(1.0, 5.0) * scale_factor
|
||||||
if definition.category == ItemDefinition.Category.WEAPON:
|
if definition.category == ItemDefinition.Category.WEAPON:
|
||||||
var lower := randi_range(mini(definition.damage_lower_roll_min, definition.damage_lower_roll_max), maxi(definition.damage_lower_roll_min, definition.damage_lower_roll_max))
|
var lower := randi_range(mini(definition.damage_lower_roll_min, definition.damage_lower_roll_max), maxi(definition.damage_lower_roll_min, definition.damage_lower_roll_max))
|
||||||
var spread := randi_range(mini(definition.damage_spread_roll_min, definition.damage_spread_roll_max), maxi(definition.damage_spread_roll_min, definition.damage_spread_roll_max))
|
var spread := randi_range(mini(definition.damage_spread_roll_min, definition.damage_spread_roll_max), maxi(definition.damage_spread_roll_min, definition.damage_spread_roll_max))
|
||||||
|
|||||||
@ -55,7 +55,7 @@ func roll_damage() -> float:
|
|||||||
func get_energy_cost() -> float:
|
func get_energy_cost() -> float:
|
||||||
if definition == null or definition.category != ItemDefinition.Category.WEAPON:
|
if definition == null or definition.category != ItemDefinition.Category.WEAPON:
|
||||||
return 0.0
|
return 0.0
|
||||||
if definition.weapon_kind == ItemDefinition.WeaponKind.MACHINE_GUN:
|
if definition.weapon_kind in [ItemDefinition.WeaponKind.MACHINE_GUN, ItemDefinition.WeaponKind.MISSILE]:
|
||||||
return 0.0
|
return 0.0
|
||||||
# Compare this weapon with its starter damage. Captain/global gear buffs are free.
|
# Compare this weapon with its starter damage. Captain/global gear buffs are free.
|
||||||
var base_lower := roundf((definition.damage_lower_roll_min + definition.damage_lower_roll_max) * 0.5)
|
var base_lower := roundf((definition.damage_lower_roll_min + definition.damage_lower_roll_max) * 0.5)
|
||||||
@ -115,6 +115,8 @@ func get_tooltip_text() -> String:
|
|||||||
lines.append("Każdy strzał / impuls losuje obrażenia z tego zakresu.")
|
lines.append("Każdy strzał / impuls losuje obrażenia z tego zakresu.")
|
||||||
if definition.weapon_kind == ItemDefinition.WeaponKind.MACHINE_GUN:
|
if definition.weapon_kind == ItemDefinition.WeaponKind.MACHINE_GUN:
|
||||||
lines.append("Zasięg: %.0f px • Amunicja: 1 / strzał" % definition.weapon_range)
|
lines.append("Zasięg: %.0f px • Amunicja: 1 / strzał" % definition.weapon_range)
|
||||||
|
elif definition.weapon_kind == ItemDefinition.WeaponKind.MISSILE:
|
||||||
|
lines.append("ŚPM • Amunicja: 1 rakieta / strzał • Cooldown bazowy: 5 s • Bez kosztu energii")
|
||||||
else:
|
else:
|
||||||
lines.append("Zasięg: %.0f px • Energia: %.1f / strzał" % [definition.weapon_range, get_energy_cost()])
|
lines.append("Zasięg: %.0f px • Energia: %.1f / strzał" % [definition.weapon_range, get_energy_cost()])
|
||||||
lines.append("Odstęp strzałów: %.2f s" % maxf(definition.fire_interval, definition.weapon_cooldown))
|
lines.append("Odstęp strzałów: %.2f s" % maxf(definition.fire_interval, definition.weapon_cooldown))
|
||||||
|
|||||||
@ -5,7 +5,12 @@ signal inventory_changed
|
|||||||
signal ammunition_changed
|
signal ammunition_changed
|
||||||
|
|
||||||
const CARGO_SIZE := 20
|
const CARGO_SIZE := 20
|
||||||
const WEAPON_SLOT_COUNT := 2
|
const WEAPON_SLOT_COUNT := 3
|
||||||
|
const MISSILE_SLOT := 2
|
||||||
|
const STARTING_MISSILE_AMMUNITION := 2
|
||||||
|
const MISSILE_CRAFT_PARTS_COST := 50.0
|
||||||
|
const MISSILE_BUY_BASE_COST := 10
|
||||||
|
const MISSILE_DEFINITIONS := [preload("res://resources/items/missile_launcher.tres"), preload("res://resources/items/unguided_missile.tres")]
|
||||||
const MODULE_SLOT_COUNT := 6
|
const MODULE_SLOT_COUNT := 6
|
||||||
const STARTING_AMMUNITION := 300
|
const STARTING_AMMUNITION := 300
|
||||||
const AMMUNITION_CRAFT_AMOUNT := 100
|
const AMMUNITION_CRAFT_AMOUNT := 100
|
||||||
@ -14,6 +19,7 @@ const AMMUNITION_BUY_AMOUNT := 100
|
|||||||
const AMMUNITION_BUY_BASE_COST := 20
|
const AMMUNITION_BUY_BASE_COST := 20
|
||||||
|
|
||||||
var ammunition: int = STARTING_AMMUNITION
|
var ammunition: int = STARTING_AMMUNITION
|
||||||
|
var missile_ammunition: int = STARTING_MISSILE_AMMUNITION
|
||||||
|
|
||||||
var cargo: Array[ItemInstance] = []
|
var cargo: Array[ItemInstance] = []
|
||||||
var weapon_slots: Array[ItemInstance] = []
|
var weapon_slots: Array[ItemInstance] = []
|
||||||
@ -31,8 +37,10 @@ func _ready() -> void:
|
|||||||
else:
|
else:
|
||||||
cargo.assign(GameState.restart_inventory["cargo"])
|
cargo.assign(GameState.restart_inventory["cargo"])
|
||||||
weapon_slots.assign(GameState.restart_inventory["weapon"])
|
weapon_slots.assign(GameState.restart_inventory["weapon"])
|
||||||
|
weapon_slots.resize(WEAPON_SLOT_COUNT)
|
||||||
module_slots.assign(GameState.restart_inventory["module"])
|
module_slots.assign(GameState.restart_inventory["module"])
|
||||||
ammunition = int(GameState.restart_inventory.get("ammunition", STARTING_AMMUNITION))
|
ammunition = int(GameState.restart_inventory.get("ammunition", STARTING_AMMUNITION))
|
||||||
|
missile_ammunition = int(GameState.restart_inventory.get("missile_ammunition", STARTING_MISSILE_AMMUNITION))
|
||||||
GameState.restart_inventory.clear()
|
GameState.restart_inventory.clear()
|
||||||
_recalculate_ship_stats()
|
_recalculate_ship_stats()
|
||||||
inventory_changed.emit()
|
inventory_changed.emit()
|
||||||
@ -51,6 +59,7 @@ func preserve_for_restart() -> void:
|
|||||||
"weapon": weapon_slots.duplicate(),
|
"weapon": weapon_slots.duplicate(),
|
||||||
"module": module_slots.duplicate(),
|
"module": module_slots.duplicate(),
|
||||||
"ammunition": ammunition,
|
"ammunition": ammunition,
|
||||||
|
"missile_ammunition": missile_ammunition,
|
||||||
}
|
}
|
||||||
|
|
||||||
func consume_ammunition() -> bool:
|
func consume_ammunition() -> bool:
|
||||||
@ -122,18 +131,63 @@ func can_move_item(from_kind: String, from_index: int, to_kind: String, to_index
|
|||||||
var item := source[from_index]
|
var item := source[from_index]
|
||||||
if item == null or item.definition == null:
|
if item == null or item.definition == null:
|
||||||
return false
|
return false
|
||||||
if to_kind == "weapon" and item.definition.category != ItemDefinition.Category.WEAPON:
|
if not _accepts_item(to_kind, to_index, item):
|
||||||
return false
|
|
||||||
if to_kind == "module" and item.definition.category == ItemDefinition.Category.WEAPON:
|
|
||||||
return false
|
return false
|
||||||
var displaced := destination[to_index]
|
var displaced := destination[to_index]
|
||||||
if displaced != null and displaced.definition != null:
|
if displaced != null and displaced.definition != null:
|
||||||
if from_kind == "weapon" and displaced.definition.category != ItemDefinition.Category.WEAPON:
|
if not _accepts_item(from_kind, from_index, displaced):
|
||||||
return false
|
|
||||||
if from_kind == "module" and displaced.definition.category == ItemDefinition.Category.WEAPON:
|
|
||||||
return false
|
return false
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
func _accepts_item(kind: String, index: int, item: ItemInstance) -> bool:
|
||||||
|
if kind == "weapon":
|
||||||
|
return item.definition.category == ItemDefinition.Category.WEAPON and (item.definition.weapon_kind == ItemDefinition.WeaponKind.MISSILE) == (index == MISSILE_SLOT)
|
||||||
|
return kind != "module" or item.definition.category != ItemDefinition.Category.WEAPON
|
||||||
|
|
||||||
|
func get_missile_count() -> int:
|
||||||
|
return missile_ammunition
|
||||||
|
|
||||||
|
func get_missile_cooldown(item: ItemInstance) -> float:
|
||||||
|
var reduction := item.get_stat_total("missile_cooldown_reduction")
|
||||||
|
for equipped in weapon_slots + module_slots:
|
||||||
|
if equipped != null and equipped != item:
|
||||||
|
reduction += equipped.get_stat_total("missile_cooldown_reduction")
|
||||||
|
return maxf(1.0, 5.0 - reduction)
|
||||||
|
|
||||||
|
func consume_missile() -> bool:
|
||||||
|
if missile_ammunition <= 0:
|
||||||
|
return false
|
||||||
|
missile_ammunition -= 1
|
||||||
|
ammunition_changed.emit()
|
||||||
|
return true
|
||||||
|
|
||||||
|
func can_craft_missile() -> bool:
|
||||||
|
return GameState.captain.parts >= MISSILE_CRAFT_PARTS_COST
|
||||||
|
|
||||||
|
func get_missile_buy_cost() -> int:
|
||||||
|
return MISSILE_BUY_BASE_COST * maxi(1, GameState.system_level)
|
||||||
|
|
||||||
|
func can_buy_missile() -> bool:
|
||||||
|
return GameState.captain.credits >= get_missile_buy_cost()
|
||||||
|
|
||||||
|
func craft_missile() -> bool:
|
||||||
|
if not can_craft_missile():
|
||||||
|
return false
|
||||||
|
GameState.captain.parts -= MISSILE_CRAFT_PARTS_COST
|
||||||
|
missile_ammunition += 1
|
||||||
|
GameState.captain.emit_changed()
|
||||||
|
ammunition_changed.emit()
|
||||||
|
return true
|
||||||
|
|
||||||
|
func buy_missile() -> bool:
|
||||||
|
if not can_buy_missile():
|
||||||
|
return false
|
||||||
|
GameState.captain.credits -= get_missile_buy_cost()
|
||||||
|
missile_ammunition += 1
|
||||||
|
GameState.captain.emit_changed()
|
||||||
|
ammunition_changed.emit()
|
||||||
|
return true
|
||||||
|
|
||||||
func move_item(from_kind: String, from_index: int, to_kind: String, to_index: int) -> bool:
|
func move_item(from_kind: String, from_index: int, to_kind: String, to_index: int) -> bool:
|
||||||
if not can_move_item(from_kind, from_index, to_kind, to_index):
|
if not can_move_item(from_kind, from_index, to_kind, to_index):
|
||||||
return false
|
return false
|
||||||
|
|||||||
@ -32,6 +32,7 @@ func _ready() -> void:
|
|||||||
_inventory = get_tree().get_first_node_in_group("ship_inventory") as ShipInventory
|
_inventory = get_tree().get_first_node_in_group("ship_inventory") as ShipInventory
|
||||||
if _inventory:
|
if _inventory:
|
||||||
_inventory.inventory_changed.connect(_refresh)
|
_inventory.inventory_changed.connect(_refresh)
|
||||||
|
_inventory.ammunition_changed.connect(_refresh)
|
||||||
match slot_kind:
|
match slot_kind:
|
||||||
"weapon":
|
"weapon":
|
||||||
custom_minimum_size = Vector2(90, 38)
|
custom_minimum_size = Vector2(90, 38)
|
||||||
@ -52,7 +53,7 @@ func _ready() -> void:
|
|||||||
slot_label.text_overrun_behavior = TextServer.OVERRUN_NO_TRIMMING
|
slot_label.text_overrun_behavior = TextServer.OVERRUN_NO_TRIMMING
|
||||||
var binding := Label.new()
|
var binding := Label.new()
|
||||||
binding.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
binding.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
binding.text = ("LPM" if slot_index == 0 else "PPM") if slot_kind == "weapon" else str(slot_index + 1)
|
binding.text = (["LPM", "PPM", "ŚPM"][slot_index]) if slot_kind == "weapon" else str(slot_index + 1)
|
||||||
binding.position = Vector2(2, -14)
|
binding.position = Vector2(2, -14)
|
||||||
binding.add_theme_font_size_override("font_size", 9)
|
binding.add_theme_font_size_override("font_size", 9)
|
||||||
binding.add_theme_color_override("font_color", Color("a0b2c4"))
|
binding.add_theme_color_override("font_color", Color("a0b2c4"))
|
||||||
@ -63,17 +64,33 @@ func _ready() -> void:
|
|||||||
marker.add_child(binding)
|
marker.add_child(binding)
|
||||||
_refresh()
|
_refresh()
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
if slot_kind == "weapon" and slot_index == ShipInventory.MISSILE_SLOT:
|
||||||
|
queue_redraw()
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
if slot_kind != "weapon" or slot_index != ShipInventory.MISSILE_SLOT or _inventory == null:
|
||||||
|
return
|
||||||
|
var weapons := _inventory.ship.get_node("WeaponController")
|
||||||
|
var remaining := float(weapons.get("missile_cooldown_remaining"))
|
||||||
|
var duration := float(weapons.get("missile_cooldown_duration"))
|
||||||
|
if remaining > 0.0:
|
||||||
|
var height := (size.y - 4.0) * clampf(remaining / duration, 0.0, 1.0)
|
||||||
|
draw_rect(Rect2(2.0, size.y - 2.0 - height, size.x - 4.0, height), Color(1.0, 0.5, 0.1, 0.45))
|
||||||
|
|
||||||
func _refresh() -> void:
|
func _refresh() -> void:
|
||||||
if not is_node_ready() or not _inventory:
|
if not is_node_ready() or not _inventory:
|
||||||
return
|
return
|
||||||
var item: ItemInstance = _inventory.get_item(slot_kind, slot_index)
|
var item: ItemInstance = _inventory.get_item(slot_kind, slot_index)
|
||||||
_apply_slot_style(item)
|
_apply_slot_style(item)
|
||||||
tooltip_text = item.get_tooltip_text() if item != null else ""
|
tooltip_text = item.get_tooltip_text() if item != null else ("WYRZUTNIA [ŚPM] — przeciągnij wyrzutnię z magazynu." if slot_kind == "weapon" and slot_index == ShipInventory.MISSILE_SLOT else "")
|
||||||
|
if item != null and slot_kind == "weapon" and slot_index == ShipInventory.MISSILE_SLOT:
|
||||||
|
tooltip_text += "\nCooldown po addonach: %.2f s\nZapas rakiet: %d" % [_inventory.get_missile_cooldown(item), _inventory.get_missile_count()]
|
||||||
if _delete_button:
|
if _delete_button:
|
||||||
_delete_button.visible = item != null
|
_delete_button.visible = item != null
|
||||||
if item == null or item.definition == null:
|
if item == null or item.definition == null:
|
||||||
slot_label.add_theme_color_override("font_color", Color("82909e"))
|
slot_label.add_theme_color_override("font_color", Color("82909e"))
|
||||||
slot_label.text = ""
|
slot_label.text = "RAKIETY" if slot_kind == "weapon" and slot_index == ShipInventory.MISSILE_SLOT else ""
|
||||||
return
|
return
|
||||||
var definition := item.definition
|
var definition := item.definition
|
||||||
slot_label.add_theme_color_override("font_color", Color("f1f4f8"))
|
slot_label.add_theme_color_override("font_color", Color("f1f4f8"))
|
||||||
|
|||||||
@ -12,14 +12,27 @@ signal next_level_requested
|
|||||||
var _inventory: ShipInventory
|
var _inventory: ShipInventory
|
||||||
var planet: Node2D
|
var planet: Node2D
|
||||||
var _open_tween: Tween
|
var _open_tween: Tween
|
||||||
|
var _missile_button: Button
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
next_button.pressed.connect(func() -> void: next_level_requested.emit())
|
next_button.pressed.connect(func() -> void: next_level_requested.emit())
|
||||||
buy_ammunition_button.pressed.connect(_buy_ammunition)
|
buy_ammunition_button.pressed.connect(_buy_ammunition)
|
||||||
reset_skills_button.pressed.connect(_reset_skills)
|
reset_skills_button.pressed.connect(_reset_skills)
|
||||||
|
_missile_button = Button.new()
|
||||||
|
_missile_button.custom_minimum_size.y = 36
|
||||||
|
_missile_button.add_theme_font_size_override("font_size", 12)
|
||||||
|
_missile_button.focus_mode = Control.FOCUS_NONE
|
||||||
|
_missile_button.tooltip_text = "Jedna sztuka amunicji rakietowej do dowolnej wyrzutni."
|
||||||
|
_missile_button.pressed.connect(func() -> void:
|
||||||
|
if visible and _inventory:
|
||||||
|
_inventory.buy_missile()
|
||||||
|
)
|
||||||
|
$Center/Panel/Contents.add_child(_missile_button)
|
||||||
|
$Center/Panel/Contents.move_child(_missile_button, reset_skills_button.get_index())
|
||||||
_inventory = get_tree().get_first_node_in_group("ship_inventory") as ShipInventory
|
_inventory = get_tree().get_first_node_in_group("ship_inventory") as ShipInventory
|
||||||
if _inventory:
|
if _inventory:
|
||||||
_inventory.ammunition_changed.connect(_refresh_ammunition_service)
|
_inventory.ammunition_changed.connect(_refresh_ammunition_service)
|
||||||
|
_inventory.inventory_changed.connect(_refresh_ammunition_service)
|
||||||
GameState.captain.changed.connect(_refresh_ammunition_service)
|
GameState.captain.changed.connect(_refresh_ammunition_service)
|
||||||
_refresh_ammunition_service()
|
_refresh_ammunition_service()
|
||||||
|
|
||||||
@ -61,6 +74,8 @@ func _position_at_planet() -> void:
|
|||||||
position = Vector2(clampf(target.x, 8.0, maxf(8.0, screen_right - size.x)), clampf(target.y, 8.0, maxf(8.0, viewport_size.y - size.y - 80.0)))
|
position = Vector2(clampf(target.x, 8.0, maxf(8.0, screen_right - size.x)), clampf(target.y, 8.0, maxf(8.0, viewport_size.y - size.y - 80.0)))
|
||||||
|
|
||||||
func _refresh_ammunition_service() -> void:
|
func _refresh_ammunition_service() -> void:
|
||||||
|
_missile_button.disabled = _inventory == null or not _inventory.can_buy_missile()
|
||||||
|
_missile_button.text = "KUP +1 RAKIETĘ — %d KREDYTÓW" % (_inventory.get_missile_buy_cost() if _inventory else ShipInventory.MISSILE_BUY_BASE_COST)
|
||||||
reset_skills_button.disabled = not GameState.captain.can_reset_skills()
|
reset_skills_button.disabled = not GameState.captain.can_reset_skills()
|
||||||
reset_skills_button.text = "RESET SKILLI — %d KREDYTÓW" % GameState.captain.get_skill_reset_cost()
|
reset_skills_button.text = "RESET SKILLI — %d KREDYTÓW" % GameState.captain.get_skill_reset_cost()
|
||||||
reset_skills_button.tooltip_text = "Zwraca wszystkie %d wydanych punktów nauki. Koszt: 100 kredytów × poziom kapitana." % GameState.captain.get_spent_learning_points()
|
reset_skills_button.tooltip_text = "Zwraca wszystkie %d wydanych punktów nauki. Koszt: 100 kredytów × poziom kapitana." % GameState.captain.get_spent_learning_points()
|
||||||
|
|||||||
@ -12,12 +12,23 @@ const CARGO_SIZE := 20
|
|||||||
var _inventory: ShipInventory
|
var _inventory: ShipInventory
|
||||||
var _drawer_open := false
|
var _drawer_open := false
|
||||||
var _slide_tween: Tween
|
var _slide_tween: Tween
|
||||||
|
var _missile_button: Button
|
||||||
var drawer_width := 780.0
|
var drawer_width := 780.0
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
close_button.pressed.connect(close_drawer)
|
close_button.pressed.connect(close_drawer)
|
||||||
craft_button.pressed.connect(_craft_ammunition)
|
craft_button.pressed.connect(_craft_ammunition)
|
||||||
craft_button.text = "TWÓRZ +%d AMUNICJI (%.0f części)" % [ShipInventory.AMMUNITION_CRAFT_AMOUNT, ShipInventory.AMMUNITION_CRAFT_PARTS_COST]
|
craft_button.text = "TWÓRZ +%d AMUNICJI (%.0f części)" % [ShipInventory.AMMUNITION_CRAFT_AMOUNT, ShipInventory.AMMUNITION_CRAFT_PARTS_COST]
|
||||||
|
var missile_row := HBoxContainer.new()
|
||||||
|
$Contents.add_child(missile_row)
|
||||||
|
$Contents.move_child(missile_row, $Contents/CargoGrid.get_index())
|
||||||
|
_missile_button = Button.new()
|
||||||
|
_missile_button.text = "TWÓRZ +1 RAKIETĘ (%.0f części)" % ShipInventory.MISSILE_CRAFT_PARTS_COST
|
||||||
|
_missile_button.tooltip_text = "Amunicja do obu typów wyrzutni rakiet. Wyrzutnie zdobywasz jako loot."
|
||||||
|
_missile_button.add_theme_font_size_override("font_size", 11)
|
||||||
|
_missile_button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
|
_missile_button.pressed.connect(func() -> void: _inventory.craft_missile())
|
||||||
|
missile_row.add_child(_missile_button)
|
||||||
_inventory = get_tree().get_first_node_in_group("ship_inventory") as ShipInventory
|
_inventory = get_tree().get_first_node_in_group("ship_inventory") as ShipInventory
|
||||||
if _inventory:
|
if _inventory:
|
||||||
_inventory.inventory_changed.connect(_refresh_title)
|
_inventory.inventory_changed.connect(_refresh_title)
|
||||||
@ -32,9 +43,10 @@ func _ready() -> void:
|
|||||||
|
|
||||||
func _refresh_title() -> void:
|
func _refresh_title() -> void:
|
||||||
craft_button.disabled = _inventory == null or not _inventory.can_craft_ammunition()
|
craft_button.disabled = _inventory == null or not _inventory.can_craft_ammunition()
|
||||||
|
_missile_button.disabled = _inventory == null or not _inventory.can_craft_missile()
|
||||||
if _inventory:
|
if _inventory:
|
||||||
title_label.text = "MAGAZYN (%d/%d) · Części: %.1f" % [_inventory.get_cargo_used(), CARGO_SIZE, GameState.captain.parts]
|
title_label.text = "MAGAZYN (%d/%d) · Części: %.1f" % [_inventory.get_cargo_used(), CARGO_SIZE, GameState.captain.parts]
|
||||||
ammunition_label.text = "AMUNICJA: %d" % _inventory.ammunition
|
ammunition_label.text = "AMUNICJA: %d · RAKIETY: %d" % [_inventory.ammunition, _inventory.get_missile_count()]
|
||||||
|
|
||||||
func _craft_ammunition() -> void:
|
func _craft_ammunition() -> void:
|
||||||
if _inventory:
|
if _inventory:
|
||||||
|
|||||||
107
tests/abilities/missile_system_test.gd
Normal file
107
tests/abilities/missile_system_test.gd
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
extends Node2D
|
||||||
|
|
||||||
|
const PLAYER := preload("res://scenes/game/player_ship.tscn")
|
||||||
|
const PROJECTILE := preload("res://scenes/game/weapon_projectile.tscn")
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
GameState.start_new_run()
|
||||||
|
var ship := PLAYER.instantiate() as CharacterBody2D
|
||||||
|
add_child(ship)
|
||||||
|
ship.set_physics_process(false)
|
||||||
|
var weapons := ship.get_node("WeaponController")
|
||||||
|
weapons.set_physics_process(false)
|
||||||
|
var inventory := ship.get_node("ShipInventory") as ShipInventory
|
||||||
|
assert(inventory.weapon_slots.size() == 3)
|
||||||
|
assert(inventory.get_missile_count() == 2 and inventory.get_cargo_used() == 0)
|
||||||
|
var launcher := ItemInstance.new()
|
||||||
|
launcher.definition = ShipInventory.MISSILE_DEFINITIONS[0]
|
||||||
|
assert(inventory.add_item(launcher))
|
||||||
|
assert(not inventory.move_item("cargo", 0, "weapon", 0))
|
||||||
|
assert(not inventory.move_item("weapon", 0, "weapon", 2))
|
||||||
|
assert(inventory.move_item("cargo", 0, "weapon", 2))
|
||||||
|
assert(not inventory.move_item("weapon", 2, "weapon", 0))
|
||||||
|
assert(not inventory.move_item("weapon", 2, "module", 0))
|
||||||
|
var energy_before := float(ship.get("energy"))
|
||||||
|
var missile := inventory.weapon_slots[2]
|
||||||
|
assert(missile.get_energy_cost() == 0.0)
|
||||||
|
var addon := ItemStatModifier.new()
|
||||||
|
addon.stat_key = "missile_cooldown_reduction"
|
||||||
|
addon.value = 0.1
|
||||||
|
missile.additional_modifiers.append(addon)
|
||||||
|
assert(is_equal_approx(inventory.get_missile_cooldown(missile), 4.9))
|
||||||
|
var middle := InputEventMouseButton.new()
|
||||||
|
middle.button_index = MOUSE_BUTTON_MIDDLE
|
||||||
|
middle.pressed = true
|
||||||
|
assert(InputMap.action_has_event("ship_fire_missile", middle))
|
||||||
|
weapons.call("_unhandled_input", middle)
|
||||||
|
weapons.call("_physics_process", 0.1)
|
||||||
|
assert(ship.get("energy") == energy_before and inventory.get_missile_count() == 1)
|
||||||
|
assert(inventory.weapon_slots[2] == missile and missile.additional_modifiers[0] == addon)
|
||||||
|
assert(is_equal_approx(weapons.get("missile_cooldown_remaining"), 4.9))
|
||||||
|
assert(not weapons.call("try_fire_missile"))
|
||||||
|
weapons.call("_physics_process", 2.0)
|
||||||
|
assert(is_equal_approx(weapons.get("missile_cooldown_remaining"), 2.9))
|
||||||
|
weapons.call("_physics_process", 3.0)
|
||||||
|
assert(weapons.call("try_fire_missile"))
|
||||||
|
assert(inventory.get_missile_count() == 0 and inventory.weapon_slots[2] == missile)
|
||||||
|
weapons.set("missile_cooldown_remaining", 0.0)
|
||||||
|
assert(not weapons.call("try_fire_missile"))
|
||||||
|
assert(inventory.weapon_slots[2] == missile and ship.get("energy") == energy_before)
|
||||||
|
GameState.captain.parts = 49.0
|
||||||
|
assert(not inventory.craft_missile())
|
||||||
|
GameState.captain.parts = 50.0
|
||||||
|
assert(inventory.craft_missile() and GameState.captain.parts == 0.0)
|
||||||
|
var unguided := ItemInstance.new()
|
||||||
|
unguided.definition = ShipInventory.MISSILE_DEFINITIONS[1]
|
||||||
|
assert(inventory.add_item(unguided))
|
||||||
|
assert(not unguided.definition.missile_homing)
|
||||||
|
assert(unguided.get_damage_range().x > missile.get_damage_range().y)
|
||||||
|
assert(inventory.move_item("cargo", 0, "weapon", 2))
|
||||||
|
weapons.set("missile_cooldown_remaining", 0.0)
|
||||||
|
assert(weapons.call("try_fire_missile"))
|
||||||
|
var found_unguided := false
|
||||||
|
for child in get_children():
|
||||||
|
if child.scene_file_path == "res://scenes/game/weapon_projectile.tscn" and not child.get("missile_homing"):
|
||||||
|
found_unguided = true
|
||||||
|
assert(found_unguided)
|
||||||
|
var target := Node2D.new()
|
||||||
|
target.position = Vector2(0, 100)
|
||||||
|
add_child(target)
|
||||||
|
var straight := PROJECTILE.instantiate() as Area2D
|
||||||
|
straight.call("configure", Vector2.ZERO, Vector2.RIGHT, ItemDefinition.WeaponKind.MISSILE, 480.0, 100.0, 1000.0, target)
|
||||||
|
straight.set("missile_homing", false)
|
||||||
|
straight.collision_mask = 0
|
||||||
|
add_child(straight)
|
||||||
|
straight.set_physics_process(false)
|
||||||
|
straight.call("_physics_process", 0.5)
|
||||||
|
assert(straight.position.is_equal_approx(Vector2(240, 0)))
|
||||||
|
GameState.system_level = 3
|
||||||
|
GameState.captain.credits = 29
|
||||||
|
assert(not inventory.buy_missile())
|
||||||
|
GameState.captain.credits = 30
|
||||||
|
assert(inventory.buy_missile() and GameState.captain.credits == 0)
|
||||||
|
GameState.captain.parts = 100.0
|
||||||
|
GameState.captain.credits = 100
|
||||||
|
for index in inventory.cargo.size():
|
||||||
|
if inventory.cargo[index] == null:
|
||||||
|
inventory.cargo[index] = missile
|
||||||
|
var ammo_before := inventory.missile_ammunition
|
||||||
|
assert(inventory.craft_missile() and GameState.captain.parts == 50.0)
|
||||||
|
assert(inventory.buy_missile() and GameState.captain.credits == 70)
|
||||||
|
assert(inventory.missile_ammunition == ammo_before + 2)
|
||||||
|
addon.value = 100.0
|
||||||
|
assert(inventory.get_missile_cooldown(missile) == 1.0)
|
||||||
|
var affix := load("res://resources/items/affixes/missile_cooldown.tres") as ItemAffixDefinition
|
||||||
|
assert(affix.can_roll(ShipInventory.MISSILE_DEFINITIONS[0], 1))
|
||||||
|
assert(affix.roll_value(1) >= 0.1 and affix.roll_value(1000) >= 1.0)
|
||||||
|
inventory.preserve_for_restart()
|
||||||
|
assert(GameState.restart_inventory["weapon"].size() == 3)
|
||||||
|
var restored := PLAYER.instantiate() as CharacterBody2D
|
||||||
|
add_child(restored)
|
||||||
|
restored.set_physics_process(false)
|
||||||
|
restored.get_node("WeaponController").set_physics_process(false)
|
||||||
|
var restored_inventory := restored.get_node("ShipInventory") as ShipInventory
|
||||||
|
assert(restored_inventory.missile_ammunition == inventory.missile_ammunition)
|
||||||
|
assert(restored_inventory.weapon_slots[2] == unguided)
|
||||||
|
print("MISSILE_SYSTEM_TEST: PASS (slots, permanent launchers, separate ammo, cooldown, no energy, variants, crafting, purchases, affix, restart)")
|
||||||
|
get_tree().quit()
|
||||||
1
tests/abilities/missile_system_test.gd.uid
Normal file
1
tests/abilities/missile_system_test.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://bui0803ewdmjn
|
||||||
4
tests/abilities/missile_system_test.tscn
Normal file
4
tests/abilities/missile_system_test.tscn
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
[ext_resource type="Script" path="res://tests/abilities/missile_system_test.gd" id="1"]
|
||||||
|
[node name="MissileSystemTest" type="Node2D"]
|
||||||
|
script = ExtResource("1")
|
||||||
@ -32,7 +32,7 @@ func _ready() -> void:
|
|||||||
addon.stat_key = "damage_percent"
|
addon.stat_key = "damage_percent"
|
||||||
addon.value = 10.0
|
addon.value = 10.0
|
||||||
stronger.additional_modifiers.append(addon)
|
stronger.additional_modifiers.append(addon)
|
||||||
if definition.weapon_kind == ItemDefinition.WeaponKind.MACHINE_GUN:
|
if definition.weapon_kind in [ItemDefinition.WeaponKind.MACHINE_GUN, ItemDefinition.WeaponKind.MISSILE]:
|
||||||
assert(stronger.get_energy_cost() == 0.0)
|
assert(stronger.get_energy_cost() == 0.0)
|
||||||
else:
|
else:
|
||||||
assert(stronger.get_energy_cost() > cost_before_addon)
|
assert(stronger.get_energy_cost() > cost_before_addon)
|
||||||
@ -92,13 +92,14 @@ func _ready() -> void:
|
|||||||
assert(inventory.craft_ammunition())
|
assert(inventory.craft_ammunition())
|
||||||
assert(inventory.ammunition == 100 and GameState.captain.parts == 0.0)
|
assert(inventory.ammunition == 100 and GameState.captain.parts == 0.0)
|
||||||
GameState.system_level = 3
|
GameState.system_level = 3
|
||||||
assert(inventory.get_ammunition_buy_cost() == 300)
|
var buy_cost := ShipInventory.AMMUNITION_BUY_BASE_COST * 3
|
||||||
GameState.captain.credits = 299
|
assert(inventory.get_ammunition_buy_cost() == buy_cost)
|
||||||
|
GameState.captain.credits = buy_cost - 1
|
||||||
assert(not inventory.buy_ammunition())
|
assert(not inventory.buy_ammunition())
|
||||||
assert(inventory.ammunition == 100 and GameState.captain.credits == 299)
|
assert(inventory.ammunition == 100 and GameState.captain.credits == buy_cost - 1)
|
||||||
GameState.captain.credits = 600
|
GameState.captain.credits = buy_cost * 2
|
||||||
assert(inventory.buy_ammunition())
|
assert(inventory.buy_ammunition())
|
||||||
assert(inventory.ammunition == 200 and GameState.captain.credits == 300)
|
assert(inventory.ammunition == 200 and GameState.captain.credits == buy_cost)
|
||||||
assert(inventory.buy_ammunition())
|
assert(inventory.buy_ammunition())
|
||||||
assert(inventory.ammunition == 300 and GameState.captain.credits == 0)
|
assert(inventory.ammunition == 300 and GameState.captain.credits == 0)
|
||||||
assert(not inventory.buy_ammunition())
|
assert(not inventory.buy_ammunition())
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user