fix icon mapping in campaign ranking
This commit is contained in:
parent
0bfe27e0d3
commit
d766befd31
5 changed files with 113 additions and 58 deletions
|
|
@ -50,13 +50,25 @@ class IconName(str, Enum):
|
|||
NP3RD = "np3rd"
|
||||
TIEBREAK_TOKEN = auto()
|
||||
VP1STDRAW = auto()
|
||||
VP1STTIEBREAK = auto()
|
||||
VP1STBREAK = auto()
|
||||
VP1STTIEDRAW = auto()
|
||||
VP2NDDRAW = auto()
|
||||
VP2NDTIEBREAK = auto()
|
||||
VP2NDBREAK = auto()
|
||||
VP2NDTIEDRAW = auto()
|
||||
VP3RDDRAW = auto()
|
||||
VP3RDTIEBREAK = auto()
|
||||
VP3RDBREAK = auto()
|
||||
VP3RDTIEDRAW = auto()
|
||||
VPNTHDRAW = auto()
|
||||
VPNTHTIEBREAK = auto()
|
||||
VPNTHBREAK = auto()
|
||||
VPNTHTIEDRAW = auto()
|
||||
|
||||
|
||||
RANK_TO_ICON = {
|
||||
1: IconName.VP1ST,
|
||||
2: IconName.VP2ND,
|
||||
3: IconName.VP3RD,
|
||||
4: IconName.VPNTH,
|
||||
}
|
||||
|
||||
|
||||
class Icons:
|
||||
|
|
@ -119,41 +131,65 @@ class Icons:
|
|||
cls.get_pixmap(IconName.VP1ST),
|
||||
cls.get_pixmap(IconName.DRAW),
|
||||
)
|
||||
elif name == IconName.VP1STTIEBREAK:
|
||||
elif name == IconName.VP1STBREAK:
|
||||
pix = cls._compose(
|
||||
cls.get_pixmap(IconName.VP1ST),
|
||||
cls.get_pixmap(IconName.TOKEN),
|
||||
)
|
||||
elif name == IconName.VP1STTIEDRAW:
|
||||
pix = cls._compose(
|
||||
cls.get_pixmap(IconName.VP1ST),
|
||||
cls.get_pixmap(IconName.DRAW),
|
||||
cls.get_pixmap(IconName.TOKEN),
|
||||
)
|
||||
elif name == IconName.VP2NDDRAW:
|
||||
pix = cls._compose(
|
||||
cls.get_pixmap(IconName.VP2ND),
|
||||
cls.get_pixmap(IconName.DRAW),
|
||||
)
|
||||
elif name == IconName.VP2NDTIEBREAK:
|
||||
elif name == IconName.VP2NDBREAK:
|
||||
pix = cls._compose(
|
||||
cls.get_pixmap(IconName.VP2ND),
|
||||
cls.get_pixmap(IconName.TOKEN),
|
||||
)
|
||||
elif name == IconName.VP2NDTIEDRAW:
|
||||
pix = cls._compose(
|
||||
cls.get_pixmap(IconName.VP2ND),
|
||||
cls.get_pixmap(IconName.DRAW),
|
||||
cls.get_pixmap(IconName.TOKEN),
|
||||
)
|
||||
elif name == IconName.VP3RDDRAW:
|
||||
pix = cls._compose(
|
||||
cls.get_pixmap(IconName.VP3RD),
|
||||
cls.get_pixmap(IconName.DRAW),
|
||||
)
|
||||
elif name == IconName.VP3RDTIEBREAK:
|
||||
elif name == IconName.VP3RDBREAK:
|
||||
pix = cls._compose(
|
||||
cls.get_pixmap(IconName.VP3RD),
|
||||
cls.get_pixmap(IconName.TOKEN),
|
||||
)
|
||||
elif name == IconName.VP3RDTIEDRAW:
|
||||
pix = cls._compose(
|
||||
cls.get_pixmap(IconName.VP3RD),
|
||||
cls.get_pixmap(IconName.DRAW),
|
||||
cls.get_pixmap(IconName.TOKEN),
|
||||
)
|
||||
elif name == IconName.VPNTHDRAW:
|
||||
pix = cls._compose(
|
||||
cls.get_pixmap(IconName.VPNTH),
|
||||
cls.get_pixmap(IconName.DRAW),
|
||||
)
|
||||
elif name == IconName.VPNTHTIEBREAK:
|
||||
elif name == IconName.VPNTHBREAK:
|
||||
pix = cls._compose(
|
||||
cls.get_pixmap(IconName.VPNTH),
|
||||
cls.get_pixmap(IconName.TOKEN),
|
||||
)
|
||||
elif name == IconName.VPNTHTIEDRAW:
|
||||
pix = cls._compose(
|
||||
cls.get_pixmap(IconName.VPNTH),
|
||||
cls.get_pixmap(IconName.DRAW),
|
||||
cls.get_pixmap(IconName.TOKEN),
|
||||
)
|
||||
else:
|
||||
path = RESOURCES_DIR / cls._paths[name]
|
||||
pix = QPixmap(path.as_posix())
|
||||
|
|
@ -161,14 +197,20 @@ class Icons:
|
|||
return pix
|
||||
|
||||
@staticmethod
|
||||
def _compose(left: QPixmap, right: QPixmap) -> QPixmap:
|
||||
w = left.width() + right.width()
|
||||
h = max(left.height(), right.height())
|
||||
def _compose(*pixmaps: QPixmap) -> QPixmap:
|
||||
if not pixmaps:
|
||||
return QPixmap()
|
||||
if len(pixmaps) == 1:
|
||||
return pixmaps[0]
|
||||
w = sum(p.width() for p in pixmaps)
|
||||
h = max(p.height() for p in pixmaps)
|
||||
result = QPixmap(w, h)
|
||||
result.fill(Qt.GlobalColor.transparent)
|
||||
painter = QPainter(result)
|
||||
painter.drawPixmap(0, (h - left.height()) // 2, left)
|
||||
painter.drawPixmap(left.width(), (h - right.height()) // 2, right)
|
||||
x = 0
|
||||
for p in pixmaps:
|
||||
painter.drawPixmap(x, (h - p.height()) // 2, p)
|
||||
x += p.width()
|
||||
painter.end()
|
||||
return result
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,14 @@ from typing import List, Dict, TYPE_CHECKING
|
|||
from PyQt6.QtWidgets import QMessageBox, QDialog
|
||||
from PyQt6.QtGui import QIcon
|
||||
|
||||
from warchron.constants import RefreshScope, ContextType, ItemType, Icons, IconName
|
||||
from warchron.constants import (
|
||||
RefreshScope,
|
||||
ContextType,
|
||||
ItemType,
|
||||
Icons,
|
||||
IconName,
|
||||
RANK_TO_ICON,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from warchron.controller.app_controller import AppController
|
||||
|
|
@ -45,40 +52,25 @@ class CampaignController:
|
|||
war, ContextType.CAMPAIGN, campaign.id, scores
|
||||
)
|
||||
icon_map = {}
|
||||
for rank, group in ranking:
|
||||
vp = scores[group[0]].victory_points
|
||||
tie_id = f"{campaign.id}:score:{vp}"
|
||||
is_tie = len(group) > 1
|
||||
broken = TieResolver.was_tie_broken_by_tokens(
|
||||
war,
|
||||
ContextType.CAMPAIGN,
|
||||
tie_id,
|
||||
for rank, group, token_map in ranking:
|
||||
base_icon = RANK_TO_ICON.get(rank, IconName.VPNTH)
|
||||
tie_id = f"{campaign.id}:score:{scores[group[0]].victory_points}"
|
||||
tie_resolved = TieResolver.is_tie_resolved(
|
||||
war, ContextType.CAMPAIGN, tie_id
|
||||
)
|
||||
# choose icon name
|
||||
if rank == 1:
|
||||
base = IconName.VP1ST
|
||||
draw = IconName.VP1STDRAW
|
||||
tb = IconName.VP1STTIEBREAK
|
||||
elif rank == 2:
|
||||
base = IconName.VP2ND
|
||||
draw = IconName.VP2NDDRAW
|
||||
tb = IconName.VP2NDTIEBREAK
|
||||
elif rank == 3:
|
||||
base = IconName.VP3RD
|
||||
draw = IconName.VP3RDDRAW
|
||||
tb = IconName.VP3RDTIEBREAK
|
||||
else:
|
||||
base = IconName.VPNTH
|
||||
draw = IconName.VPNTHDRAW
|
||||
tb = IconName.VPNTHTIEBREAK
|
||||
if not is_tie:
|
||||
icon = Icons.get(base)
|
||||
elif not broken:
|
||||
icon = QIcon(Icons.get_pixmap(draw))
|
||||
else:
|
||||
icon = QIcon(Icons.get_pixmap(tb))
|
||||
for pid in group:
|
||||
icon_map[pid] = icon
|
||||
spent = token_map.get(pid, 0)
|
||||
if not tie_resolved and spent == 0:
|
||||
icon_name = getattr(IconName, f"{base_icon.name}DRAW")
|
||||
elif tie_resolved and spent == 0 and len(group) > 1:
|
||||
icon_name = getattr(IconName, f"{base_icon.name}DRAW")
|
||||
elif tie_resolved and spent > 0 and len(group) == 1:
|
||||
icon_name = getattr(IconName, f"{base_icon.name}BREAK")
|
||||
elif tie_resolved and spent > 0 and len(group) > 1:
|
||||
icon_name = getattr(IconName, f"{base_icon.name}TIEDRAW")
|
||||
else:
|
||||
icon_name = base_icon
|
||||
icon_map[pid] = QIcon(Icons.get_pixmap(icon_name))
|
||||
return icon_map
|
||||
|
||||
def _fill_campaign_details(self, campaign_id: str) -> None:
|
||||
|
|
|
|||
|
|
@ -37,24 +37,23 @@ class ResultChecker:
|
|||
context_type: ContextType,
|
||||
context_id: str,
|
||||
scores: Dict[str, ParticipantScore],
|
||||
) -> List[Tuple[int, List[str]]]:
|
||||
) -> List[Tuple[int, List[str], Dict[str, int]]]:
|
||||
vp_buckets: Dict[int, List[str]] = defaultdict(list)
|
||||
for pid, score in scores.items():
|
||||
vp_buckets[score.victory_points].append(pid)
|
||||
sorted_vps = sorted(vp_buckets.keys(), reverse=True)
|
||||
ranking: List[Tuple[int, List[str]]] = []
|
||||
ranking: List[Tuple[int, List[str], Dict[str, int]]] = []
|
||||
current_rank = 1
|
||||
for vp in sorted_vps:
|
||||
participants = vp_buckets[vp]
|
||||
# no tie
|
||||
if len(participants) == 1:
|
||||
ranking.append((current_rank, participants))
|
||||
current_rank += 1
|
||||
continue
|
||||
tie_id = f"{context_id}:score:{vp}"
|
||||
# tie unresolved → shared rank (theoretically impossible)
|
||||
if not TieResolver.is_tie_resolved(war, context_type, tie_id):
|
||||
ranking.append((current_rank, participants))
|
||||
# no tie
|
||||
if len(participants) == 1 or not TieResolver.is_tie_resolved(
|
||||
war, context_type, tie_id
|
||||
):
|
||||
ranking.append(
|
||||
(current_rank, participants, {pid: 0 for pid in participants})
|
||||
)
|
||||
current_rank += 1
|
||||
continue
|
||||
# apply token ranking
|
||||
|
|
@ -64,7 +63,11 @@ class ResultChecker:
|
|||
tie_id,
|
||||
participants,
|
||||
)
|
||||
tokens_spent = TieResolver.tokens_spent_map(
|
||||
war, context_type, tie_id, participants
|
||||
)
|
||||
for group in groups:
|
||||
ranking.append((current_rank, group))
|
||||
group_tokens = {pid: tokens_spent[pid] for pid in group}
|
||||
ranking.append((current_rank, group, group_tokens))
|
||||
current_rank += 1
|
||||
return ranking
|
||||
|
|
|
|||
|
|
@ -131,6 +131,24 @@ class TieResolver:
|
|||
groups[-1].append(pid)
|
||||
return groups
|
||||
|
||||
@staticmethod
|
||||
def tokens_spent_map(
|
||||
war: War,
|
||||
context_type: ContextType,
|
||||
context_id: str,
|
||||
participants: List[str],
|
||||
) -> Dict[str, int]:
|
||||
spent = {pid: 0 for pid in participants}
|
||||
for ev in war.events:
|
||||
if (
|
||||
isinstance(ev, InfluenceSpent)
|
||||
and ev.context_type == context_type
|
||||
and ev.context_id == context_id
|
||||
and ev.participant_id in spent
|
||||
):
|
||||
spent[ev.participant_id] += ev.amount
|
||||
return spent
|
||||
|
||||
@staticmethod
|
||||
def get_active_participants(
|
||||
war: War,
|
||||
|
|
|
|||
|
|
@ -475,7 +475,7 @@ class View(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||
table.setColumnCount(len(headers))
|
||||
table.setHorizontalHeaderLabels(headers)
|
||||
table.setRowCount(len(participants))
|
||||
table.setIconSize(QSize(32, 16))
|
||||
table.setIconSize(QSize(48, 16))
|
||||
for row, part in enumerate(participants):
|
||||
name_item = QtWidgets.QTableWidgetItem(part.player_name)
|
||||
if part.rank_icon:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue