243 lines
7.1 KiB
Go
Executable File
243 lines
7.1 KiB
Go
Executable File
package logic
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"math/rand"
|
||
"time"
|
||
"wuziqi-server/core"
|
||
"wuziqi-server/items"
|
||
)
|
||
|
||
// ApplyDamage 处理伤害计算、减免和效果
|
||
func (e *GameEngine) ApplyDamage(state *core.GameState, target *core.Player, amount int, isItemEffect bool) {
|
||
if target.HP <= 0 {
|
||
return
|
||
}
|
||
|
||
// 1. 护盾减免
|
||
if target.Shield {
|
||
target.Shield = false
|
||
e.Logger.Info("Player %s (%s) blocked damage with shield", target.UserID, target.Character)
|
||
return // Blocked
|
||
}
|
||
|
||
// 2. 角色特质修改
|
||
// 猫咪天赋: 伤害强制为1
|
||
// 树懒: 如果是定时炸弹(item effect logic handled in engine.go), here we just take raw amount
|
||
// But CharacterManager.OnDamageTaken handles Cat logic
|
||
amount = e.CharManager.OnDamageTaken(target, amount, isItemEffect)
|
||
e.Logger.Info("ApplyDamage: PlayerID=%s, Char=%s, FinalAmount=%d", target.UserID, target.Character, amount)
|
||
|
||
// 3. 诅咒修改
|
||
// 非猫角色受到诅咒伤害翻倍
|
||
if target.Curse && target.Character != "cat" {
|
||
amount *= 2
|
||
target.Curse = false
|
||
} else if target.Character == "cat" {
|
||
target.Curse = false // 即使没有增加伤害也清除诅咒
|
||
}
|
||
|
||
// 4. 应用伤害
|
||
target.HP -= amount
|
||
|
||
// 5. 鸡的特质(受伤获得道具)
|
||
if itemID, triggered := e.CharManager.TryTriggerChickenAbility(target); triggered {
|
||
switch itemID {
|
||
case "skip":
|
||
target.SkipTurn = true
|
||
target.Shield = true
|
||
case "shield":
|
||
target.Shield = true
|
||
case "magnifier":
|
||
// 触发放大镜逻辑
|
||
if e.ItemManager != nil {
|
||
// 这里不方便使用 ItemStrategy,因为上下文需要 ItemContext
|
||
// 如果构建上下文,我们可以直接执行逻辑或重用策略
|
||
// 为了简单起见,我们直接实现逻辑以避免开销
|
||
for i := 0; i < 100; i++ {
|
||
cellIdx := rand.Intn(len(state.Grid))
|
||
if !state.Grid[cellIdx].Revealed {
|
||
cellType := state.Grid[cellIdx].Type
|
||
if state.Grid[cellIdx].Type == "item" {
|
||
cellType = state.Grid[cellIdx].ItemID
|
||
}
|
||
target.RevealedCells[cellIdx] = cellType
|
||
break
|
||
}
|
||
}
|
||
}
|
||
}
|
||
e.Logger.Info("Chicken %s triggered ability, got %s", target.UserID, itemID)
|
||
e.BroadcastEvent(core.GameEvent{
|
||
Type: "ability", PlayerID: target.UserID, PlayerName: target.Username,
|
||
Message: fmt.Sprintf("🐔 鸡你太美!受伤触发天赋,获得了 %s!", itemID),
|
||
})
|
||
}
|
||
|
||
// 6. 死亡检查
|
||
if target.HP <= 0 {
|
||
if target.Revive {
|
||
target.Revive = false
|
||
target.HP = 1
|
||
e.BroadcastEvent(core.GameEvent{
|
||
Type: "ability", PlayerID: target.UserID, PlayerName: target.Username,
|
||
Message: "💖 复活甲生效,免疫死亡!",
|
||
})
|
||
} else if e.CharManager.TryTriggerHippoResist(target) {
|
||
target.HP = 1
|
||
e.BroadcastEvent(core.GameEvent{
|
||
Type: "ability", PlayerID: target.UserID, PlayerName: target.Username,
|
||
Message: "🦛 河马皮糙肉厚,免疫了一次死亡!",
|
||
})
|
||
}
|
||
}
|
||
|
||
if target.HP <= 0 {
|
||
target.HP = 0
|
||
state.LastDeadPlayerID = target.UserID
|
||
}
|
||
}
|
||
|
||
func (e *GameEngine) HealPlayer(p *core.Player, amount int) {
|
||
if p.HP < p.MaxHP {
|
||
p.HP += amount
|
||
if p.HP > p.MaxHP {
|
||
p.HP = p.MaxHP
|
||
}
|
||
}
|
||
}
|
||
|
||
// HandleMove 处理玩家的移动
|
||
func (e *GameEngine) HandleMove(state *core.GameState, userID string, cellIndex int) {
|
||
e.Logger.Info("HandleMove: UserID=%s, Index=%d", userID, cellIndex)
|
||
|
||
// 验证回合
|
||
if len(state.TurnOrder) == 0 {
|
||
return
|
||
}
|
||
currentUserID := state.TurnOrder[state.CurrentTurnIndex]
|
||
if userID != currentUserID {
|
||
e.Logger.Warn("HandleMove rejected: Turn mismatch. Incoming=%s, Expected=%s", userID, currentUserID)
|
||
return
|
||
}
|
||
|
||
// 验证格子
|
||
if cellIndex < 0 || cellIndex >= len(state.Grid) {
|
||
return
|
||
}
|
||
cell := state.Grid[cellIndex]
|
||
if cell.Revealed {
|
||
return
|
||
}
|
||
|
||
player := state.Players[userID]
|
||
if player == nil {
|
||
return
|
||
}
|
||
|
||
// 执行移动
|
||
cell.Revealed = true
|
||
state.GlobalTurnCount++
|
||
state.LastMoveTimestamp = time.Now().Unix()
|
||
|
||
// 狗狗技能:基于狗狗自身的移动步数触发
|
||
if player.Character == "dog" {
|
||
player.DogStepCount++
|
||
interval := 6
|
||
if len(state.Players) >= 6 {
|
||
interval = 9
|
||
}
|
||
if player.DogStepCount%interval == 0 {
|
||
// 触发放大镜效果
|
||
for i := 0; i < 100; i++ {
|
||
idx := rand.Intn(len(state.Grid))
|
||
if !state.Grid[idx].Revealed {
|
||
cellType := state.Grid[idx].Type
|
||
if state.Grid[idx].Type == "item" {
|
||
cellType = state.Grid[idx].ItemID
|
||
}
|
||
player.RevealedCells[idx] = cellType
|
||
coords := state.FormatCoordinates(idx)
|
||
contentDesc := core.TranslateCellType(cellType)
|
||
msg := fmt.Sprintf("🐶 狗狗触发嗅觉天赋(第%d步),发现 %s 格子是 [%s]!", player.DogStepCount, coords, contentDesc)
|
||
|
||
e.SendPrivateEvent(player.UserID, core.GameEvent{
|
||
Type: "ability", PlayerID: player.UserID, PlayerName: player.Username,
|
||
Message: msg,
|
||
CellIndex: idx, CellType: cellType,
|
||
})
|
||
break
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 猴子技能
|
||
if player.Character == "monkey" && player.MonkeyBananaCount < 2 && rand.Float32() < 0.15 {
|
||
e.HealPlayer(player, 1)
|
||
player.MonkeyBananaCount++
|
||
e.BroadcastEvent(core.GameEvent{
|
||
Type: "ability", PlayerID: player.UserID, PlayerName: player.Username,
|
||
Value: 1, Message: "🍌 猴子发现了香蕉,回复1点血量!",
|
||
})
|
||
}
|
||
|
||
// 处理内容
|
||
if cell.Type == "bomb" {
|
||
dmg := 2
|
||
// 树懒踩炸弹伤害减半
|
||
if player.Character == "sloth" {
|
||
dmg = 1
|
||
}
|
||
e.Logger.Info("BombHit: UserID=%s, Char=%s, Dmg=%d", player.UserID, player.Character, dmg)
|
||
e.BroadcastEvent(core.GameEvent{
|
||
Type: "damage", PlayerID: player.UserID, PlayerName: player.Username,
|
||
Value: dmg, Message: fmt.Sprintf("💣 踩到炸弹,受到%d点伤害!", dmg),
|
||
})
|
||
e.ApplyDamage(state, player, dmg, false)
|
||
|
||
} else if cell.Type == "item" {
|
||
if player.Character == "hippo" {
|
||
e.BroadcastEvent(core.GameEvent{
|
||
Type: "ability", PlayerID: player.UserID, PlayerName: player.Username,
|
||
ItemID: cell.ItemID, Message: "🦛 河马无法拾取道具!",
|
||
})
|
||
} else {
|
||
// 构建上下文
|
||
ctx := items.ItemContext{
|
||
Logger: e.Logger,
|
||
Dispatcher: e.Dispatcher,
|
||
Logic: e,
|
||
}
|
||
e.ItemManager.UseItem(state, player, cell.ItemID, ctx)
|
||
}
|
||
|
||
} else if cell.Type == "empty" {
|
||
if cell.NeighborBombs == 0 {
|
||
revealed := RevealSafeArea(state, cellIndex)
|
||
if len(revealed) > 1 {
|
||
e.BroadcastEvent(core.GameEvent{
|
||
Type: "ability", PlayerID: player.UserID, PlayerName: player.Username,
|
||
Value: len(revealed), Message: fmt.Sprintf("🔓 发现安全区域,自动揭示了 %d 个格子!", len(revealed)),
|
||
})
|
||
}
|
||
}
|
||
}
|
||
|
||
// 游戏结束和回合推进
|
||
// 无论如何先尝试推进回合(特别是如果当前玩家刚刚死亡/跳过)
|
||
e.AdvanceTurn(state)
|
||
|
||
// 然后检查游戏是否结束
|
||
if e.CheckGameOver(state) {
|
||
e.Logger.Info("Match %s ended during HandleMove for user %s", state.WinnerID, userID)
|
||
return
|
||
}
|
||
|
||
// 广播常规状态更新
|
||
e.Logger.Debug("Broadcasting state update for match, current turn index: %d, alive players: %d", state.CurrentTurnIndex, len(state.Players))
|
||
updateData, _ := json.Marshal(state.Sanitize())
|
||
e.Dispatcher.BroadcastMessage(core.OpCodeUpdateState, updateData, nil, nil, true)
|
||
}
|