docs: 新增西班牙语和日语README并优化多语言文档

新增README-ES.md(西班牙语)和README-JA.md(日语)文档,完善多语言README互链。优化各语言README徽章、技术栈、外链格式及语言切换区,提升文档一致性与可读性。
This commit is contained in:
谦君
2025-12-25 18:25:08 +08:00
parent b24a262ca7
commit 724a70bebb
72 changed files with 13300 additions and 2133 deletions

View File

@@ -10,6 +10,9 @@ interface CombatUnit {
shield: number
armor: number
rapidFire?: Record<string, number> // 快速射击
// 战斗状态追踪(用于护盾再生和装甲损坏效果)
currentShield?: number // 当前护盾值(每轮开始恢复)
armorDamage?: number // 累积装甲损坏(降低防御效果)
}
// 战斗方
@@ -55,7 +58,8 @@ const prepareCombatUnits = (side: BattleSide, isDefender: boolean = false): Comb
count: count,
attack: applyTechBonus(config.attack, side.weaponTech),
shield: applyTechBonus(config.shield, side.shieldTech),
armor: applyTechBonus(config.armor, side.armorTech)
armor: applyTechBonus(config.armor, side.armorTech),
rapidFire: config.rapidFire as Record<string, number> | undefined
})
}
}
@@ -72,6 +76,7 @@ const prepareCombatUnits = (side: BattleSide, isDefender: boolean = false): Comb
attack: applyTechBonus(config.attack, side.weaponTech),
shield: applyTechBonus(config.shield, side.shieldTech),
armor: applyTechBonus(config.armor, side.armorTech)
// 防御设施没有rapidFire
})
}
}
@@ -81,20 +86,57 @@ const prepareCombatUnits = (side: BattleSide, isDefender: boolean = false): Comb
}
/**
* 计算一个单位对另一个单位造成的伤害
* 战斗效果配置
*/
const calculateDamage = (attacker: CombatUnit, defender: CombatUnit): { destroyed: number; damagedShield: number } => {
const COMBAT_EFFECTS = {
// 护盾弹回阈值:攻击力低于护盾此比例时大概率弹回
SHIELD_BOUNCE_THRESHOLD: 0.01,
// 护盾弹回时仍有此概率穿透
SHIELD_BOUNCE_PENETRATION_CHANCE: 0.01,
// 每轮护盾再生比例(恢复最大护盾的百分比)
SHIELD_REGEN_RATE: 0.7,
// 装甲损坏累积效果:每次受到未被护盾完全吸收的伤害,累积装甲损坏
ARMOR_DAMAGE_RATE: 0.05,
// 装甲损坏上限(最多降低防御效果的百分比)
MAX_ARMOR_DAMAGE: 0.3,
// 重型武器对护盾穿透概率(攻击力>5000的武器
HEAVY_WEAPON_SHIELD_PENETRATION: 0.15,
// 重型武器阈值
HEAVY_WEAPON_THRESHOLD: 5000
}
/**
* 计算一个单位对另一个单位造成的伤害
* 增强版:包含护盾弹回、重型武器穿透、装甲损坏累积
*/
const calculateDamage = (attacker: CombatUnit, defender: CombatUnit): { destroyed: number; damagedShield: number; armorDamageDealt: number } => {
const attackPower = attacker.attack
const defenderShield = defender.shield
const defenderArmor = defender.armor
// 使用当前护盾值(如果有),否则使用最大护盾
const defenderCurrentShield = defender.currentShield ?? defender.shield
// 考虑装甲损坏后的有效装甲
const armorDamageMultiplier = 1 - (defender.armorDamage ?? 0)
const effectiveArmor = defender.armor * armorDamageMultiplier
let destroyed = 0
let damagedShield = 0
let armorDamageDealt = 0
// 如果攻击力小于护盾的1%,有很大概率无法击穿护盾
if (attackPower < defenderShield * 0.01) {
if (Math.random() > 0.01) {
return { destroyed: 0, damagedShield: 0 }
// 重型武器穿透:高攻击力武器有概率部分无视护盾
let shieldPenetration = 0
if (attackPower >= COMBAT_EFFECTS.HEAVY_WEAPON_THRESHOLD) {
if (Math.random() < COMBAT_EFFECTS.HEAVY_WEAPON_SHIELD_PENETRATION) {
// 穿透30%-50%的护盾
shieldPenetration = 0.3 + Math.random() * 0.2
}
}
// 计算实际护盾值(考虑穿透)
const effectiveShield = defenderCurrentShield * (1 - shieldPenetration)
// 如果攻击力小于护盾的1%,有很大概率无法击穿护盾(护盾弹回机制)
if (attackPower < effectiveShield * COMBAT_EFFECTS.SHIELD_BOUNCE_THRESHOLD) {
if (Math.random() > COMBAT_EFFECTS.SHIELD_BOUNCE_PENETRATION_CHANCE) {
return { destroyed: 0, damagedShield: 0, armorDamageDealt: 0 }
}
}
@@ -102,26 +144,96 @@ const calculateDamage = (attacker: CombatUnit, defender: CombatUnit): { destroye
let remainingDamage = attackPower
// 先消耗护盾
if (remainingDamage > defenderShield) {
remainingDamage -= defenderShield
damagedShield = defenderShield
if (remainingDamage > effectiveShield) {
remainingDamage -= effectiveShield
damagedShield = effectiveShield
// 更新单位的当前护盾
defender.currentShield = Math.max(0, defenderCurrentShield - damagedShield)
} else {
damagedShield = remainingDamage
return { destroyed: 0, damagedShield }
defender.currentShield = Math.max(0, defenderCurrentShield - damagedShield)
return { destroyed: 0, damagedShield, armorDamageDealt: 0 }
}
// 穿透护盾后对装甲造成损坏累积
if (remainingDamage > 0) {
armorDamageDealt = Math.min(
COMBAT_EFFECTS.ARMOR_DAMAGE_RATE,
COMBAT_EFFECTS.MAX_ARMOR_DAMAGE - (defender.armorDamage ?? 0)
)
defender.armorDamage = Math.min(
COMBAT_EFFECTS.MAX_ARMOR_DAMAGE,
(defender.armorDamage ?? 0) + armorDamageDealt
)
}
// 再消耗装甲
if (remainingDamage > defenderArmor) {
if (remainingDamage > effectiveArmor) {
destroyed = 1
} else {
// 有概率摧毁
const destroyChance = remainingDamage / defenderArmor
// 有概率摧毁(基于伤害与有效装甲的比例)
const destroyChance = remainingDamage / effectiveArmor
if (Math.random() < destroyChance) {
destroyed = 1
}
}
return { destroyed, damagedShield }
return { destroyed, damagedShield, armorDamageDealt }
}
/**
* 执行单个攻击单位的射击(包含快速射击机制)
* OGame规则如果攻击者对目标有rapidFire值N攻击后有(N-1)/N的概率再次攻击
* @param attacker 攻击单位
* @param targets 目标单位数组
* @param losses 损失记录对象
* @param isShipLoss 是否是舰船损失(用于区分舰船和防御)
*/
const executeAttack = (
attacker: CombatUnit,
targets: CombatUnit[],
shipLosses: Partial<Fleet>,
defenseLosses: Partial<Record<DefenseType, number>>
): void => {
if (targets.length === 0) return
// 随机选择一个目标
const targetIndex = Math.floor(Math.random() * targets.length)
const target = targets[targetIndex]
if (!target) return
const { destroyed } = calculateDamage(attacker, target)
if (destroyed > 0) {
target.count -= destroyed
// 记录损失
if (Object.values(ShipType).includes(target.type as ShipType)) {
const shipType = target.type as ShipType
shipLosses[shipType] = (shipLosses[shipType] || 0) + destroyed
} else {
const defenseType = target.type as DefenseType
defenseLosses[defenseType] = (defenseLosses[defenseType] || 0) + destroyed
}
// 如果目标被全部摧毁,从列表中移除
if (target.count <= 0) {
targets.splice(targetIndex, 1)
}
}
// 快速射击机制如果攻击者对目标类型有rapidFire有概率继续攻击
if (attacker.rapidFire && targets.length > 0) {
const rapidFireValue = attacker.rapidFire[target.type]
if (rapidFireValue && rapidFireValue > 1) {
// 继续攻击的概率 = (N-1)/N
const continueChance = (rapidFireValue - 1) / rapidFireValue
if (Math.random() < continueChance) {
// 递归执行下一次攻击
executeAttack(attacker, targets, shipLosses, defenseLosses)
}
}
}
}
/**
@@ -132,43 +244,17 @@ const executeRound = (attackerUnits: CombatUnit[], defenderUnits: CombatUnit[]):
const defenderShipLosses: Partial<Fleet> = {}
const defenderDefenseLosses: Partial<Record<DefenseType, number>> = {}
// 攻击方向防守方射击
// 攻击方向防守方射击(带快速射击)
for (const attacker of attackerUnits) {
for (let i = 0; i < attacker.count; i++) {
// 随机选择一个目标
if (defenderUnits.length === 0) break
const targetIndex = Math.floor(Math.random() * defenderUnits.length)
const target = defenderUnits[targetIndex]
if (!target) continue
const { destroyed } = calculateDamage(attacker, target)
if (destroyed > 0) {
target.count -= destroyed
// 记录损失
if (Object.values(ShipType).includes(target.type as ShipType)) {
const shipType = target.type as ShipType
defenderShipLosses[shipType] = (defenderShipLosses[shipType] || 0) + destroyed
} else {
const defenseType = target.type as DefenseType
defenderDefenseLosses[defenseType] = (defenderDefenseLosses[defenseType] || 0) + destroyed
}
// 如果目标被全部摧毁,从列表中移除
if (target.count <= 0) {
defenderUnits.splice(targetIndex, 1)
}
}
executeAttack(attacker, defenderUnits, defenderShipLosses, defenderDefenseLosses)
}
}
// 防守方向攻击方射击
// 防守方向攻击方射击防御设施没有rapidFire使用简化逻辑
for (const defender of defenderUnits) {
for (let i = 0; i < defender.count; i++) {
// 随机选择一个目标
if (attackerUnits.length === 0) break
const targetIndex = Math.floor(Math.random() * attackerUnits.length)
@@ -246,6 +332,27 @@ export const simulateBattle = (
let attackerUnits = prepareCombatUnits(attacker, false)
let defenderUnits = prepareCombatUnits(defender, true)
// 初始化战斗状态
const initializeCombatState = (units: CombatUnit[]) => {
for (const unit of units) {
unit.currentShield = unit.shield
unit.armorDamage = 0
}
}
initializeCombatState(attackerUnits)
initializeCombatState(defenderUnits)
// 护盾再生函数:每轮战斗后恢复部分护盾
const regenerateShields = (units: CombatUnit[]) => {
for (const unit of units) {
if (unit.currentShield !== undefined && unit.currentShield < unit.shield) {
// 恢复最大护盾的70%(但不超过最大值)
const regenAmount = unit.shield * COMBAT_EFFECTS.SHIELD_REGEN_RATE
unit.currentShield = Math.min(unit.shield, unit.currentShield + regenAmount)
}
}
}
const totalAttackerLosses: Partial<Fleet> = {}
const totalDefenderShipLosses: Partial<Fleet> = {}
const totalDefenderDefenseLosses: Partial<Record<DefenseType, number>> = {}
@@ -272,6 +379,10 @@ export const simulateBattle = (
const roundResult = executeRound(attackerUnits, defenderUnits)
// 每轮结束后护盾再生
regenerateShields(attackerUnits)
regenerateShields(defenderUnits)
// 保存当前回合详情
roundDetails.push({
round: rounds,

View File

@@ -109,15 +109,27 @@ export const migrateGameData = (): void => {
planet.temperature = generatePlanetTemperature(planet.position.position)
needsSave = true
}
// 迁移矿脉数据:确保所有矿脉都有 position 字段
if (planet.oreDeposits && !planet.isMoon) {
const deposits = planet.oreDeposits as any
// 情况1旧格式有 initialMetal需要删除并添加 position
if (deposits.initialMetal !== undefined) {
delete deposits.initialMetal
delete deposits.initialCrystal
delete deposits.initialDeuterium
needsSave = true
}
// 情况2没有 position 字段,需要添加
if (!deposits.position) {
deposits.position = { ...planet.position }
needsSave = true
}
}
})
if (needsSave) {
console.log('[Migration] Added temperature to player planets')
}
}
// NPC星球
if (oldData.npcs && Array.isArray(oldData.npcs)) {
let npcPlanetMigrated = false
oldData.npcs.forEach((npc: NPC) => {
if (npc.planets && Array.isArray(npc.planets)) {
npc.planets.forEach((planet: Planet) => {
@@ -125,14 +137,26 @@ export const migrateGameData = (): void => {
if (!planet.isMoon && !planet.temperature) {
planet.temperature = generatePlanetTemperature(planet.position.position)
needsSave = true
npcPlanetMigrated = true
}
// 迁移矿脉数据:确保所有矿脉都有 position 字段
if (planet.oreDeposits && !planet.isMoon) {
const deposits = planet.oreDeposits as any
// 情况1旧格式有 initialMetal需要删除
if (deposits.initialMetal !== undefined) {
delete deposits.initialMetal
delete deposits.initialCrystal
delete deposits.initialDeuterium
needsSave = true
}
// 情况2没有 position 字段,需要添加
if (!deposits.position) {
deposits.position = { ...planet.position }
needsSave = true
}
}
})
}
})
if (npcPlanetMigrated) {
console.log('[Migration] Added temperature to NPC planets')
}
}
// 迁移 player.diplomaticRelations 到 npc.relations
@@ -172,7 +196,6 @@ export const migrateGameData = (): void => {
// 删除旧的 diplomaticRelations 字段
delete oldData.player.diplomaticRelations
needsSave = true
console.log('[Migration] Migrated player.diplomaticRelations to npc.relations')
}
// 检查是否需要迁移地图数据
@@ -241,7 +264,6 @@ export const migrateGameData = (): void => {
if (universePlanetMigrated) {
localStorage.setItem(universeStorageKey, encryptData(universeData))
console.log('[Migration] Added temperature to universe planets')
}
} catch (error) {
console.error('[Migration] Failed to migrate universe planets temperature:', error)
@@ -251,7 +273,6 @@ export const migrateGameData = (): void => {
// 如果有任何数据被修改保存gameStore数据
if (needsSave) {
localStorage.setItem(storageKey, encryptData(oldData))
console.log('[Migration] Game data migrated successfully')
}
} catch (error) {
console.error('[Migration] Failed to migrate game data:', error)