feat: 扩展游戏内容和地图系统优化
- MiniMap: 添加缩放/平移功能,优化节点显示样式 - 新增洞穴相关敌人和Boss(洞穴蝙蝠、洞穴领主) - 新增义体类物品(钢制义臂、光学义眼、真皮护甲) - 扩展武器技能系统(剑、斧、钝器、弓箭精通) - 更新商店配置和义体相关功能 - 完善玩家/游戏Store状态管理 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,7 +13,10 @@
|
|||||||
"Bash(git remote add:*)",
|
"Bash(git remote add:*)",
|
||||||
"Bash(git add:*)",
|
"Bash(git add:*)",
|
||||||
"Bash(git commit:*)",
|
"Bash(git commit:*)",
|
||||||
"Bash(git push:*)"
|
"Bash(git push:*)",
|
||||||
|
"Read(//d/uniapp/app_test/wwa3/**)",
|
||||||
|
"Bash(npx eslint:*)",
|
||||||
|
"mcp__playwright__browser_close"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,18 @@
|
|||||||
<view class="mini-map">
|
<view class="mini-map">
|
||||||
<!-- 地图容器 -->
|
<!-- 地图容器 -->
|
||||||
<view class="mini-map__container">
|
<view class="mini-map__container">
|
||||||
|
<scroll-view
|
||||||
|
class="mini-map__scroll"
|
||||||
|
scroll-x
|
||||||
|
scroll-y
|
||||||
|
:scroll-left="scrollLeft"
|
||||||
|
:scroll-top="scrollTop"
|
||||||
|
@scroll="onScroll"
|
||||||
|
>
|
||||||
|
<view
|
||||||
|
class="mini-map__content"
|
||||||
|
:style="contentStyle"
|
||||||
|
>
|
||||||
<!-- 连接线层 -->
|
<!-- 连接线层 -->
|
||||||
<view class="mini-map__connections">
|
<view class="mini-map__connections">
|
||||||
<view
|
<view
|
||||||
@@ -21,6 +33,9 @@
|
|||||||
:class="getNodeClass(node)"
|
:class="getNodeClass(node)"
|
||||||
:style="getNodeStyle(node)"
|
:style="getNodeStyle(node)"
|
||||||
@click="handleNodeClick(node)"
|
@click="handleNodeClick(node)"
|
||||||
|
@touchstart="onTouchStart"
|
||||||
|
@touchmove="onTouchMove"
|
||||||
|
@touchend="onTouchEnd"
|
||||||
>
|
>
|
||||||
<!-- 节点圆点 -->
|
<!-- 节点圆点 -->
|
||||||
<view class="node__dot"></view>
|
<view class="node__dot"></view>
|
||||||
@@ -38,6 +53,21 @@
|
|||||||
<text v-else-if="getDistance(node) > 0" class="node__distance">{{ getDistance(node) }}</text>
|
<text v-else-if="getDistance(node) > 0" class="node__distance">{{ getDistance(node) }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
|
||||||
|
<!-- 缩放控制 -->
|
||||||
|
<view class="mini-map__zoom-controls">
|
||||||
|
<view class="zoom-btn" @click="zoomIn">
|
||||||
|
<text class="zoom-icon">+</text>
|
||||||
|
</view>
|
||||||
|
<view class="zoom-btn" @click="resetZoom">
|
||||||
|
<text class="zoom-icon">⟲</text>
|
||||||
|
</view>
|
||||||
|
<view class="zoom-btn" @click="zoomOut">
|
||||||
|
<text class="zoom-icon">−</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 图例 -->
|
<!-- 图例 -->
|
||||||
<view class="mini-map__legend">
|
<view class="mini-map__legend">
|
||||||
@@ -79,28 +109,45 @@ const player = usePlayerStore()
|
|||||||
const mapData = ref({ nodes: [], edges: [], width: 300, height: 400 })
|
const mapData = ref({ nodes: [], edges: [], width: 300, height: 400 })
|
||||||
const selectedPath = ref([])
|
const selectedPath = ref([])
|
||||||
|
|
||||||
|
// 缩放和平移状态
|
||||||
|
const zoom = ref(1)
|
||||||
|
const scrollLeft = ref(0)
|
||||||
|
const scrollTop = ref(0)
|
||||||
|
const currentLocationNode = ref(null)
|
||||||
|
|
||||||
|
// 容器尺寸
|
||||||
|
const containerWidth = 280
|
||||||
|
const containerHeight = 300
|
||||||
|
|
||||||
|
// 触摸拖动状态
|
||||||
|
const touchStartX = ref(0)
|
||||||
|
const touchStartY = ref(0)
|
||||||
|
const isDragging = ref(false)
|
||||||
|
|
||||||
const currentLocation = computed(() => player.currentLocation)
|
const currentLocation = computed(() => player.currentLocation)
|
||||||
|
|
||||||
|
// 内容样式
|
||||||
|
const contentStyle = computed(() => {
|
||||||
|
return {
|
||||||
|
width: (containerWidth * zoom.value) + 'px',
|
||||||
|
height: (containerHeight * zoom.value) + 'px',
|
||||||
|
transformOrigin: 'center center'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// 初始化地图
|
// 初始化地图
|
||||||
function initMap() {
|
function initMap() {
|
||||||
const data = getMapData(player.currentLocation)
|
const data = getMapData(player.currentLocation)
|
||||||
|
|
||||||
// 缩放坐标以适应容器
|
// 不再缩放以适应容器,使用原始坐标
|
||||||
const containerWidth = 280
|
// 但确保地图足够大
|
||||||
const containerHeight = 340
|
const padding = 40
|
||||||
const scaleX = containerWidth / data.width
|
|
||||||
const scaleY = containerHeight / data.height
|
|
||||||
const scale = Math.min(scaleX, scaleY, 1)
|
|
||||||
|
|
||||||
// 居中偏移
|
|
||||||
const offsetX = (containerWidth - data.width * scale) / 2 + 10
|
|
||||||
const offsetY = (containerHeight - data.height * scale) / 2 + 10
|
|
||||||
|
|
||||||
mapData.value = {
|
mapData.value = {
|
||||||
nodes: data.nodes.map(n => ({
|
nodes: data.nodes.map(n => ({
|
||||||
...n,
|
...n,
|
||||||
x: n.x * scale + offsetX,
|
x: n.x,
|
||||||
y: n.y * scale + offsetY
|
y: n.y
|
||||||
})),
|
})),
|
||||||
edges: data.edges,
|
edges: data.edges,
|
||||||
width: data.width,
|
width: data.width,
|
||||||
@@ -108,21 +155,74 @@ function initMap() {
|
|||||||
reachable: data.reachable
|
reachable: data.reachable
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新缩放比例供样式使用
|
// 找到当前节点并居中
|
||||||
updateNodeStyles()
|
centerOnLocation()
|
||||||
selectedPath.value = []
|
selectedPath.value = []
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新节点样式(转换为rpx)
|
// 居中到当前位置
|
||||||
function updateNodeStyles() {
|
function centerOnLocation() {
|
||||||
// 在实际渲染时使用百分比或rpx
|
const currentNode = mapData.value.nodes.find(n => n.id === currentLocation.value)
|
||||||
|
if (!currentNode) return
|
||||||
|
|
||||||
|
currentLocationNode.value = currentNode
|
||||||
|
|
||||||
|
// 计算需要滚动的位置以居中当前节点
|
||||||
|
// 考虑缩放比例
|
||||||
|
const targetLeft = currentNode.x * zoom.value - containerWidth / 2
|
||||||
|
const targetTop = currentNode.y * zoom.value - containerHeight / 2
|
||||||
|
|
||||||
|
scrollLeft.value = Math.max(0, targetLeft)
|
||||||
|
scrollTop.value = Math.max(0, targetTop)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 缩放控制
|
||||||
|
function zoomIn() {
|
||||||
|
zoom.value = Math.min(2, zoom.value + 0.2)
|
||||||
|
centerOnLocation()
|
||||||
|
}
|
||||||
|
|
||||||
|
function zoomOut() {
|
||||||
|
zoom.value = Math.max(0.5, zoom.value - 0.2)
|
||||||
|
centerOnLocation()
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetZoom() {
|
||||||
|
zoom.value = 1
|
||||||
|
centerOnLocation()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 触摸事件处理(用于拖动)
|
||||||
|
function onTouchStart(e) {
|
||||||
|
touchStartX.value = e.touches[0].clientX
|
||||||
|
touchStartY.value = e.touches[0].clientY
|
||||||
|
isDragging.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function onTouchMove(e) {
|
||||||
|
const deltaX = e.touches[0].clientX - touchStartX.value
|
||||||
|
const deltaY = e.touches[0].clientY - touchStartY.value
|
||||||
|
|
||||||
|
if (Math.abs(deltaX) > 5 || Math.abs(deltaY) > 5) {
|
||||||
|
isDragging.value = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onTouchEnd(e) {
|
||||||
|
// 如果不是拖动,则视为点击
|
||||||
|
// 这里的处理在 handleNodeClick 中完成
|
||||||
|
}
|
||||||
|
|
||||||
|
// 滚动事件
|
||||||
|
function onScroll(e) {
|
||||||
|
// 可以在这里记录滚动位置
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取节点样式
|
// 获取节点样式
|
||||||
function getNodeStyle(node) {
|
function getNodeStyle(node) {
|
||||||
return {
|
return {
|
||||||
left: node.x + 'px',
|
left: (node.x * zoom.value) + 'px',
|
||||||
top: node.y + 'px'
|
top: (node.y * zoom.value) + 'px'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,14 +280,14 @@ function getLineStyle(edge) {
|
|||||||
|
|
||||||
if (!fromNode || !toNode) return {}
|
if (!fromNode || !toNode) return {}
|
||||||
|
|
||||||
const dx = toNode.x - fromNode.x
|
const dx = (toNode.x - fromNode.x) * zoom.value
|
||||||
const dy = toNode.y - fromNode.y
|
const dy = (toNode.y - fromNode.y) * zoom.value
|
||||||
const length = Math.sqrt(dx * dx + dy * dy)
|
const length = Math.sqrt(dx * dx + dy * dy)
|
||||||
const angle = Math.atan2(dy, dx) * 180 / Math.PI
|
const angle = Math.atan2(dy, dx) * 180 / Math.PI
|
||||||
|
|
||||||
return {
|
return {
|
||||||
left: fromNode.x + 'px',
|
left: (fromNode.x * zoom.value) + 'px',
|
||||||
top: fromNode.y + 'px',
|
top: (fromNode.y * zoom.value) + 'px',
|
||||||
width: length + 'px',
|
width: length + 'px',
|
||||||
transform: `rotate(${angle}deg)`
|
transform: `rotate(${angle}deg)`
|
||||||
}
|
}
|
||||||
@@ -252,6 +352,17 @@ onMounted(() => {
|
|||||||
border: 2rpx solid #4a5568;
|
border: 2rpx solid #4a5568;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__scroll {
|
||||||
|
width: 100%;
|
||||||
|
height: 300rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
position: relative;
|
||||||
|
min-width: 100%;
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
&__connections {
|
&__connections {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
@@ -276,6 +387,38 @@ onMounted(() => {
|
|||||||
border: 1rpx solid $accent;
|
border: 1rpx solid $accent;
|
||||||
border-radius: 8rpx;
|
border-radius: 8rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__zoom-controls {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 12rpx;
|
||||||
|
right: 12rpx;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8rpx;
|
||||||
|
z-index: 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.zoom-btn {
|
||||||
|
width: 56rpx;
|
||||||
|
height: 56rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: rgba($bg-primary, 0.8);
|
||||||
|
border: 1rpx solid rgba($accent, 0.5);
|
||||||
|
border-radius: 8rpx;
|
||||||
|
backdrop-filter: blur(4rpx);
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background-color: rgba($accent, 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.zoom-icon {
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: $accent;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.connection-line {
|
.connection-line {
|
||||||
|
|||||||
@@ -14,11 +14,16 @@ export const ENEMY_CONFIG = {
|
|||||||
health: 35,
|
health: 35,
|
||||||
attack: 8,
|
attack: 8,
|
||||||
defense: 2,
|
defense: 2,
|
||||||
|
strength: 8, // 力量,影响攻击
|
||||||
|
agility: 6, // 敏捷,影响闪避(降低EP,提高玩家命中率)
|
||||||
|
dexterity: 7, // 灵巧,影响命中
|
||||||
|
intuition: 3, // 智力,影响AP/EP
|
||||||
|
vitality: 8, // 体质
|
||||||
speed: 1.2
|
speed: 1.2
|
||||||
},
|
},
|
||||||
derivedStats: {
|
derivedStats: {
|
||||||
ap: 8,
|
ap: 8,
|
||||||
ep: 10
|
ep: 6 // 降低EP值,使玩家更容易命中
|
||||||
},
|
},
|
||||||
expReward: 20,
|
expReward: 20,
|
||||||
skillExpReward: 12,
|
skillExpReward: 12,
|
||||||
@@ -36,11 +41,16 @@ export const ENEMY_CONFIG = {
|
|||||||
health: 20,
|
health: 20,
|
||||||
attack: 5,
|
attack: 5,
|
||||||
defense: 1,
|
defense: 1,
|
||||||
|
strength: 5,
|
||||||
|
agility: 10, // 高敏捷,难命中
|
||||||
|
dexterity: 6,
|
||||||
|
intuition: 2,
|
||||||
|
vitality: 5,
|
||||||
speed: 1.5
|
speed: 1.5
|
||||||
},
|
},
|
||||||
derivedStats: {
|
derivedStats: {
|
||||||
ap: 6,
|
ap: 6,
|
||||||
ep: 12
|
ep: 11 // 高闪避,符合老鼠特性
|
||||||
},
|
},
|
||||||
expReward: 10,
|
expReward: 10,
|
||||||
skillExpReward: 6,
|
skillExpReward: 6,
|
||||||
@@ -58,11 +68,16 @@ export const ENEMY_CONFIG = {
|
|||||||
health: 50,
|
health: 50,
|
||||||
attack: 15,
|
attack: 15,
|
||||||
defense: 5,
|
defense: 5,
|
||||||
|
strength: 14,
|
||||||
|
agility: 10,
|
||||||
|
dexterity: 12,
|
||||||
|
intuition: 6,
|
||||||
|
vitality: 12,
|
||||||
speed: 1.3
|
speed: 1.3
|
||||||
},
|
},
|
||||||
derivedStats: {
|
derivedStats: {
|
||||||
ap: 14,
|
ap: 14,
|
||||||
ep: 13
|
ep: 11
|
||||||
},
|
},
|
||||||
expReward: 40,
|
expReward: 40,
|
||||||
skillExpReward: 20,
|
skillExpReward: 20,
|
||||||
@@ -80,6 +95,11 @@ export const ENEMY_CONFIG = {
|
|||||||
health: 60,
|
health: 60,
|
||||||
attack: 18,
|
attack: 18,
|
||||||
defense: 8,
|
defense: 8,
|
||||||
|
strength: 16,
|
||||||
|
agility: 9,
|
||||||
|
dexterity: 14,
|
||||||
|
intuition: 8,
|
||||||
|
vitality: 15,
|
||||||
speed: 1.0
|
speed: 1.0
|
||||||
},
|
},
|
||||||
derivedStats: {
|
derivedStats: {
|
||||||
@@ -103,17 +123,23 @@ export const ENEMY_CONFIG = {
|
|||||||
health: 250,
|
health: 250,
|
||||||
attack: 30,
|
attack: 30,
|
||||||
defense: 15,
|
defense: 15,
|
||||||
|
strength: 25,
|
||||||
|
agility: 14,
|
||||||
|
dexterity: 20,
|
||||||
|
intuition: 12,
|
||||||
|
vitality: 25,
|
||||||
speed: 1.1
|
speed: 1.1
|
||||||
},
|
},
|
||||||
derivedStats: {
|
derivedStats: {
|
||||||
ap: 30,
|
ap: 30,
|
||||||
ep: 18
|
ep: 16
|
||||||
},
|
},
|
||||||
expReward: 200,
|
expReward: 200,
|
||||||
skillExpReward: 80,
|
skillExpReward: 80,
|
||||||
drops: [
|
drops: [
|
||||||
{ itemId: 'basement_key', chance: 1.0, count: { min: 1, max: 1 } },
|
{ itemId: 'basement_key', chance: 1.0, count: { min: 1, max: 1 } },
|
||||||
{ itemId: 'dog_skin', chance: 0.5, count: { min: 2, max: 4 } }
|
{ itemId: 'dog_skin', chance: 0.5, count: { min: 2, max: 4 } },
|
||||||
|
{ itemId: 'steel_arm_prosthetic', chance: 0.3, count: { min: 1, max: 1 }, fixedQuality: true } // 义体掉落
|
||||||
],
|
],
|
||||||
isBoss: true
|
isBoss: true
|
||||||
},
|
},
|
||||||
@@ -127,11 +153,16 @@ export const ENEMY_CONFIG = {
|
|||||||
health: 40,
|
health: 40,
|
||||||
attack: 25,
|
attack: 25,
|
||||||
defense: 3,
|
defense: 3,
|
||||||
|
strength: 20,
|
||||||
|
agility: 16, // 高闪避
|
||||||
|
dexterity: 18,
|
||||||
|
intuition: 6,
|
||||||
|
vitality: 8,
|
||||||
speed: 1.8
|
speed: 1.8
|
||||||
},
|
},
|
||||||
derivedStats: {
|
derivedStats: {
|
||||||
ap: 22,
|
ap: 22,
|
||||||
ep: 24
|
ep: 18 // 高闪避,但不是不可能命中
|
||||||
},
|
},
|
||||||
expReward: 70,
|
expReward: 70,
|
||||||
skillExpReward: 35,
|
skillExpReward: 35,
|
||||||
@@ -149,17 +180,24 @@ export const ENEMY_CONFIG = {
|
|||||||
health: 500,
|
health: 500,
|
||||||
attack: 50,
|
attack: 50,
|
||||||
defense: 25,
|
defense: 25,
|
||||||
|
strength: 45,
|
||||||
|
agility: 18,
|
||||||
|
dexterity: 35,
|
||||||
|
intuition: 20,
|
||||||
|
vitality: 50,
|
||||||
speed: 0.9
|
speed: 0.9
|
||||||
},
|
},
|
||||||
derivedStats: {
|
derivedStats: {
|
||||||
ap: 50,
|
ap: 50,
|
||||||
ep: 25
|
ep: 22
|
||||||
},
|
},
|
||||||
expReward: 500,
|
expReward: 500,
|
||||||
skillExpReward: 200,
|
skillExpReward: 200,
|
||||||
drops: [
|
drops: [
|
||||||
{ itemId: 'rare_gem', chance: 0.8, count: { min: 1, max: 1 } },
|
{ itemId: 'rare_gem', chance: 0.8, count: { min: 1, max: 1 } },
|
||||||
{ itemId: 'iron_sword', chance: 0.3, count: { min: 1, max: 1 } }
|
{ itemId: 'iron_sword', chance: 0.3, count: { min: 1, max: 1 } },
|
||||||
|
{ itemId: 'optical_eye_prosthetic', chance: 0.4, count: { min: 1, max: 1 }, fixedQuality: true },
|
||||||
|
{ itemId: 'dermal_armor_prosthetic', chance: 0.3, count: { min: 1, max: 1 }, fixedQuality: true }
|
||||||
],
|
],
|
||||||
isBoss: true
|
isBoss: true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -494,6 +494,71 @@ export const ITEM_CONFIG = {
|
|||||||
description: '一本神圣的书籍,可以用来祈祷。',
|
description: '一本神圣的书籍,可以用来祈祷。',
|
||||||
stackable: false,
|
stackable: false,
|
||||||
effect: { sanity: 10 }
|
effect: { sanity: 10 }
|
||||||
|
},
|
||||||
|
|
||||||
|
// ===== 义体(仅Boss掉落,无品质) =====
|
||||||
|
steel_arm_prosthetic: {
|
||||||
|
id: 'steel_arm_prosthetic',
|
||||||
|
name: '合金臂义体',
|
||||||
|
type: 'prosthetic',
|
||||||
|
subtype: 'arm',
|
||||||
|
icon: '🦾',
|
||||||
|
baseValue: 2000,
|
||||||
|
quality: 150, // 固定品质
|
||||||
|
fixedQuality: true, // 标记为固定品质
|
||||||
|
stats: { strength: 8, attack: 10 },
|
||||||
|
skill: 'steel_arm_slash', // 提供的技能
|
||||||
|
skillUnlocked: true,
|
||||||
|
description: '用合金制成的义体手臂,大幅增强力量。可使用【合金斩击】技能。',
|
||||||
|
bossOnly: true // 仅Boss掉落
|
||||||
|
},
|
||||||
|
|
||||||
|
optical_eye_prosthetic: {
|
||||||
|
id: 'optical_eye_prosthetic',
|
||||||
|
name: '光学义眼',
|
||||||
|
type: 'prosthetic',
|
||||||
|
subtype: 'head',
|
||||||
|
icon: '👁️',
|
||||||
|
baseValue: 1800,
|
||||||
|
quality: 140,
|
||||||
|
fixedQuality: true,
|
||||||
|
stats: { dexterity: 8, intuition: 5 },
|
||||||
|
skill: 'target_lock', // 提供的技能
|
||||||
|
skillUnlocked: true,
|
||||||
|
description: '植入式义眼,提高命中和暴击。可使用【目标锁定】技能。',
|
||||||
|
bossOnly: true
|
||||||
|
},
|
||||||
|
|
||||||
|
spinal_boost_prosthetic: {
|
||||||
|
id: 'spinal_boost_prosthetic',
|
||||||
|
name: '脊柱加速器',
|
||||||
|
type: 'prosthetic',
|
||||||
|
subtype: 'spine',
|
||||||
|
icon: '🦴',
|
||||||
|
baseValue: 2500,
|
||||||
|
quality: 160,
|
||||||
|
fixedQuality: true,
|
||||||
|
stats: { agility: 10, speed: 15 },
|
||||||
|
skill: 'overdrive', // 提供的技能
|
||||||
|
skillUnlocked: true,
|
||||||
|
description: '植入脊柱的加速装置,极大提升速度。可使用【过载】技能。',
|
||||||
|
bossOnly: true
|
||||||
|
},
|
||||||
|
|
||||||
|
dermal_armor_prosthetic: {
|
||||||
|
id: 'dermal_armor_prosthetic',
|
||||||
|
name: '真皮装甲',
|
||||||
|
type: 'prosthetic',
|
||||||
|
subtype: 'body',
|
||||||
|
icon: '🦾',
|
||||||
|
baseValue: 2200,
|
||||||
|
quality: 155,
|
||||||
|
fixedQuality: true,
|
||||||
|
stats: { defense: 15, vitality: 8 },
|
||||||
|
skill: 'iron_skin', // 提供的技能
|
||||||
|
skillUnlocked: true,
|
||||||
|
description: '植入皮下的装甲层,提供强大防御。可使用【钢铁皮肤】技能。',
|
||||||
|
bossOnly: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,6 +571,7 @@ export const ITEM_CATEGORIES = {
|
|||||||
armor: { id: 'armor', name: '防具', icon: '🛡️' },
|
armor: { id: 'armor', name: '防具', icon: '🛡️' },
|
||||||
shield: { id: 'shield', name: '盾牌', icon: '🛡️' },
|
shield: { id: 'shield', name: '盾牌', icon: '🛡️' },
|
||||||
accessory: { id: 'accessory', name: '饰品', icon: '💍' },
|
accessory: { id: 'accessory', name: '饰品', icon: '💍' },
|
||||||
|
prosthetic: { id: 'prosthetic', name: '义体', icon: '🦾' },
|
||||||
consumable: { id: 'consumable', name: '消耗品', icon: '🧪' },
|
consumable: { id: 'consumable', name: '消耗品', icon: '🧪' },
|
||||||
book: { id: 'book', name: '书籍', icon: '📖' },
|
book: { id: 'book', name: '书籍', icon: '📖' },
|
||||||
material: { id: 'material', name: '素材', icon: '📦' },
|
material: { id: 'material', name: '素材', icon: '📦' },
|
||||||
|
|||||||
106
config/skills.js
106
config/skills.js
@@ -111,5 +111,111 @@ export const SKILL_CONFIG = {
|
|||||||
15: { desc: '所有制药成功率+20%', effect: { herbingSuccessRate: 20 } }
|
15: { desc: '所有制药成功率+20%', effect: { herbingSuccessRate: 20 } }
|
||||||
},
|
},
|
||||||
unlockCondition: null
|
unlockCondition: null
|
||||||
|
},
|
||||||
|
|
||||||
|
// ===== 义体相关技能 =====
|
||||||
|
prosthetic_adaptation: {
|
||||||
|
id: 'prosthetic_adaptation',
|
||||||
|
name: '义体适应性',
|
||||||
|
type: 'passive',
|
||||||
|
category: 'prosthetic',
|
||||||
|
icon: '🦾',
|
||||||
|
maxLevel: 20,
|
||||||
|
expPerLevel: (level) => level * 50,
|
||||||
|
parentSkill: null,
|
||||||
|
milestones: {
|
||||||
|
1: { desc: '解锁义体装备功能', effect: {} },
|
||||||
|
3: { desc: '义体技能伤害+10%', effect: { prostheticSkillDamage: 10 } },
|
||||||
|
5: { desc: '义体耐力消耗-20%', effect: { prostheticStaminaCost: -0.2 } },
|
||||||
|
10: { desc: '义体技能伤害+25%', effect: { prostheticSkillDamage: 25 } },
|
||||||
|
15: { desc: '义体冷却时间-30%', effect: { prostheticCooldown: -0.3 } },
|
||||||
|
20: { desc: '义体所有效果+50%', effect: { prostheticAllEffect: 50 } }
|
||||||
|
},
|
||||||
|
unlockCondition: {
|
||||||
|
type: 'item',
|
||||||
|
item: 'any_prosthetic'
|
||||||
|
},
|
||||||
|
desc: '使用义体时提升,增强义体效果'
|
||||||
|
},
|
||||||
|
|
||||||
|
// ===== 义体攻击技能 =====
|
||||||
|
steel_arm_slash: {
|
||||||
|
id: 'steel_arm_slash',
|
||||||
|
name: '合金斩击',
|
||||||
|
type: 'combat',
|
||||||
|
category: 'prosthetic_skill',
|
||||||
|
icon: '⚔️',
|
||||||
|
maxLevel: 1, // 义体技能不可升级
|
||||||
|
expPerLevel: () => 0,
|
||||||
|
parentSkill: null,
|
||||||
|
milestones: {},
|
||||||
|
unlockCondition: {
|
||||||
|
type: 'equipment',
|
||||||
|
item: 'steel_arm_prosthetic'
|
||||||
|
},
|
||||||
|
desc: '合金臂义体专属技能。造成200%攻击力的伤害。',
|
||||||
|
staminaCost: 15,
|
||||||
|
cooldown: 0,
|
||||||
|
damageMultiplier: 2.0
|
||||||
|
},
|
||||||
|
|
||||||
|
target_lock: {
|
||||||
|
id: 'target_lock',
|
||||||
|
name: '目标锁定',
|
||||||
|
type: 'combat',
|
||||||
|
category: 'prosthetic_skill',
|
||||||
|
icon: '🎯',
|
||||||
|
maxLevel: 1,
|
||||||
|
expPerLevel: () => 0,
|
||||||
|
parentSkill: null,
|
||||||
|
milestones: {},
|
||||||
|
unlockCondition: {
|
||||||
|
type: 'equipment',
|
||||||
|
item: 'optical_eye_prosthetic'
|
||||||
|
},
|
||||||
|
desc: '光学义眼专属技能。下一次攻击必定暴击。',
|
||||||
|
staminaCost: 8,
|
||||||
|
cooldown: 3,
|
||||||
|
buff: 'guaranteedCrit'
|
||||||
|
},
|
||||||
|
|
||||||
|
overdrive: {
|
||||||
|
id: 'overdrive',
|
||||||
|
name: '过载',
|
||||||
|
type: 'combat',
|
||||||
|
category: 'prosthetic_skill',
|
||||||
|
icon: '⚡',
|
||||||
|
maxLevel: 1,
|
||||||
|
expPerLevel: () => 0,
|
||||||
|
parentSkill: null,
|
||||||
|
milestones: {},
|
||||||
|
unlockCondition: {
|
||||||
|
type: 'equipment',
|
||||||
|
item: 'spinal_boost_prosthetic'
|
||||||
|
},
|
||||||
|
desc: '脊柱加速器专属技能。3秒内攻击速度+100%。',
|
||||||
|
staminaCost: 20,
|
||||||
|
cooldown: 5,
|
||||||
|
buff: 'attackSpeedBoost'
|
||||||
|
},
|
||||||
|
|
||||||
|
iron_skin: {
|
||||||
|
id: 'iron_skin',
|
||||||
|
name: '钢铁皮肤',
|
||||||
|
type: 'combat',
|
||||||
|
category: 'prosthetic_skill',
|
||||||
|
icon: '🛡️',
|
||||||
|
maxLevel: 1,
|
||||||
|
expPerLevel: () => 0,
|
||||||
|
parentSkill: null,
|
||||||
|
milestones: {},
|
||||||
|
unlockCondition: {
|
||||||
|
type: 'equipment',
|
||||||
|
item: 'dermal_armor_prosthetic'
|
||||||
|
},
|
||||||
|
desc: '真皮装甲专属技能。3秒内防御力+50%。',
|
||||||
|
staminaCost: 15,
|
||||||
|
cooldown: 4,
|
||||||
|
buff: 'defenseBoost'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ export const useGameStore = defineStore('game', () => {
|
|||||||
const combatState = ref(null)
|
const combatState = ref(null)
|
||||||
const autoCombat = ref(false) // 自动战斗模式
|
const autoCombat = ref(false) // 自动战斗模式
|
||||||
const isSearching = ref(false) // 正在寻找敌人中(自动战斗间隔期间)
|
const isSearching = ref(false) // 正在寻找敌人中(自动战斗间隔期间)
|
||||||
|
const preferredStance = ref('balance') // 记住玩家偏好的战斗姿态
|
||||||
|
|
||||||
// 活动任务
|
// 活动任务
|
||||||
const activeTasks = ref([])
|
const activeTasks = ref([])
|
||||||
@@ -45,6 +46,16 @@ export const useGameStore = defineStore('game', () => {
|
|||||||
// 当前事件
|
// 当前事件
|
||||||
const currentEvent = ref(null)
|
const currentEvent = ref(null)
|
||||||
|
|
||||||
|
// 成就系统
|
||||||
|
const achievements = ref({})
|
||||||
|
const achievementProgress = ref({
|
||||||
|
totalKills: 0,
|
||||||
|
bossKills: 0,
|
||||||
|
prostheticEquipped: 0,
|
||||||
|
visitedLocations: new Set(),
|
||||||
|
totalEarned: 0
|
||||||
|
})
|
||||||
|
|
||||||
// 添加日志
|
// 添加日志
|
||||||
function addLog(message, type = 'info') {
|
function addLog(message, type = 'info') {
|
||||||
const time = `${String(gameTime.value.hour).padStart(2, '0')}:${String(gameTime.value.minute).padStart(2, '0')}`
|
const time = `${String(gameTime.value.hour).padStart(2, '0')}:${String(gameTime.value.minute).padStart(2, '0')}`
|
||||||
@@ -60,6 +71,54 @@ export const useGameStore = defineStore('game', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查成就
|
||||||
|
function checkAchievements(triggerType, data = {}) {
|
||||||
|
const { ACHIEVEMENT_CONFIG } = require('@/config/achievements.js')
|
||||||
|
let newAchievements = []
|
||||||
|
|
||||||
|
for (const [id, achievement] of Object.entries(ACHIEVEMENT_CONFIG)) {
|
||||||
|
// 已完成的跳过
|
||||||
|
if (achievements.value[id]) continue
|
||||||
|
|
||||||
|
let unlocked = false
|
||||||
|
|
||||||
|
switch (achievement.condition.type) {
|
||||||
|
case 'kill':
|
||||||
|
unlocked = achievementProgress.value.totalKills >= achievement.condition.count
|
||||||
|
break
|
||||||
|
case 'boss_kill':
|
||||||
|
unlocked = achievementProgress.value.bossKills >= achievement.condition.count
|
||||||
|
break
|
||||||
|
case 'equip_prosthetic':
|
||||||
|
unlocked = data.prostheticCount >= achievement.condition.count
|
||||||
|
break
|
||||||
|
case 'skill_level':
|
||||||
|
unlocked = data.maxSkillLevel >= achievement.condition.level
|
||||||
|
break
|
||||||
|
case 'visit_locations':
|
||||||
|
unlocked = achievementProgress.value.visitedLocations.size >= achievement.condition.count
|
||||||
|
break
|
||||||
|
case 'total_earned':
|
||||||
|
unlocked = achievementProgress.value.totalEarned >= achievement.condition.amount
|
||||||
|
break
|
||||||
|
case 'survive_days':
|
||||||
|
unlocked = gameTime.value.day >= achievement.condition.days
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unlocked) {
|
||||||
|
achievements.value[id] = {
|
||||||
|
unlocked: true,
|
||||||
|
timestamp: Date.now()
|
||||||
|
}
|
||||||
|
newAchievements.push(achievement)
|
||||||
|
addLog(`🏆 解锁成就: ${achievement.icon} ${achievement.name}`, 'reward')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newAchievements
|
||||||
|
}
|
||||||
|
|
||||||
// 重置游戏状态
|
// 重置游戏状态
|
||||||
function resetGame() {
|
function resetGame() {
|
||||||
currentTab.value = 'status'
|
currentTab.value = 'status'
|
||||||
@@ -79,6 +138,7 @@ export const useGameStore = defineStore('game', () => {
|
|||||||
combatState.value = null
|
combatState.value = null
|
||||||
autoCombat.value = false
|
autoCombat.value = false
|
||||||
isSearching.value = false
|
isSearching.value = false
|
||||||
|
preferredStance.value = 'balance'
|
||||||
activeTasks.value = []
|
activeTasks.value = []
|
||||||
negativeStatus.value = []
|
negativeStatus.value = []
|
||||||
marketPrices.value = {
|
marketPrices.value = {
|
||||||
@@ -86,6 +146,14 @@ export const useGameStore = defineStore('game', () => {
|
|||||||
prices: {}
|
prices: {}
|
||||||
}
|
}
|
||||||
currentEvent.value = null
|
currentEvent.value = null
|
||||||
|
achievements.value = {}
|
||||||
|
achievementProgress.value = {
|
||||||
|
totalKills: 0,
|
||||||
|
bossKills: 0,
|
||||||
|
prostheticEquipped: 0,
|
||||||
|
visitedLocations: new Set(),
|
||||||
|
totalEarned: 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -97,11 +165,15 @@ export const useGameStore = defineStore('game', () => {
|
|||||||
combatState,
|
combatState,
|
||||||
autoCombat,
|
autoCombat,
|
||||||
isSearching,
|
isSearching,
|
||||||
|
preferredStance,
|
||||||
activeTasks,
|
activeTasks,
|
||||||
negativeStatus,
|
negativeStatus,
|
||||||
marketPrices,
|
marketPrices,
|
||||||
currentEvent,
|
currentEvent,
|
||||||
|
achievements,
|
||||||
|
achievementProgress,
|
||||||
addLog,
|
addLog,
|
||||||
resetGame
|
resetGame,
|
||||||
|
checkAchievements
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export const usePlayerStore = defineStore('player', () => {
|
|||||||
// 基础属性
|
// 基础属性
|
||||||
const baseStats = ref({
|
const baseStats = ref({
|
||||||
strength: 10, // 力量
|
strength: 10, // 力量
|
||||||
agility: 8, // 敏捷
|
agility: 6, // 敏捷(降低以提高被命中率)
|
||||||
dexterity: 8, // 灵巧
|
dexterity: 8, // 灵巧
|
||||||
intuition: 10, // 智力
|
intuition: 10, // 智力
|
||||||
vitality: 10 // 体质(影响HP)
|
vitality: 10 // 体质(影响HP)
|
||||||
@@ -36,9 +36,13 @@ export const usePlayerStore = defineStore('player', () => {
|
|||||||
weapon: null,
|
weapon: null,
|
||||||
armor: null,
|
armor: null,
|
||||||
shield: null,
|
shield: null,
|
||||||
accessory: null
|
accessory: null,
|
||||||
|
prosthetic: null // 义体装备位
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 义体适应性(使用义体时增加)
|
||||||
|
const prostheticAdaptation = ref(0)
|
||||||
|
|
||||||
// 背包
|
// 背包
|
||||||
const inventory = ref([])
|
const inventory = ref([])
|
||||||
|
|
||||||
@@ -53,6 +57,12 @@ export const usePlayerStore = defineStore('player', () => {
|
|||||||
// 标记
|
// 标记
|
||||||
const flags = ref({})
|
const flags = ref({})
|
||||||
|
|
||||||
|
// 击杀统计(用于成就和解锁条件)
|
||||||
|
const killCount = ref({})
|
||||||
|
|
||||||
|
// 访问过的位置
|
||||||
|
const visitedLocations = ref(new Set())
|
||||||
|
|
||||||
// 计算属性:总货币
|
// 计算属性:总货币
|
||||||
const totalCurrency = computed(() => {
|
const totalCurrency = computed(() => {
|
||||||
return {
|
return {
|
||||||
@@ -66,7 +76,7 @@ export const usePlayerStore = defineStore('player', () => {
|
|||||||
function resetPlayer() {
|
function resetPlayer() {
|
||||||
baseStats.value = {
|
baseStats.value = {
|
||||||
strength: 10,
|
strength: 10,
|
||||||
agility: 8,
|
agility: 6, // 降低以提高被命中率
|
||||||
dexterity: 8,
|
dexterity: 8,
|
||||||
intuition: 10,
|
intuition: 10,
|
||||||
vitality: 10
|
vitality: 10
|
||||||
@@ -89,12 +99,16 @@ export const usePlayerStore = defineStore('player', () => {
|
|||||||
weapon: null,
|
weapon: null,
|
||||||
armor: null,
|
armor: null,
|
||||||
shield: null,
|
shield: null,
|
||||||
accessory: null
|
accessory: null,
|
||||||
|
prosthetic: null
|
||||||
}
|
}
|
||||||
|
prostheticAdaptation.value = 0
|
||||||
inventory.value = []
|
inventory.value = []
|
||||||
currency.value = { copper: 0 }
|
currency.value = { copper: 0 }
|
||||||
currentLocation.value = 'camp'
|
currentLocation.value = 'camp'
|
||||||
flags.value = {}
|
flags.value = {}
|
||||||
|
killCount.value = {}
|
||||||
|
visitedLocations.value = new Set()
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -103,11 +117,14 @@ export const usePlayerStore = defineStore('player', () => {
|
|||||||
level,
|
level,
|
||||||
skills,
|
skills,
|
||||||
equipment,
|
equipment,
|
||||||
|
prostheticAdaptation,
|
||||||
inventory,
|
inventory,
|
||||||
currency,
|
currency,
|
||||||
totalCurrency,
|
totalCurrency,
|
||||||
currentLocation,
|
currentLocation,
|
||||||
flags,
|
flags,
|
||||||
|
killCount,
|
||||||
|
visitedLocations,
|
||||||
resetPlayer
|
resetPlayer
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
45
计划第二步.md
45
计划第二步.md
@@ -1,45 +0,0 @@
|
|||||||
接下来开发计划
|
|
||||||
阶段1:修复代码问题(优先)
|
|
||||||
# 任务 文件
|
|
||||||
1 添加gameStore中shop抽屉状态 store/game.js
|
|
||||||
2 修复eventSystem中SKILL_CONFIG导入 utils/eventSystem.js
|
|
||||||
3 修复environmentSystem中里程碑奖励调用 utils/environmentSystem.js
|
|
||||||
4 统一击杀数存储方式 utils/eventSystem.js, components/panels/MapPanel.vue
|
|
||||||
5 InventoryDrawer使用itemSystem函数 components/drawers/InventoryDrawer.vue
|
|
||||||
6 任务完成使用addSkillExp utils/taskSystem.js
|
|
||||||
阶段2:补充未实现功能
|
|
||||||
# 功能 描述
|
|
||||||
1 阅读功能 将书籍任务与UI关联,显示阅读进度
|
|
||||||
2 训练功能 添加训练任务UI,技能训练
|
|
||||||
3 任务UI面板 显示活动中的挂机任务进度
|
|
||||||
4 装备属性生效 确保装备属性正确应用到战斗计算
|
|
||||||
5 探索功能 添加探索事件触发
|
|
||||||
阶段3:UI美化
|
|
||||||
# 内容 说明
|
|
||||||
1 状态面板优化 添加属性详情展开/折叠
|
|
||||||
2 战斗视觉反馈 伤害数字跳动、暴击动画
|
|
||||||
3 品质特效 不同品质物品的光效/边框
|
|
||||||
4 日志颜色优化 更精细的日志类型着色
|
|
||||||
5 技能面板 里程碑奖励可视化显示
|
|
||||||
6 过渡动画 页面切换、抽屉弹出动画
|
|
||||||
阶段4:数值调整
|
|
||||||
# 内容 当前 建议
|
|
||||||
1 初始属性 全部10 按角色差异化
|
|
||||||
2 敌人伤害 野狗攻击8 对新手可能偏高
|
|
||||||
3 经验曲线 线性增长 考虑指数衰减
|
|
||||||
4 耐力消耗 战斗2/秒 平衡性测试
|
|
||||||
5 物品价格 基础价格10-50 经济平衡
|
|
||||||
6 品质概率 随机50-150 高品质概率过低
|
|
||||||
阶段5:内容扩展(剧情之前先讨论)
|
|
||||||
# 内容 说明
|
|
||||||
1 更多武器类型 剑、斧、法杖等
|
|
||||||
2 更多消耗品 药水、食物种类
|
|
||||||
3 更多敌人 不同区域的怪物
|
|
||||||
4 更多被动技能 适应不同环境
|
|
||||||
5 成就系统 记录玩家成就
|
|
||||||
🎯 建议优先处理顺序
|
|
||||||
立即修复:代码逻辑问题(阶段1)
|
|
||||||
核心功能补全:阅读、训练、任务UI(阶段2)
|
|
||||||
数值平衡测试:实际游玩体验后调整(阶段4)
|
|
||||||
UI美化:在功能稳定后进行(阶段3)
|
|
||||||
剧情讨论:最后我们一起讨论完善(阶段5)
|
|
||||||
Reference in New Issue
Block a user