1
1
mirror of https://github.com/Rundll86/Dog-Lynx-And-HCN.git synced 2026-06-04 10:47:13 +08:00

feat: 添加武器升华系统及相关UI组件

实现武器升华功能,包括:
- 新增SublimateOption类处理升华选项
- 添加SublimateOptionHandler UI组件
- 在武器卡片中集成升华界面
- 重构武器描述生成逻辑
- 新增钻石资源消耗机制
- 优化UI布局和样式
- 修复多处类型引用错误
This commit is contained in:
2026-05-10 11:49:17 +08:00
parent 1071e87da6
commit 7a0cf96d7d
39 changed files with 558 additions and 147 deletions
+1 -1
View File
@@ -25,7 +25,7 @@ func beforeOpen(_args: Array = []):
for feed in ComponentManager.feeds:
var card = feed.instantiate() as Feed
card.freeToBuy = true
if card.topic == FeedName.Topic.WEAPON:
if card.topic == CategoryStore.Topic.WEAPON:
if weaponCounted < OutGameStorage.maxInitialWeaponCount:
initialWeaponSelection.add_child(card)
card.selected.connect(
+19 -3
View File
@@ -3,17 +3,33 @@ extends Weapon
func sublimateOptions() -> Array[SublimateOption]:
return [
SublimateOption.new("健体·阳", "格挡次数+1", func(w: Weapon, _e): w.addStoreExtra("count", 1)),
SublimateOption.new("健体·阴", "气力上限+1", func(w: Weapon, _e): w.addStoreExtra("max", 1)),
SublimateOption.new("引气入体", "乾坤剑伤害+6", func(w: Weapon, _e): w.addStoreExtra("atk", 6)),
SublimateOption.new("引气入体", "乾坤剑伤害+6",
func(w: Weapon, _e): w.addStoreExtra("atk", 6),
1,
CategoryStore.Quality.COMMON
),
SublimateOption.new("健体·阳", "格挡次数+1",
func(w: Weapon, _e): w.addStoreExtra("count", 1),
1,
CategoryStore.Quality.LEGENDARY
),
SublimateOption.new("健体·阴", "气力上限+1",
func(w: Weapon, _e): w.addStoreExtra("max", 1),
1,
CategoryStore.Quality.EPIC
),
SublimateOption.new("献祭", "乾坤剑伤害-8,但弹反概率+4%",
func(w: Weapon, _e):
w.addStoreExtra("atk", -10)
w.addStoreExtra("rate", 0.05),
1,
CategoryStore.Quality.RARE
),
SublimateOption.new("亏心", "扣除你的所有幸运,每点幸运增加1%弹反概率",
func(w: Weapon, e: EntityBase):
w.addStoreExtra("rate", e.fields[FieldStore.Entity.LUCK_VALUE]),
1,
CategoryStore.Quality.WASTE
),
]
func update(to: int, origin: Dictionary, _entity: EntityBase):
+1 -1
View File
@@ -7,7 +7,7 @@ enum ComposeMode {
}
@export var targetFields: Array[FieldStore.Entity] = []
@export var targetTopics: Array[FeedName.Topic] = []
@export var targetTopics: Array[CategoryStore.Topic] = []
@export var composeMode: ComposeMode = ComposeMode.ALL
@export var clickToRefresh: bool = false
+1 -1
View File
@@ -1,7 +1,7 @@
@tool
extends HBoxContainer
@export var targetTopics: Array[FeedName.Topic] = []
@export var targetTopics: Array[CategoryStore.Topic] = []
@export var clickToRefresh: bool = false
var lastState: bool = false
+1 -1
View File
@@ -68,7 +68,7 @@ var inventory = {
ItemStore.ItemType.BEACHBALL: 0,
ItemStore.ItemType.SOUL: 0,
ItemStore.ItemType.CRYSTAL: 0,
ItemStore.ItemType.DIAMOND: 0
ItemStore.ItemType.DIAMOND: 10
}
var inventoryMax = {
ItemStore.ItemType.BASEBALL: INF, # 无限
+42 -62
View File
@@ -2,80 +2,60 @@
extends HBoxContainer
class_name FeedName
enum Quality {
WASTE,
COMMON,
RARE,
EPIC,
LEGENDARY,
}
enum Topic {
SURVIVAL,
ENERGY,
BULLET,
SPEED,
DAMAGE,
PROBABILITY,
FEED,
DROP,
WEAPON,
SUMMON,
}
@export var displayName: String = "未命名饲料"
@export var quality: Quality = Quality.COMMON
@export var topic: Topic = Topic.SURVIVAL
@export var quality: CategoryStore.Quality = CategoryStore.Quality.COMMON
@export var topic: CategoryStore.Topic = CategoryStore.Topic.SURVIVAL
@export var qualityColorMap = {
Quality.WASTE: Color(),
Quality.COMMON: Color(),
Quality.RARE: Color(),
Quality.EPIC: Color(),
Quality.LEGENDARY: Color()
CategoryStore.Quality.WASTE: Color(),
CategoryStore.Quality.COMMON: Color(),
CategoryStore.Quality.RARE: Color(),
CategoryStore.Quality.EPIC: Color(),
CategoryStore.Quality.LEGENDARY: Color()
}
@export var qualityNameMap = {
Quality.WASTE: "常见",
Quality.COMMON: "普通",
Quality.RARE: "稀有",
Quality.EPIC: "史诗",
Quality.LEGENDARY: "传说"
CategoryStore.Quality.WASTE: "常见",
CategoryStore.Quality.COMMON: "普通",
CategoryStore.Quality.RARE: "稀有",
CategoryStore.Quality.EPIC: "史诗",
CategoryStore.Quality.LEGENDARY: "传说"
}
@export var qualityRandomWeight = {
Quality.WASTE: 20,
Quality.COMMON: 100,
Quality.RARE: 30,
Quality.EPIC: 10,
Quality.LEGENDARY: 5
CategoryStore.Quality.WASTE: 20,
CategoryStore.Quality.COMMON: 100,
CategoryStore.Quality.RARE: 30,
CategoryStore.Quality.EPIC: 10,
CategoryStore.Quality.LEGENDARY: 5
}
@export var luckInfluence = {
Quality.WASTE: - 0.5,
Quality.COMMON: - 1,
Quality.RARE: 0,
Quality.EPIC: 1,
Quality.LEGENDARY: 2,
CategoryStore.Quality.WASTE: - 0.5,
CategoryStore.Quality.COMMON: - 1,
CategoryStore.Quality.RARE: 0,
CategoryStore.Quality.EPIC: 1,
CategoryStore.Quality.LEGENDARY: 2,
}
@export var topicNameMap = {
Topic.SURVIVAL: "生存",
Topic.ENERGY: "能量",
Topic.BULLET: "子弹",
Topic.SPEED: "速度",
Topic.DAMAGE: "伤害",
Topic.PROBABILITY: "幸运",
Topic.FEED: "饲料",
Topic.DROP: "掉落物",
Topic.WEAPON: "武器",
Topic.SUMMON: "召唤",
CategoryStore.Topic.SURVIVAL: "生存",
CategoryStore.Topic.ENERGY: "能量",
CategoryStore.Topic.BULLET: "子弹",
CategoryStore.Topic.SPEED: "速度",
CategoryStore.Topic.DAMAGE: "伤害",
CategoryStore.Topic.PROBABILITY: "幸运",
CategoryStore.Topic.FEED: "饲料",
CategoryStore.Topic.DROP: "掉落物",
CategoryStore.Topic.WEAPON: "武器",
CategoryStore.Topic.SUMMON: "召唤",
}
@export var topicColorMap = {
Topic.SURVIVAL: Color(),
Topic.ENERGY: Color(),
Topic.BULLET: Color(),
Topic.SPEED: Color(),
Topic.DAMAGE: Color(),
Topic.PROBABILITY: Color(),
Topic.FEED: Color(),
Topic.DROP: Color(),
Topic.WEAPON: Color(),
Topic.SUMMON: Color(),
CategoryStore.Topic.SURVIVAL: Color(),
CategoryStore.Topic.ENERGY: Color(),
CategoryStore.Topic.BULLET: Color(),
CategoryStore.Topic.SPEED: Color(),
CategoryStore.Topic.DAMAGE: Color(),
CategoryStore.Topic.PROBABILITY: Color(),
CategoryStore.Topic.FEED: Color(),
CategoryStore.Topic.DROP: Color(),
CategoryStore.Topic.WEAPON: Color(),
CategoryStore.Topic.SUMMON: Color(),
}
@onready var qualityLabel: Label = $"%quality"
@@ -0,0 +1,30 @@
@tool
extends Control
class_name SublimateOptionHandler
signal apply()
@onready var nameLabel: Label = $%name
@onready var applyBtn: Button = $%applyBtn
@onready var costItemShow: ItemShow = $%costItem
var use: SublimateOption;
func _ready():
nameLabel.label_settings = nameLabel.label_settings.duplicate()
applyBtn.pressed.connect(
func():
if UIState.player.useItem({ItemStore.ItemType.DIAMOND: use.cost}):
apply.emit()
else:
UIState.showTip("钻石数量不足!", TipBox.MessageType.ERROR)
)
rebuildInfo()
func rebuildInfo():
if is_instance_valid(use):
nameLabel.label_settings.font_color = CategoryStore.qualityColorMap[use.quality]
nameLabel.label_settings.outline_color = CategoryStore.qualityColorMap[use.quality]
nameLabel.text = use.displayName
applyBtn.text = use.description
costItemShow.count = use.cost
@@ -0,0 +1 @@
uid://qpx600iiwgae
+13
View File
@@ -0,0 +1,13 @@
@tool
extends Button
class_name TextSwitchButton
@export var pressedText: String = "已按下"
@export var unpressedText: String = "未按下"
func _ready():
updateText()
toggled.connect(updateText)
func updateText():
text = [unpressedText, pressedText][int(button_pressed)]
@@ -0,0 +1 @@
uid://5r8mvbag4m0q
+2 -2
View File
@@ -6,8 +6,8 @@ signal selected(applied: bool)
@export var avatarTexture: Texture2D = null
@export var displayName: String = "未命名饲料"
@export var quality: FeedName.Quality = FeedName.Quality.COMMON
@export var topic: FeedName.Topic = FeedName.Topic.SURVIVAL
@export var quality: CategoryStore.Quality = CategoryStore.Quality.COMMON
@export var topic: CategoryStore.Topic = CategoryStore.Topic.SURVIVAL
@export var fields: Array[FieldStore.Entity] = []
@export var fieldValues: Array[float] = []
@export var weapons: Array[PackedScene] = []
+11 -5
View File
@@ -1,15 +1,21 @@
class_name SublimateOption
signal applied()
var displayName: String = "升华"
var description: String = "描述"
var executor: Callable = func(_weapon: Weapon, _entity: EntityBase): return
var cost: int = 1
var quality: CategoryStore.Quality = CategoryStore.Quality.COMMON
func _init(displayNames: String, descriptions: String, executors: Callable):
func _init(displayNames: String, descriptions: String, executors: Callable, costs: int, qualities: CategoryStore.Quality):
displayName = displayNames
description = descriptions
executor = executors
cost = costs
quality = qualities
func apply(entity: EntityBase, index: int):
var weapon = entity.weapons[index]
if weapon is Weapon:
executor.call(weapon, entity)
func apply(entity: EntityBase, weapon: Weapon):
cost += 1
executor.call(weapon, entity)
applied.emit()
+42 -3
View File
@@ -48,6 +48,8 @@ enum EmitType {
@onready var extractBtn: Button = $%extractBtn
@onready var inlayBtn: Button = $%inlayBtn
@onready var sublimateOptionsBox: Control = $%sublimateOptions
var cooldownTimer: CooldownTimer = null
var originalStore: Dictionary = {}
var chargedTime: float = 0
@@ -55,6 +57,7 @@ var attackSpeed: float = 1
var looping: bool = false
var autoUpdate: bool = false
var storeExtra: Dictionary = {}
var sublimateOptionsStored: Array[SublimateOption] = []
func _ready():
cooldownTimer = CooldownTimer.new()
@@ -126,6 +129,7 @@ func _ready():
for i in sounds.get_children():
i.process_mode = ProcessMode.PROCESS_MODE_ALWAYS
debugRebuild = false # 只能在编辑器里打开
rebuildInfo()
func _physics_process(_delta):
if debugRebuild:
rebuildInfo()
@@ -153,6 +157,10 @@ func multipiler() -> float:
else:
return 1
func rebuildInfo(showNext: bool = false):
rebuildBaseInfo()
rebuildDescription(showNext)
rebuildSublimateOptions(showNext)
func rebuildBaseInfo():
avatarRect.texture = avatarTexture
nameLabel.displayName = displayName
nameLabel.quality = quality
@@ -171,7 +179,6 @@ func rebuildInfo(showNext: bool = false):
if is_instance_valid(UIState.player):
beachball.enough = canUpdate(UIState.player)
soul.enough = canInlay()
descriptionLabel.text = buildDescription(showNext && (canUpdate(UIState.player) || canInlay()))
func formatValue(value: Variant, type: FieldStore.DataType) -> String:
if type == FieldStore.DataType.VALUE:
return "%.2f" % value
@@ -186,11 +193,10 @@ func formatValue(value: Variant, type: FieldStore.DataType) -> String:
else:
return str(value)
func buildDescription(showNext: bool = false) -> String:
var current = store
var next = update(level + 1, originalStore.duplicate(), UIState.player)
var result = descriptionTemplate
for key in store.keys():
var data = current[key]
var data = readStore(key)
var nextData = next[key]
var type = storeType.get(key, FieldStore.DataType.VALUE)
data = formatValue(data, type)
@@ -202,6 +208,24 @@ func buildDescription(showNext: bool = false) -> String:
text = "[color=cyan]%s[/color]" % data
result = result.replace("$" + key, text)
return result
func rebuildDescription(showNext: bool):
descriptionLabel.text = buildDescription(showNext && (canUpdate(UIState.player) || canInlay()))
func rebuildSublimateOptions(showNext: bool):
for i in sublimateOptionsBox.get_children():
sublimateOptionsBox.remove_child(i)
for sublimate in getSublimateOptions():
var instance = ComponentManager.getUIComponent("SublimateOption").instantiate() as SublimateOptionHandler
instance.use = sublimate
instance.apply.connect(
func():
sublimate.apply(UIState.player, self )
rebuildBaseInfo()
rebuildDescription(showNext)
instance.rebuildInfo()
disruptSublimateOptions()
)
sublimateOptionsBox.add_child(instance)
disruptSublimateOptions()
func readStore(key: String):
return store.get(key, 0) + readStoreExtra(key)
func playSound(sound: String):
@@ -246,8 +270,23 @@ func addStoreExtra(key: String, value: float):
if !storeExtra.has(key):
storeExtra[key] = 0
storeExtra[key] += value
storeExtra[key] = clamp(storeExtra[key], 0, INF)
func readStoreExtra(key: String):
return storeExtra.get(key, 0)
func getSublimateOptions() -> Array[SublimateOption]:
if len(sublimateOptionsStored) == 0:
sublimateOptionsStored = sublimateOptions()
return sublimateOptionsStored
func disruptSublimateOptions():
var children = sublimateOptionsBox.get_children()
children.shuffle()
for index in len(children):
sublimateOptionsBox.remove_child(children[index])
for index in len(children):
var child = children[index]
if child is SublimateOptionHandler:
child.visible = index < 3
sublimateOptionsBox.add_child(child)
# 抽象
func sublimateOptions() -> Array[SublimateOption]:
+74
View File
@@ -0,0 +1,74 @@
class_name CategoryStore
enum Quality {
WASTE,
COMMON,
RARE,
EPIC,
LEGENDARY,
}
enum Topic {
SURVIVAL,
ENERGY,
BULLET,
SPEED,
DAMAGE,
PROBABILITY,
FEED,
DROP,
WEAPON,
SUMMON,
}
static var qualityColorMap = {
Quality.WASTE: Color("808080"),
Quality.COMMON: Color("ffffff"),
Quality.RARE: Color("007eff"),
Quality.EPIC: Color("8100ff"),
Quality.LEGENDARY: Color("ff7100"),
}
static var qualityNameMap = {
Quality.WASTE: "常见",
Quality.COMMON: "普通",
Quality.RARE: "稀有",
Quality.EPIC: "史诗",
Quality.LEGENDARY: "传说"
}
static var qualityRandomWeight = {
Quality.WASTE: 20,
Quality.COMMON: 100,
Quality.RARE: 30,
Quality.EPIC: 10,
Quality.LEGENDARY: 5
}
static var luckInfluence = {
Quality.WASTE: - 0.5,
Quality.COMMON: - 1,
Quality.RARE: 0,
Quality.EPIC: 1,
Quality.LEGENDARY: 2,
}
static var topicNameMap = {
Topic.SURVIVAL: "生存",
Topic.ENERGY: "能量",
Topic.BULLET: "子弹",
Topic.SPEED: "速度",
Topic.DAMAGE: "伤害",
Topic.PROBABILITY: "幸运",
Topic.FEED: "饲料",
Topic.DROP: "掉落物",
Topic.WEAPON: "武器",
Topic.SUMMON: "召唤",
}
static var topicColorMap = {
Topic.SURVIVAL: Color("ff0095"),
Topic.ENERGY: Color("00aeff"),
Topic.BULLET: Color("995900"),
Topic.SPEED: Color("995900"),
Topic.DAMAGE: Color("c070ff"),
Topic.PROBABILITY: Color("ff6c00"),
Topic.FEED: Color("ffffff"),
Topic.DROP: Color("737373"),
Topic.WEAPON: Color("ffd000"),
Topic.SUMMON: Color("00ff9b"),
}
+1
View File
@@ -0,0 +1 @@
uid://cekdcml1yb4g8