fix: correct import and handle null values in selectors

- loadout_manager_simple: use ArmorSelectorDialog (not ArmorSelectionDialog)
- weapon_selector: handle null/invalid decay/ammo values from API
- Add safe Decimal conversion with InvalidOperation handling
- Filter out weapons with invalid data before populating list
This commit is contained in:
LemonNexus 2026-02-09 21:56:33 +00:00
parent fe5efa181d
commit 5a9ffe5fb8
2 changed files with 65 additions and 23 deletions

View File

@ -389,9 +389,9 @@ class LoadoutManagerDialog(QDialog):
def _select_armor(self): def _select_armor(self):
"""Open simplified armor selector.""" """Open simplified armor selector."""
from ui.armor_selection_dialog import ArmorSelectionDialog from ui.armor_selector import ArmorSelectorDialog
dialog = ArmorSelectionDialog(self) dialog = ArmorSelectorDialog(self)
if dialog.exec() == QDialog.DialogCode.Accepted: if dialog.exec() == QDialog.DialogCode.Accepted:
result = dialog.get_selected_armor() result = dialog.get_selected_armor()
if result: if result:

View File

@ -4,7 +4,7 @@ Quick weapon selection for cost configuration.
""" """
import logging import logging
from decimal import Decimal from decimal import Decimal, InvalidOperation
from PyQt6.QtWidgets import ( from PyQt6.QtWidgets import (
QDialog, QVBoxLayout, QHBoxLayout, QLabel, QDialog, QVBoxLayout, QHBoxLayout, QLabel,
@ -105,7 +105,22 @@ class WeaponSelectorDialog(QDialog):
"""Load weapons from API.""" """Load weapons from API."""
try: try:
nexus = get_nexus_api() nexus = get_nexus_api()
self._weapons = nexus.get_all_weapons() all_weapons = nexus.get_all_weapons()
# Filter out weapons with invalid/null decay or ammo
self._weapons = []
for w in all_weapons:
try:
# Validate that decay and ammo are valid numbers
decay_val = w.decay if w.decay is not None else 0
ammo_val = w.ammo if w.ammo is not None else 0
# Try to convert to Decimal to validate
Decimal(str(decay_val))
Decimal(str(ammo_val))
self._weapons.append(w)
except (InvalidOperation, ValueError, TypeError):
# Skip weapons with invalid data
continue
# Sort by name # Sort by name
self._weapons.sort(key=lambda w: w.name.lower()) self._weapons.sort(key=lambda w: w.name.lower())
@ -120,25 +135,34 @@ class WeaponSelectorDialog(QDialog):
self.weapon_list.clear() self.weapon_list.clear()
for weapon in weapons: for weapon in weapons:
# Calculate cost per shot try:
decay_pec = Decimal(str(weapon.decay)) # Get values with safe defaults
ammo = Decimal(str(weapon.ammo)) decay_raw = weapon.decay if weapon.decay is not None else 0
cost_per_shot = (decay_pec / Decimal("100")) + (ammo * Decimal("0.0001")) ammo_raw = weapon.ammo if weapon.ammo is not None else 0
item = QListWidgetItem(f"{weapon.name} (💰 {cost_per_shot:.4f} PED)") # Calculate cost per shot
item.setData(Qt.ItemDataRole.UserRole, weapon) decay_pec = Decimal(str(decay_raw))
ammo = Decimal(str(ammo_raw))
cost_per_shot = (decay_pec / Decimal("100")) + (ammo * Decimal("0.0001"))
# Tooltip item = QListWidgetItem(f"{weapon.name} (💰 {cost_per_shot:.4f} PED)")
tooltip = ( item.setData(Qt.ItemDataRole.UserRole, weapon)
f"Damage: {weapon.damage}\n"
f"Decay: {weapon.decay} PEC\n"
f"Ammo: {weapon.ammo}\n"
f"Range: {weapon.range}\n"
f"DPP: {weapon.dpp:.2f}"
)
item.setToolTip(tooltip)
self.weapon_list.addItem(item) # Tooltip
tooltip = (
f"Damage: {weapon.damage}\n"
f"Decay: {decay_raw} PEC\n"
f"Ammo: {ammo_raw}\n"
f"Range: {weapon.range}\n"
f"DPP: {weapon.dpp:.2f}" if weapon.dpp else "DPP: -"
)
item.setToolTip(tooltip)
self.weapon_list.addItem(item)
except Exception as e:
# Skip weapons that fail to process
logger.debug(f"Skipping weapon {getattr(weapon, 'name', 'unknown')}: {e}")
continue
def _on_search(self, text): def _on_search(self, text):
"""Filter weapons by search text.""" """Filter weapons by search text."""
@ -158,6 +182,24 @@ class WeaponSelectorDialog(QDialog):
self.selected_weapon = weapon self.selected_weapon = weapon
# Get values with safe defaults
decay_raw = weapon.decay if weapon.decay is not None else 0
ammo_raw = weapon.ammo if weapon.ammo is not None else 0
# Calculate cost per shot
decay_pec = Decimal(str(decay_raw))
ammo = Decimal(str(ammo_raw))
cost_per_shot = (decay_pec / Decimal("100")) + (ammo * Decimal("0.0001"))
# Update preview
self.preview_name.setText(weapon.name)
self.preview_damage.setText(str(weapon.damage) if weapon.damage is not None else "-")
self.preview_decay.setText(f"{decay_raw} PEC")
self.preview_ammo.setText(str(ammo_raw))
self.preview_cost.setText(f"{cost_per_shot:.4f} PED")
self.ok_btn.setEnabled(True)
# Calculate cost per shot # Calculate cost per shot
decay_pec = Decimal(str(weapon.decay)) decay_pec = Decimal(str(weapon.decay))
ammo = Decimal(str(weapon.ammo)) ammo = Decimal(str(weapon.ammo))