231 lines
7.3 KiB
GDScript
231 lines
7.3 KiB
GDScript
extends Node
|
|
class_name ShipInventory
|
|
|
|
signal inventory_changed
|
|
signal ammunition_changed
|
|
|
|
const CARGO_SIZE := 20
|
|
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 STARTING_AMMUNITION := 50
|
|
const AMMUNITION_CRAFT_AMOUNT := 100
|
|
const AMMUNITION_CRAFT_PARTS_COST := 50.0
|
|
const AMMUNITION_BUY_AMOUNT := 100
|
|
const AMMUNITION_BUY_BASE_COST := 20
|
|
|
|
var ammunition: int = STARTING_AMMUNITION
|
|
var missile_ammunition: int = STARTING_MISSILE_AMMUNITION
|
|
|
|
var cargo: Array[ItemInstance] = []
|
|
var weapon_slots: Array[ItemInstance] = []
|
|
var module_slots: Array[ItemInstance] = []
|
|
|
|
@onready var ship: CharacterBody2D = get_parent()
|
|
|
|
func _ready() -> void:
|
|
add_to_group("ship_inventory")
|
|
cargo.resize(CARGO_SIZE)
|
|
weapon_slots.resize(WEAPON_SLOT_COUNT)
|
|
module_slots.resize(MODULE_SLOT_COUNT)
|
|
if GameState.restart_inventory.is_empty():
|
|
_add_starter_items()
|
|
else:
|
|
cargo.assign(GameState.restart_inventory["cargo"])
|
|
weapon_slots.assign(GameState.restart_inventory["weapon"])
|
|
weapon_slots.resize(WEAPON_SLOT_COUNT)
|
|
module_slots.assign(GameState.restart_inventory["module"])
|
|
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()
|
|
_recalculate_ship_stats()
|
|
inventory_changed.emit()
|
|
|
|
func get_cargo_used() -> int:
|
|
var used := 0
|
|
for item in cargo:
|
|
if item != null:
|
|
used += 1
|
|
return used
|
|
|
|
func preserve_for_restart() -> void:
|
|
# Copy the slot arrays; resources retain levels and individual modifiers.
|
|
GameState.restart_inventory = {
|
|
"cargo": cargo.duplicate(),
|
|
"weapon": weapon_slots.duplicate(),
|
|
"module": module_slots.duplicate(),
|
|
"ammunition": ammunition,
|
|
"missile_ammunition": missile_ammunition,
|
|
}
|
|
|
|
func consume_ammunition() -> bool:
|
|
if ammunition <= 0:
|
|
return false
|
|
ammunition -= 1
|
|
ammunition_changed.emit()
|
|
return true
|
|
|
|
func can_craft_ammunition() -> bool:
|
|
return GameState.captain.parts >= AMMUNITION_CRAFT_PARTS_COST
|
|
|
|
func craft_ammunition() -> bool:
|
|
if not can_craft_ammunition():
|
|
return false
|
|
GameState.captain.parts -= AMMUNITION_CRAFT_PARTS_COST
|
|
ammunition += AMMUNITION_CRAFT_AMOUNT
|
|
GameState.captain.emit_changed()
|
|
ammunition_changed.emit()
|
|
return true
|
|
|
|
func get_item(slot_kind: String, index: int) -> ItemInstance:
|
|
var slots := _get_slots(slot_kind)
|
|
if index < 0 or index >= slots.size():
|
|
return null
|
|
return slots[index]
|
|
|
|
func get_ammunition_buy_cost() -> int:
|
|
return AMMUNITION_BUY_BASE_COST * maxi(1, GameState.system_level)
|
|
|
|
func can_buy_ammunition() -> bool:
|
|
return GameState.captain.credits >= get_ammunition_buy_cost()
|
|
|
|
func buy_ammunition() -> bool:
|
|
if not can_buy_ammunition():
|
|
return false
|
|
GameState.captain.credits -= get_ammunition_buy_cost()
|
|
ammunition += AMMUNITION_BUY_AMOUNT
|
|
GameState.captain.emit_changed()
|
|
ammunition_changed.emit()
|
|
return true
|
|
|
|
func add_item(item: ItemInstance) -> bool:
|
|
if item == null or item.definition == null:
|
|
return false
|
|
for index in cargo.size():
|
|
if cargo[index] == null:
|
|
cargo[index] = item
|
|
inventory_changed.emit()
|
|
return true
|
|
return false
|
|
|
|
func delete_cargo_item(index: int) -> bool:
|
|
if index < 0 or index >= cargo.size() or cargo[index] == null:
|
|
return false
|
|
cargo[index] = null
|
|
GameState.captain.parts += 10.0
|
|
GameState.captain.emit_changed()
|
|
inventory_changed.emit()
|
|
return true
|
|
|
|
func can_move_item(from_kind: String, from_index: int, to_kind: String, to_index: int) -> bool:
|
|
var source := _get_slots(from_kind)
|
|
var destination := _get_slots(to_kind)
|
|
if from_index < 0 or from_index >= source.size() or to_index < 0 or to_index >= destination.size():
|
|
return false
|
|
if from_kind == to_kind and from_index == to_index:
|
|
return false
|
|
var item := source[from_index]
|
|
if item == null or item.definition == null:
|
|
return false
|
|
if not _accepts_item(to_kind, to_index, item):
|
|
return false
|
|
var displaced := destination[to_index]
|
|
if displaced != null and displaced.definition != null:
|
|
if not _accepts_item(from_kind, from_index, displaced):
|
|
return false
|
|
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:
|
|
if not can_move_item(from_kind, from_index, to_kind, to_index):
|
|
return false
|
|
var source := _get_slots(from_kind)
|
|
var destination := _get_slots(to_kind)
|
|
var displaced := destination[to_index]
|
|
destination[to_index] = source[from_index]
|
|
source[from_index] = displaced
|
|
_recalculate_ship_stats()
|
|
inventory_changed.emit()
|
|
return true
|
|
|
|
func _get_slots(slot_kind: String) -> Array[ItemInstance]:
|
|
match slot_kind:
|
|
"cargo":
|
|
return cargo
|
|
"weapon":
|
|
return weapon_slots
|
|
"module":
|
|
return module_slots
|
|
return []
|
|
|
|
func _recalculate_ship_stats() -> void:
|
|
var bonuses := {}
|
|
for item in weapon_slots + module_slots:
|
|
if item == null or item.definition == null:
|
|
continue
|
|
for stat_key in ["max_hull", "max_shields", "max_energy", "max_speed", "energy_regeneration", "shield_regeneration", "hull_percent", "shield_percent", "damage_percent", "speed_percent", "experience_percent", "credits_percent", "critical_chance_percent", "critical_damage_percent"]:
|
|
bonuses[stat_key] = float(bonuses.get(stat_key, 0.0)) + item.get_stat_total(stat_key)
|
|
ship.call("apply_equipment_bonuses", bonuses)
|
|
|
|
func _add_starter_items() -> void:
|
|
var definition := load("res://resources/items/plasma_cannon.tres") as ItemDefinition
|
|
if definition == null:
|
|
push_warning("Could not load starter plasma cannon")
|
|
return
|
|
var item := ItemInstance.new()
|
|
item.definition = definition
|
|
item.item_level = 1
|
|
weapon_slots[0] = item
|