Save endgame progress, team presets, technique support and camera controls
This commit is contained in:
1 parent
a681affdb3
commit
639cef7d19
52 files changed
+11940
-766
No files matched your search
@@ -12,7 +12,11 @@ import (
|
||||
|
||||
// PearlSR 005d2c1 protocol/src/protocol.pb.zig: MonsterBattleType.
|
||||
// The Go schema retains obfuscated enum labels; zero is NONE, not TRIGGER.
|
||||
const monsterBattleTrigger goproto.MonsterBattleType = 1
|
||||
const (
|
||||
monsterBattleTrigger goproto.MonsterBattleType = 1
|
||||
// PearlSR protocol.pb.zig: MONSTER_BATTLE_TYPE_NO_BATTLE.
|
||||
monsterBattleNoBattle goproto.MonsterBattleType = 4
|
||||
)
|
||||
|
||||
func init() {
|
||||
handle("StartCocoonStage", func(s *Session, req *goproto.StartCocoonStageCsReq, rsp *goproto.StartCocoonStageScRsp) error {
|
||||
@@ -109,7 +113,11 @@ func init() {
|
||||
})
|
||||
|
||||
handle("PVEBattleResult", func(s *Session, req *goproto.PVEBattleResultCsReq, rsp *goproto.PVEBattleResultScRsp) error {
|
||||
CURRENT_BATTLE.Delete(s.Token)
|
||||
current, active := CURRENT_BATTLE.Load(s.Token)
|
||||
active = active && current.StageId == req.StageId
|
||||
if active {
|
||||
CURRENT_BATTLE.Delete(s.Token)
|
||||
}
|
||||
rsp.EndStatus = req.EndStatus
|
||||
rsp.BattleId = req.BattleId
|
||||
rsp.StageId = req.StageId
|
||||
@@ -130,7 +138,7 @@ func init() {
|
||||
req.BattleId, report.TeamTotalDamage, report.RoundCnt, report.TotalBattleTurns, statusStr))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return finishChallengeBattle(s, req, rsp, active)
|
||||
})
|
||||
|
||||
// Consume every target carrier in the current schema. Only entities sent
|
||||
@@ -163,6 +171,9 @@ func init() {
|
||||
req.AssistMonsterEntityIdList, req.AssistMonsterEntityInfo, s.MonsterEntities, targets)
|
||||
|
||||
if len(targets) == 0 {
|
||||
if s.ChallengeStageID != 0 {
|
||||
SceneDebugLog("[CHALLENGE] attack without monster target request=%s", req.String())
|
||||
}
|
||||
// ไม่มี monster จริงถูกตี — ไม่เข้า (นี่คือ fix หลัก)
|
||||
SceneDebugLog("SCENE_CAST_SKILL cast_entity=%d caster=%d skill_index=%d -> no real monster target (battle skipped)",
|
||||
req.CastEntityId, req.CasterId, req.SkillIndex)
|
||||
@@ -173,6 +184,25 @@ func init() {
|
||||
SceneDebugLog("SCENE_CAST_SKILL cast_entity=%d caster=%d -> with %d monster(s)",
|
||||
req.CastEntityId, req.CasterId, len(targets))
|
||||
|
||||
// PearlSR getBattleType acknowledges non-attacking techniques without
|
||||
// starting a battle. The monster still needs a NO_BATTLE result.
|
||||
if req.SkillIndex == 1 {
|
||||
rules, err := common.LoadTechniqueRules()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
avatarID := s.techniqueAvatar(req.CasterId)
|
||||
for _, id := range rules.NonAttackTechniques {
|
||||
if avatarID == id {
|
||||
for _, target := range targets {
|
||||
rsp.MonsterBattleInfo = append(rsp.MonsterBattleInfo, &goproto.HitMonsterBattleInfo{TargetMonsterEntityId: target, MonsterBattleType: monsterBattleNoBattle})
|
||||
}
|
||||
SceneDebugLog("[TECHNIQUE] non-battle avatar=%d targets=%v", avatarID, targets)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
battleInfo, err := createBattleInfo(s, req.CasterId, req.SkillIndex)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -189,11 +219,12 @@ func init() {
|
||||
return nil
|
||||
})
|
||||
|
||||
// ตอบ MP cost ให้ client (ตอบ cast_entity_id กลับ, ไม่ตัด MP จริง)
|
||||
// Cost and recovery use the same session MP as lineup and consumables.
|
||||
handle("SceneCastSkillCostMp", func(s *Session, req *goproto.SceneCastSkillCostMpCsReq, rsp *goproto.SceneCastSkillCostMpScRsp) error {
|
||||
rsp.Retcode = 0
|
||||
rsp.CastEntityId = req.CastEntityId
|
||||
return nil
|
||||
code, err := s.payTechnique(req.CastEntityId, req.SkillIndex)
|
||||
rsp.Retcode = code
|
||||
return err
|
||||
})
|
||||
|
||||
handle("GetCurBattleInfo", func(s *Session, req *goproto.GetCurBattleInfoCsReq, rsp *goproto.GetCurBattleInfoScRsp) error {
|
||||
@@ -215,6 +246,24 @@ func createBattleInfo(s *Session, casterID, skillIndex uint32) (*goproto.SceneBa
|
||||
if player == nil {
|
||||
return nil, fmt.Errorf("battle: player data is not loaded")
|
||||
}
|
||||
if s.ChallengeBattleConfig != nil {
|
||||
// Keep challenge waves and team local to this session. External
|
||||
// Freesr reloads must not replace the stage the player just entered.
|
||||
battlePlayer := *player
|
||||
battlePlayer.BattleConfig = *s.ChallengeBattleConfig
|
||||
player = &battlePlayer
|
||||
} else if len(player.TeamPresets) > 0 {
|
||||
// A selected native preset is the party the player sees in the scene.
|
||||
// Keep the imported stage/waves while taking members from that party.
|
||||
battlePlayer := *player
|
||||
battlePlayer.BattleConfig.CustomBattleLineup = map[uint32]uint32{}
|
||||
for slot, id := range player.Lineups {
|
||||
if id != 0 {
|
||||
battlePlayer.BattleConfig.CustomBattleLineup[slot] = id
|
||||
}
|
||||
}
|
||||
player = &battlePlayer
|
||||
}
|
||||
|
||||
rules, err := loadBattleRules()
|
||||
if err != nil {
|
||||
|
||||
Reference in new issue
Block a user