mirror of
https://github.com/Rundll86/Dog-Lynx-And-HCN.git
synced 2026-05-27 22:41:56 +08:00
c413744dbf
为多个武器添加了彩蛋文本(tease)和来源信息(sources),包括GrassWall、Hetun、Tree、BigLaser、Cogwheel、Bow、DaoStatue和HXD。同时更新了武器描述和部分属性: - 为BigLaser更新显示名称为"金法阵"并修改描述 - 为DaoStatue增加攻击力从30到50 - 更新HXD的描述文本 - 在Weapon.gd中添加teaseLabel的显示/隐藏逻辑 - 在Rooster.tscn中更换默认武器为DaoStatue
201 lines
6.5 KiB
GDScript
201 lines
6.5 KiB
GDScript
@tool
|
||
extends PanelContainer
|
||
class_name Weapon
|
||
|
||
@export var avatarTexture: Texture2D = null
|
||
@export var displayName: String = "未命名武器"
|
||
@export var quality: WeaponName.Quality = WeaponName.Quality.COMMON
|
||
@export var typeTopic: WeaponName.TypeTopic = WeaponName.TypeTopic.IMPACT
|
||
@export var soulLevel: int = 1
|
||
@export var costBeachball: int = 500
|
||
@export var chargable: bool = false
|
||
@export var oneShoot: bool = false
|
||
@export var store: Dictionary = {
|
||
"atk": 10
|
||
}
|
||
@export var storeType: Dictionary = {
|
||
"atk": FieldStore.DataType.INTEGER
|
||
}
|
||
@export_multiline var descriptionTemplate: String = "造成$atk点伤害。"
|
||
@export var sources: Array[String] = []
|
||
@export var tease: String = ""
|
||
@export var needEnergy: float = 0
|
||
@export var cooldown: float = 100
|
||
@export var debugRebuild: bool = false
|
||
@export var level: int = 0
|
||
|
||
@onready var avatarRect: TextureRect = $"%avatar"
|
||
@onready var nameLabel: WeaponName = $"%name"
|
||
@onready var sourceLabel: Label = $"%source"
|
||
@onready var teaseLabel: Label = $"%tease"
|
||
@onready var energyLabel: Label = $"%energy"
|
||
@onready var beachball: ItemShow = $"%beachball"
|
||
@onready var soul: ItemShow = $"%soul"
|
||
@onready var descriptionLabel: RichTextLabel = $"%description"
|
||
@onready var updateBtn: Button = $"%updateBtn"
|
||
@onready var extractBtn: Button = $"%extractBtn"
|
||
@onready var inlayBtn: Button = $"%inlayBtn"
|
||
@onready var sounds: Node2D = $"%sounds"
|
||
@onready var moveLeftBtn: Button = $"%moveleft"
|
||
@onready var moveRightBtn: Button = $"%moveright"
|
||
|
||
var cooldownTimer: CooldownTimer = null
|
||
var originalStore: Dictionary = {}
|
||
var chargedTime: float = 0
|
||
var attackSpeed: float = 1
|
||
|
||
func _ready():
|
||
cooldownTimer = CooldownTimer.new()
|
||
cooldownTimer.cooldown = cooldown
|
||
originalStore = store
|
||
updateBtn.pressed.connect(
|
||
func():
|
||
apply(UIState.player)
|
||
)
|
||
extractBtn.pressed.connect(
|
||
func():
|
||
if soulLevel > WeaponName.SoulLevel.NORMALIZE:
|
||
UIState.player.getItem({
|
||
ItemStore.ItemType.SOUL: soulLevel - 1
|
||
})
|
||
soulLevel -= 1
|
||
updateStore(level, UIState.player)
|
||
rebuildInfo()
|
||
)
|
||
inlayBtn.pressed.connect(
|
||
func():
|
||
if soulLevel < WeaponName.SoulLevel.INFINITY:
|
||
if UIState.player.useItem({
|
||
ItemStore.ItemType.SOUL: soulLevel
|
||
}):
|
||
soulLevel += 1
|
||
updateStore(level, UIState.player)
|
||
rebuildInfo()
|
||
)
|
||
moveLeftBtn.pressed.connect(
|
||
func():
|
||
if get_parent():
|
||
var myIndex = get_index()
|
||
var leftIndex = max(myIndex - 1, 0)
|
||
get_parent().move_child(self , leftIndex)
|
||
ArrayTool.swap(UIState.player.weapons, myIndex, leftIndex)
|
||
UIState.player.rebuildWeaponIcons()
|
||
)
|
||
moveRightBtn.pressed.connect(
|
||
func():
|
||
if get_parent():
|
||
var myIndex = get_index()
|
||
var rightIndex = min(myIndex + 1, get_parent().get_child_count() - 1)
|
||
get_parent().move_child(self , rightIndex)
|
||
ArrayTool.swap(UIState.player.weapons, myIndex, rightIndex)
|
||
UIState.player.rebuildWeaponIcons()
|
||
)
|
||
for i in sounds.get_children():
|
||
i.process_mode = ProcessMode.PROCESS_MODE_ALWAYS
|
||
rebuildInfo()
|
||
debugRebuild = false # 只能在编辑器里打开
|
||
func _physics_process(_delta):
|
||
if debugRebuild:
|
||
rebuildInfo()
|
||
|
||
func canUpdate():
|
||
return UIState.player.hasItem({ItemStore.ItemType.BEACHBALL: costBeachball})
|
||
func canInlay():
|
||
return UIState.player.hasItem({ItemStore.ItemType.SOUL: soulLevel})
|
||
func apply(entity: EntityBase) -> bool:
|
||
if canUpdate():
|
||
level += 1
|
||
entity.inventory[ItemStore.ItemType.BEACHBALL] -= costBeachball
|
||
updateStore(level, entity)
|
||
costBeachball = floor(GameRule.weaponUpdateCost * costBeachball)
|
||
rebuildInfo(true)
|
||
return true
|
||
return false
|
||
func updateStore(to: int, entity: EntityBase):
|
||
store = update(to, originalStore.duplicate(), entity)
|
||
func multipiler() -> float:
|
||
if is_instance_valid(UIState.player):
|
||
return 1 - UIState.player.fields.get(FieldStore.Entity.PRICE_REDUCTION)
|
||
else:
|
||
return 1
|
||
func rebuildInfo(showNext: bool = false):
|
||
avatarRect.texture = avatarTexture
|
||
nameLabel.displayName = displayName
|
||
nameLabel.quality = quality
|
||
nameLabel.typeTopic = typeTopic
|
||
nameLabel.soulLevel = soulLevel
|
||
nameLabel.level = level
|
||
sourceLabel.text = " × ".join(sources)
|
||
if len(tease) > 0:
|
||
teaseLabel.text = "“%s”" % tease
|
||
teaseLabel.show()
|
||
else:
|
||
teaseLabel.hide()
|
||
energyLabel.text = "%.1f" % needEnergy
|
||
beachball.count = costBeachball
|
||
soul.count = soulLevel
|
||
if is_instance_valid(UIState.player):
|
||
beachball.enough = canUpdate()
|
||
soul.enough = canInlay()
|
||
descriptionLabel.text = buildDescription(showNext && (canUpdate() || canInlay()))
|
||
func formatValue(value: Variant, type: FieldStore.DataType) -> String:
|
||
if type == FieldStore.DataType.VALUE:
|
||
return "%.2f" % value
|
||
elif type == FieldStore.DataType.INTEGER:
|
||
return "%d" % value
|
||
elif type == FieldStore.DataType.PERCENT:
|
||
return ("%.1f" % (value * 100)) + "%"
|
||
elif type == FieldStore.DataType.ANGLE:
|
||
return "%.1f°" % value
|
||
elif type == FieldStore.DataType.FREQUENCY:
|
||
return "%.1fHz" % value
|
||
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 nextData = next[key]
|
||
var type = storeType.get(key, FieldStore.DataType.VALUE)
|
||
data = formatValue(data, type)
|
||
nextData = formatValue(nextData, type)
|
||
var text
|
||
if showNext:
|
||
text = "[color=cyan]%s[/color]→[color=yellow]%s[/color]" % [data, nextData]
|
||
else:
|
||
text = "[color=cyan]%s[/color]" % data
|
||
result = result.replace("$" + key, text)
|
||
return "[center]%s[/center]" % result
|
||
func readStore(key: String, default: Variant = null):
|
||
return store.get(key, default)
|
||
func playSound(sound: String):
|
||
var body = sounds.get_node_or_null(sound)
|
||
if body is AudioStreamPlayer2D:
|
||
var cloned = body.duplicate() as AudioStreamPlayer2D
|
||
add_child(cloned)
|
||
cloned.play()
|
||
await cloned.finished
|
||
cloned.queue_free()
|
||
func canAttackBy(entity: EntityBase):
|
||
cooldownTimer.speedScale = entity.fields.get(FieldStore.Entity.ATTACK_SPEED) * attackSpeed
|
||
return cooldownTimer.isCooldowned() and entity.isEnergyEnough(needEnergy) and checkAttack(entity)
|
||
func tryAttack(entity: EntityBase):
|
||
if canAttackBy(entity):
|
||
var result = await attack(entity)
|
||
if result:
|
||
cooldownTimer.start()
|
||
entity.useEnergy(needEnergy)
|
||
return result
|
||
func charged(base: float, percent: float):
|
||
return base * sqrt(1 + chargedTime / 15 * percent)
|
||
|
||
# 抽象
|
||
func update(_to: int, origin: Dictionary, _entity: EntityBase):
|
||
return origin
|
||
func checkAttack(_entity: EntityBase) -> bool:
|
||
return true
|
||
func attack(_entity: EntityBase):
|
||
pass
|