1
1
mirror of https://github.com/Rundll86/Dog-Lynx-And-HCN.git synced 2026-05-27 22:41:56 +08:00
Files
Dog-Lynx-And-HCN/scripts/Structs/Weapon.gd
T
fallingshrimp 53412c0968 feat(武器系统): 新增可蓄力钢管武器及相关功能
实现钢管武器的蓄力攻击机制,包括:
- 添加 Pipe 武器和 PipeBullet 子弹脚本及场景
- 在 Weapon 类中增加蓄力相关属性和方法
- 修改 Rooster 角色以支持武器蓄力功能
- 添加武器蓄力时间计算和伤害加成逻辑
2026-02-05 20:04:39 +08:00

185 lines
5.9 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 store: Dictionary = {
"atk": 10
}
@export var storeType: Dictionary = {
"atk": FieldStore.DataType.INTEGER
}
@export_multiline var descriptionTemplate: String = "造成$atk点伤害。"
@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 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
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
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 tryAttack(entity: EntityBase):
cooldownTimer.speedScale = entity.fields.get(FieldStore.Entity.ATTACK_SPEED)
if cooldownTimer.isCooldowned():
var result = await attack(entity)
if result:
cooldownTimer.start()
entity.useEnergy(needEnergy)
return result
func charged(base: float, percent: float):
return base * (1 + chargedTime / 50 * percent)
# 抽象
func update(_to: int, origin: Dictionary, _entity: EntityBase):
return origin
func attack(_entity: EntityBase):
pass