Clanker APR Nerf (Crafted droids)#1956
Conversation
Wave 1 of a possible 3 wave Droid nerf. This specifically fixes two things: Stat.cs: ApplyAttacksPerRound() now detects droids and reads perk levels from Droid.GetControllerItem(creature) + Droid.LoadDroidItemPropertyDetails(controller).Perks APR checks all relevant perks. Previously, Stat.ApplyAttacksPerRound() was using Perk.GetPerkLevel() for droids. For NPCs, Perk.GetPerkLevel() falls back to max perk level if local PERK_LEVEL_* isn’t set, which meant crafted droids were getting an extra 5 APR just for showing up. And just for good measure I reconfigured the free Mastery perks they were getting, meaning they should now perform at-level with a T5 PC. If they continue to need nerfs, I will drop their max stats by 5 for T5, T4, and T3, meaning they'll be locked to T4.5 equivalent PC.
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughMoves ten weapon mastery perks from Tier 3 to Tier 4 in droid defaults, adds a droid-specific perk-level resolver, exposes Changes
Sequence Diagram(s)sequenceDiagram
participant Player
participant EquipFeature as EquipmentRestrictions
participant DroidSvc as Droid.Service
participant StatSvc as Stat.Service
Player ->> EquipFeature: Equip/Unequip item
EquipFeature ->> EquipFeature: Run equip/unequip triggers
EquipFeature ->> DroidSvc: Compute right/left hand items (with slot override)
EquipFeature ->> DroidSvc: ApplyDroidAttacksPerRound(player, rightHand, leftHand)
DroidSvc ->> DroidSvc: LoadDroidItemPropertyDetails(controller) -> build resolver
DroidSvc ->> StatSvc: ApplyAttacksPerRound(droid, rightHand, leftHand, resolver)
StatSvc ->> StatSvc: Resolve perk levels via resolver or Perk.GetPerkLevel
StatSvc -->> DroidSvc: Updated attacks-per-round applied
DroidSvc -->> EquipFeature: done
EquipFeature -->> Player: finish equip/unequip
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
SWLOR.Game.Server/Service/Stat.cs (1)
1645-1654: Minor: Droid without valid controller gets zero perks.If
GetControllerItemreturns an invalid object,droidPerksremains an empty dictionary, causing all perk lookups to return 0. This is likely intentional (a droid without a controller shouldn't get bonuses), but worth confirming this edge case is expected behavior.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@SWLOR.Game.Server/Service/Stat.cs` around lines 1645 - 1654, The code initializes droidPerks to an empty Dictionary which makes lookups return zero when Droid.GetControllerItem(controller) is invalid; change the logic in the Droid handling block so droidPerks remains null unless a valid controller is found (i.e., remove the early new Dictionary<PerkType,int>() assignment and only assign droidPerks = Droid.LoadDroidItemPropertyDetails(controller).Perks when GetIsObjectValid(controller) is true) so downstream code can distinguish "no controller" (null) from "controller with zero perks" when using Droid.IsDroid, Droid.GetControllerItem, and Droid.LoadDroidItemPropertyDetails.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@SWLOR.Game.Server/Service/Stat.cs`:
- Around line 1645-1654: The code initializes droidPerks to an empty Dictionary
which makes lookups return zero when Droid.GetControllerItem(controller) is
invalid; change the logic in the Droid handling block so droidPerks remains null
unless a valid controller is found (i.e., remove the early new
Dictionary<PerkType,int>() assignment and only assign droidPerks =
Droid.LoadDroidItemPropertyDetails(controller).Perks when
GetIsObjectValid(controller) is true) so downstream code can distinguish "no
controller" (null) from "controller with zero perks" when using Droid.IsDroid,
Droid.GetControllerItem, and Droid.LoadDroidItemPropertyDetails.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: fc54819e-0495-4e5e-b824-a8952d9c972e
📒 Files selected for processing (2)
SWLOR.Game.Server/Service/Droid.csSWLOR.Game.Server/Service/Stat.cs
|
@coderabbitai re-review with your latest changes implemented, ScriptSquirrel. |
|
🧠 Learnings used✅ Actions performedFull review triggered. |
|
@coderabbitai re-review now that we're not rate-limited with your latest suggestions implemented |
|
🧠 Learnings used✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
SWLOR.Game.Server/Feature/EquipmentRestrictions.cs (1)
277-288: Extract duplicated hand-state rebuild logic into one helper.The equip and unequip paths duplicate the same right/left-hand recompute flow; consolidating this will reduce drift risk.
♻️ Suggested refactor
@@ - if (Droid.IsDroid(player)) - { - var rightHand = GetItemInSlot(InventorySlot.RightHand, player); - var leftHand = GetItemInSlot(InventorySlot.LeftHand, player); - - if (slot == InventorySlot.RightHand) - rightHand = item; - else if (slot == InventorySlot.LeftHand) - leftHand = item; - - Droid.ApplyDroidAttacksPerRound(player, rightHand, leftHand); - } + if (Droid.IsDroid(player)) + { + ApplyDroidAttacksPerRoundForPendingHandChange(player, slot, item, isUnequip: false); + } @@ - if (Droid.IsDroid(player)) - { - var slot = Item.GetItemSlot(player, item); - var rightHand = GetItemInSlot(InventorySlot.RightHand, player); - var leftHand = GetItemInSlot(InventorySlot.LeftHand, player); - - if (slot == InventorySlot.RightHand) - rightHand = OBJECT_INVALID; - else if (slot == InventorySlot.LeftHand) - leftHand = OBJECT_INVALID; - - Droid.ApplyDroidAttacksPerRound(player, rightHand, leftHand); - } + if (Droid.IsDroid(player)) + { + var slot = Item.GetItemSlot(player, item); + ApplyDroidAttacksPerRoundForPendingHandChange(player, slot, item, isUnequip: true); + } + + private static void ApplyDroidAttacksPerRoundForPendingHandChange(uint player, InventorySlot slot, uint item, bool isUnequip) + { + var rightHand = GetItemInSlot(InventorySlot.RightHand, player); + var leftHand = GetItemInSlot(InventorySlot.LeftHand, player); + + if (slot == InventorySlot.RightHand) + rightHand = isUnequip ? OBJECT_INVALID : item; + else if (slot == InventorySlot.LeftHand) + leftHand = isUnequip ? OBJECT_INVALID : item; + + Droid.ApplyDroidAttacksPerRound(player, rightHand, leftHand); + }Also applies to: 319-331
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@SWLOR.Game.Server/Feature/EquipmentRestrictions.cs` around lines 277 - 288, Extract the duplicated right/left hand rebuild logic into a single helper (e.g., UpdateDroidHandState or RecomputeDroidHands) that accepts the player, the slot being changed and the new item; inside it call GetItemInSlot(InventorySlot.RightHand/LeftHand, player), assign the passed item to the appropriate local (based on the slot) and then call Droid.ApplyDroidAttacksPerRound(player, rightHand, leftHand) if Droid.IsDroid(player). Replace the duplicated blocks in both the equip and unequip paths with a call to this new helper to ensure a single source of truth.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@SWLOR.Game.Server/Feature/EquipmentRestrictions.cs`:
- Around line 277-288: Extract the duplicated right/left hand rebuild logic into
a single helper (e.g., UpdateDroidHandState or RecomputeDroidHands) that accepts
the player, the slot being changed and the new item; inside it call
GetItemInSlot(InventorySlot.RightHand/LeftHand, player), assign the passed item
to the appropriate local (based on the slot) and then call
Droid.ApplyDroidAttacksPerRound(player, rightHand, leftHand) if
Droid.IsDroid(player). Replace the duplicated blocks in both the equip and
unequip paths with a call to this new helper to ensure a single source of truth.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d4027107-f2f5-4078-a48e-12e228e21258
📒 Files selected for processing (3)
SWLOR.Game.Server/Feature/EquipmentRestrictions.csSWLOR.Game.Server/Service/Droid.csSWLOR.Game.Server/Service/Stat.cs
🚧 Files skipped from review as they are similar to previous changes (1)
- SWLOR.Game.Server/Service/Droid.cs
|
@zunath Good to go |
|
@coderabbitai Confirm all conflicts and requests are resolved. Is this ready to merge? |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 31632
✅ No merge conflicts — the branch is ❌ Not ready to merge — there are 3 unresolved review threads from @zunath (the repo owner) that need to be addressed:
Additionally, my latest review left 2 open nitpick comments (non-blocking, but worth noting):
The owner's three threads are the blockers. I'd recommend addressing 🧠 Learnings used |
@coderabbitai Ignore the DM-Possessed creature request while we see what Zunath wants to do with that and confirm everything else is fine. This should have covered the other concerns. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 19726
✅ Code smell (Thread 3 — resolved): The refactoring is exactly as proposed. ✅ "Did you review this code?" (Thread 2 — already resolved): No action needed. ✅ Silent zero perks nitpick: ⏳ DM/DM-possessed thread (Thread 1 — unresolved): Noted, waiting on The duplicated right/left-hand rebuild logic in 🧠 Learnings used |
|
@codex review |
|
@coderabbitai - full review |
|
✅ Actions performedFull review triggered. |

Wave 1 of a possible 3 wave Droid nerf.
This specifically fixes two things:
Stat.cs:
ApplyAttacksPerRound() now detects droids and reads perk levels from Droid.GetControllerItem(creature) + Droid.LoadDroidItemPropertyDetails(controller).Perks
APR checks all relevant perks.
Previously, Stat.ApplyAttacksPerRound() was using Perk.GetPerkLevel() for droids. For NPCs, Perk.GetPerkLevel() falls back to max perk level if local PERK_LEVEL_* isn’t set, which meant crafted droids were getting an extra 5 APR just for showing up.
And just for good measure I reconfigured the free Mastery perks they were getting, meaning they should now perform at-level with a T5 PC.
If they continue to need nerfs, I will drop their max stats by 5 for T5, T4, and T3, meaning they'll be locked to T4.5 equivalent PC.
If they continue to need nerfs after that I'll take away Mastery 2 from T5 and set it to Mastery 1.
Summary by CodeRabbit
New Features
Bug Fixes
Balance Changes