Randoloot/scripts/captain/captain_skills.gd
2026-10-26 19:33:45 +01:00

98 lines
6.1 KiB
GDScript

extends RefCounted
const MAX_RANK := 3
static var _icon_cache: Dictionary = {}
const COOLDOWN := 30.0
const DURATION := 5.0
const IDS := ["business_shark", "reactor_overload", "tactical_maneuver", "efficient_magazine", "miner", "power_redirect", "lucky", "explorer", "electrician", "scientist", "gunsmith", "bounty_hunter", "missile_specialist", "emergency_procedure", "scrap_collector", "drone_commander"]
const DATA := {
"scrap_collector": {"name": "Zbieracz złomu", "active": false, "values": [0.15, 0.25, 0.40], "color": "d9b27c"},
"drone_commander": {"name": "Dowódca dronów", "active": false, "values": [0.10, 0.20, 0.30], "color": "70dfff"},
"scientist": {"name": "Naukowiec", "active": false, "values": [0.10, 0.20, 0.30], "color": "76d9ed"},
"gunsmith": {"name": "Rusznikarz", "active": false, "values": [0.10, 0.20, 0.30], "color": "e8b26e"},
"bounty_hunter": {"name": "Łowca nagród", "active": false, "values": [0.10, 0.20, 0.30], "color": "efcc70"},
"missile_specialist": {"name": "Specjalista rakietowy", "active": false, "values": [0.10, 0.15, 0.20], "color": "f29576"},
"emergency_procedure": {"name": "Procedura awaryjna", "active": true, "values": [0.05, 0.10, 0.15], "color": "85deb1"},
"electrician": {"name": "Elektryk", "active": false, "values": [0.15, 0.20, 0.25], "color": "70f5df"},
"lucky": {"name": "Farciarz", "active": false, "values": [0.05, 0.10, 0.25], "color": "e8c76f"},
"explorer": {"name": "Eksplorator", "active": false, "values": [1, 3, 6], "color": "76d9cc"},
"business_shark": {"name": "Rekin biznesu", "active": false, "values": [0.10, 0.30, 0.60], "color": "efb568"},
"reactor_overload": {"name": "Przeciążenie reaktora", "active": true, "values": [0.28, 0.70, 1.40], "color": "63d9f5"},
"tactical_maneuver": {"name": "Manewr taktyczny", "active": true, "values": [0.30, 0.60, 1.00], "color": "b9a0ef"},
"efficient_magazine": {"name": "Oszczędny magazynek", "active": false, "values": [0.10, 0.20, 0.50], "color": "a9d69a"},
"miner": {"name": "Górnik", "active": false, "values": [3, 6, 10], "color": "e5ac76"},
"power_redirect": {"name": "Przekierowanie zasilania", "active": true, "values": [1.00, 1.80, 3.00], "color": "f28b6e"},
}
static func value(skill: String, rank: int) -> float:
if not DATA.has(skill) or rank <= 0:
return 0.0
return float(DATA[skill]["values"][clampi(rank, 1, MAX_RANK) - 1])
static func duration(skill: String) -> float:
if skill == "emergency_procedure": return 0.0
return 15.0 if skill == "reactor_overload" else (7.0 if skill == "power_redirect" else DURATION)
static func cooldown(skill: String) -> float:
return 60.0 if skill == "emergency_procedure" else COOLDOWN
static func icon(skill: String) -> Texture2D:
if skill not in IDS: return null
if not _icon_cache.has(skill):
if IDS.find(skill) >= 9:
var texture: Texture2D = load("res://assets/icons/captain/%s.png" % skill)
var artwork := texture.get_image()
artwork.resize(384,384,Image.INTERPOLATE_LANCZOS)
artwork.generate_mipmaps()
_icon_cache[skill] = ImageTexture.create_from_image(artwork)
return _icon_cache[skill]
var atlas: Texture2D = load("res://assets/icons/captain/unified_skills.png")
var cell := atlas.get_size()/3.0
var index := IDS.find(skill)
var row := index/3
var rows := [0.0,0.313,0.635,1.0]
var region := Rect2i(Vector2(index%3*cell.x+4,rows[row]*atlas.get_height()+4),Vector2(cell.x-8,(rows[row+1]-rows[row])*atlas.get_height()-8))
var image := atlas.get_image().get_region(region)
image.resize(384,384,Image.INTERPOLATE_LANCZOS)
image.generate_mipmaps()
# Separate cached textures keep UV-based cooldown/rounded-corner shaders local.
_icon_cache[skill] = ImageTexture.create_from_image(image)
return _icon_cache[skill]
static func description(skill: String, rank: int) -> String:
var amount := roundi(value(skill, rank) * 100.0)
match skill:
"scrap_collector":
return "%d%% szansy na 1 dodatkową część z przeszukanego wraku. Losowanie raz na wrak. Premie rang nie sumują się." % amount
"drone_commander":
return "Obrażenia dronów bojowych większe o %d%%. Premie rang nie sumują się." % amount
"scientist":
return "Nowe badania w laboratorium trwają o %d%% krócej. Premie rang nie sumują się." % amount
"gunsmith":
return "Produkcja zwykłej i radiacyjnej amunicji daje o %d%% więcej sztuk za ten sam koszt. Nie dotyczy rakiet. Premie rang nie sumują się." % amount
"bounty_hunter":
return "O %d%% więcej kredytów za pokonanych wrogów. Premia obejmuje kredyty do zebrania po walce. Premie rang nie sumują się." % amount
"missile_specialist":
return "Czas między wystrzeleniem rakiet krótszy o %d%%. Działa po premiach sprzętu; minimalny odstęp to 1 s. Premie rang nie sumują się." % amount
"emergency_procedure":
return "Natychmiast naprawia %d%% maksymalnego kadłuba za 1 część. Wymaga uszkodzonego statku i aktywnego lotu." % amount
"electrician":
return "Powerbank przywraca %d%% maksymalnej energii zamiast 10%%. Umiejętność pasywna; premie rang nie sumują się." % amount
"lucky":
return "Szczęście: %d%% szans na przedmiot o 1 poziom wyższy niż bazowy loot planszy. Dotyczy lootu z wrogów i znalezisk. Bazowo: 0%%. Sumuje się ze sprzętem do limitu 60%%. Premie rang nie sumują się." % amount
"explorer":
return "+%d wraków na nowej planszy. Premia ustalana przy rozpoczęciu systemu; nie zmienia bieżącej planszy. Premie rang nie sumują się." % roundi(value(skill, rank))
"business_shark":
return "Zakupy za kredyty tańsze o %d%%." % amount
"reactor_overload":
return "Regeneracja energii +%d%% przez 15 sekund." % amount
"tactical_maneuver":
return "Szansa uniku wynosi %d%% przez 5 sekund. Unik anuluje całe trafienie." % amount
"efficient_magazine":
return "Zużycie amunicji mniejsze o %d%%. Obejmuje zwykłą i napromieniowaną amunicję, bez rakiet." % amount
"miner":
return "+%d szt. surowca z każdej zniszczonej asteroidy." % roundi(value(skill, rank))
"power_redirect":
return "Regeneracja energii +%d%% przez 7 sekund. Zużywa wszystkie tarcze i blokuje ich odzysk na czas działania. Wymaga min. 25%% tarcz." % amount
return ""