From 276cb142996cd9b42c9f369b17af126c9337e205 Mon Sep 17 00:00:00 2001 From: CAtlas0784 Date: Sat, 31 Oct 2026 21:55:50 +0700 Subject: [PATCH] fix(cw): award Rank SSS at 100 HP, map role damage and equipment in settlement, and fix overworld black screen --- internal/gameserver/currency_wars_quit.go | 7 +- .../gameserver/currency_wars_settlement.go | 33 +++++++- scripts/freecam.lua | 75 ++++++++++++------- 3 files changed, 82 insertions(+), 33 deletions(-) diff --git a/internal/gameserver/currency_wars_quit.go b/internal/gameserver/currency_wars_quit.go index f402fdc..1de1860 100644 --- a/internal/gameserver/currency_wars_quit.go +++ b/internal/gameserver/currency_wars_quit.go @@ -82,7 +82,10 @@ func currencyWarsTerminalSettlement(catalog *common.CurrencyWarsCatalog, data *p if isWon && player.PPKKHHNEOHB > 0 && player.GridFightLineupHp > 0 { hpPercent := float64(player.GridFightLineupHp) / float64(player.PPKKHHNEOHB) * 100.0 if hpPercent >= 100.0 || player.GridFightLineupHp >= player.PPKKHHNEOHB { - rankType = 4 // Rank SS (flawless / 100% HP) + rankType = 5 // Rank SSS (flawless / 100% HP) + divisionUp = 3 + } else if hpPercent >= 90.0 { + rankType = 4 // Rank SS divisionUp = 3 } else if hpPercent >= 70.0 { rankType = 3 // Rank S @@ -95,7 +98,7 @@ func currencyWarsTerminalSettlement(catalog *common.CurrencyWarsCatalog, data *p divisionUp = 1 } } else { - rankType = 0 + rankType = 0 // Rank C (defeat / 0 HP) divisionUp = 0 } diff --git a/internal/gameserver/currency_wars_settlement.go b/internal/gameserver/currency_wars_settlement.go index adf78ec..4b716e8 100644 --- a/internal/gameserver/currency_wars_settlement.go +++ b/internal/gameserver/currency_wars_settlement.go @@ -418,21 +418,48 @@ func finishCurrencyWarsBattle(s *Session, req *pb.PVEBattleResultCsReq, current } for _, role := range current.EIGMKOJOEEI.GridGameRoleList { total := float64(0) + specialID := uint32(0) + if config, err := catalog.CapturedRoleVariant(role.RoleId, role.RoleStar); err == nil { + specialID = config.Config.SpecialAvatarID + } + if specialID == 0 { + specialID = 3700000 + role.AvatarId + } + + matchRole := func(id uint32) bool { + return id == role.RoleId || id == role.AvatarId || id == role.UniqueId || id == specialID || + (id > 3700000 && id-3700000 == role.AvatarId) + } + if req.Stt != nil && req.Stt.APAGMJNECCN != nil { for _, stat := range req.Stt.APAGMJNECCN.DOGMMGLBJIJ { - if (stat.RoleId == role.RoleId || stat.RoleId == role.AvatarId || stat.RoleId == role.UniqueId) && !math.IsNaN(stat.Damage) && !math.IsInf(stat.Damage, 0) && stat.Damage > 0 { + if matchRole(stat.RoleId) && !math.IsNaN(stat.Damage) && !math.IsInf(stat.Damage, 0) && stat.Damage > 0 { total += stat.Damage } } } if total == 0 && req.Stt != nil { for _, ba := range req.Stt.BattleAvatarList { - if (ba.Id == role.AvatarId || ba.Id == role.RoleId) && !math.IsNaN(ba.TotalDamage) && !math.IsInf(ba.TotalDamage, 0) && ba.TotalDamage > 0 { + if matchRole(ba.Id) && !math.IsNaN(ba.TotalDamage) && !math.IsInf(ba.TotalDamage, 0) && ba.TotalDamage > 0 { total += ba.TotalDamage } } } - damage.EEGPILJDLBG = append(damage.EEGPILJDLBG, &pb.PLFKMENCDMM{RoleId: role.RoleId, RoleStar: role.RoleStar, TotalDamage: total, DIGNECHKINI: uint64(role.Pos) > uint64(frontMax)}) + + var eqList []uint32 + for _, eq := range role.CNIJIJMEPEF { + if eq != nil && eq.GridFightEquipmentId != 0 { + eqList = append(eqList, eq.GridFightEquipmentId) + } + } + + damage.EEGPILJDLBG = append(damage.EEGPILJDLBG, &pb.PLFKMENCDMM{ + RoleId: role.RoleId, + RoleStar: role.RoleStar, + TotalDamage: total, + DIGNECHKINI: uint64(role.Pos) > uint64(frontMax), + GridFightEquipmentList: eqList, + }) } oldChapter, oldSection := stage.DCAHJELNJNP, stage.SectionId var nextNotify *pb.GridFightSyncUpdateResultScNotify diff --git a/scripts/freecam.lua b/scripts/freecam.lua index 5149cd7..1d7907a 100644 --- a/scripts/freecam.lua +++ b/scripts/freecam.lua @@ -126,9 +126,17 @@ end -- phase does not expose either, do not guess a world position. local function current_facecam_target() local manager = CS.RPG.Client.GlobalVars.s_GamePhaseManager - local flags = CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags), 60) - local field = typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase', flags) - local phase = manager and field and field:GetValue(manager) + local phase = nil + if manager then + local flags = CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags), 60) + local field = typeof(CS.RPG.Client.GamePhaseManager):GetField('_CurrentPhase', flags) + if field then + phase = field:GetValue(manager) + end + if not phase and manager.PhaseContext then + phase = manager.PhaseContext + end + end if not phase then return nil, nil, nil, false end local now = Time.unscaledTime or 0 @@ -295,11 +303,9 @@ local function update_facecam(cam, settings) local alive, active = pcall(function() return head and root and head.gameObject.activeInHierarchy end) if not alive or not active then -- Character transformations or ultimate cutscenes can briefly unload/hide a model. - -- Hold last valid camera transform only within a short grace period (3s). - -- If character remains unavailable (e.g. battle finished or scene changed), - -- return false so FaceCam automatically deactivates and restores Cinemachine. + -- Hold last valid camera transform; do not drop FaceCam lock during ultimates. _G.__FC_FACE_MISSING_SINCE = _G.__FC_FACE_MISSING_SINCE or now - if now - _G.__FC_FACE_MISSING_SINCE > 3.0 then + if now - _G.__FC_FACE_MISSING_SINCE > 8.0 then return false end if _G.__FC_POS and _G.__FC_EULER then @@ -307,7 +313,7 @@ local function update_facecam(cam, settings) cam.transform.eulerAngles = _G.__FC_EULER return true end - return false + return true end _G.__FC_FACE_MISSING_SINCE = nil @@ -324,27 +330,26 @@ local function update_facecam(cam, settings) local eyeOffset = 0.08 local faceCenter = head.position + Vector3(0, eyeOffset, 0) - -- In HSR rigs, head.up is aligned with the facial forward axis. - -- Project onto horizontal plane (Y=0) so camera remains level and doesn't tilt/pitch with nodding. - local fwdX = head.up.x - local fwdZ = head.up.z - local fwdMagSq = fwdX * fwdX + fwdZ * fwdZ + -- Prioritize character model forward direction so camera stays solidly centered + -- in front of the avatar without snapping/flipping during attacks or ultimate cutscenes. local fwd - if fwdMagSq > 0.001 then - local invMag = 1.0 / math.sqrt(fwdMagSq) - fwd = Vector3(fwdX * invMag, 0, fwdZ * invMag) - elseif root then - local rX = root.forward.x - local rZ = root.forward.z + if root then + local rX, rZ = root.forward.x, root.forward.z local rMagSq = rX * rX + rZ * rZ if rMagSq > 0.001 then local invR = 1.0 / math.sqrt(rMagSq) fwd = Vector3(rX * invR, 0, rZ * invR) + end + end + if not fwd then + local hX, hZ = head.up.x, head.up.z + local hMagSq = hX * hX + hZ * hZ + if hMagSq > 0.001 then + local invH = 1.0 / math.sqrt(hMagSq) + fwd = Vector3(hX * invH, 0, hZ * invH) else fwd = Vector3(0, 0, 1) end - else - fwd = Vector3(0, 0, 1) end local desiredPos = faceCenter + fwd * distance @@ -587,14 +592,15 @@ function _G.__FREECAM_TICK() -- get pinned in the void (black screen) when returning to overworld scenes like Dewlight Pavilion. pcall(function() local manager = CS.RPG.Client.GlobalVars.s_GamePhaseManager - local phaseField = _G.__FC_PHASE_FIELD - if not phaseField then - local flags = CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags), 60) - phaseField = typeof(CS.RPG.Client.GamePhaseManager):GetField("_CurrentPhase", flags) - _G.__FC_PHASE_FIELD = phaseField + local currentPhaseName = "" + if manager then + if manager.CurrentGamePhaseType then + currentPhaseName = tostring(manager.CurrentGamePhaseType) + end + if currentPhaseName == "" and manager.PhaseContext then + currentPhaseName = manager.PhaseContext:GetType().Name + end end - local currentPhase = manager and phaseField and phaseField:GetValue(manager) - local currentPhaseName = currentPhase and currentPhase:GetType().Name or "" if _G.__FC_LAST_PHASE_NAME and _G.__FC_LAST_PHASE_NAME ~= currentPhaseName and currentPhaseName ~= "" then local cam = get_active_cam() set_cinemachine_enabled(cam, true) @@ -619,6 +625,19 @@ function _G.__FREECAM_TICK() end end) + -- Ensure Cinemachine is always active when Freecam is off to prevent black screens + if not _G.__FREECAM_ENABLED then + pcall(function() + local mainCam = CS.UnityEngine.Camera.main + if mainCam then + local brain = mainCam:GetComponent(typeof(CS.Cinemachine.CinemachineBrain)) + if brain and not brain.enabled then + brain.enabled = true + end + end + end) + end + if _G.__FREECAM_ENABLED then local cam = get_active_cam() if cam then