commit 32b9feab09fd3f47f875b4845c6812df061b1026 parent 9ce228e1f5657451b042dcf82db105f7f1694d25 Author: n8n-bot <bot@novabryan.com> Date: Tue, 22 Sep 2026 13:14:45 +0000 Auto-dump EVE code: 24.01.3532181 (20260922_3532181_code) Diffstat:
90 files changed, 2692 insertions(+), 828 deletions(-)
diff --git a/README.md b/README.md @@ -8,6 +8,7 @@ A timeline of all version captures and synchronizations is documented here: | Update Date | Target Version Tag | Version | Notes | | :--- | :--- | :--- | :--- | +| **2026-09-22** | `eve-24_01_3532181` | 24.01.3532181 | Automated unpack and sync | | **2026-09-22** | `eve-24_01_3528119` | 24.01.3528119 | Automated unpack and sync | | **2026-09-15** | `eve-24_01_3503375` | 24.01.3503375 | Automated unpack and sync | | **2026-08-26** | `eve-24_01_3478781` | 24.01.3478781 | Partial official migration to Python 3 | diff --git a/achievement_system/client/api/error.py b/achievement_system/client/api/error.py @@ -39,3 +39,15 @@ class AlreadyPinnedError(RuntimeError): class PinNotFoundError(RuntimeError): pass + + +class TrackedAchievementLimitReachedError(RuntimeError): + pass + + +class AchievementAlreadyTrackedError(RuntimeError): + pass + + +class TrackedAchievementNotFoundError(RuntimeError): + pass diff --git a/achievement_system/client/api/repository.py b/achievement_system/client/api/repository.py @@ -1,5 +1,5 @@ #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\achievement_system\client\api\repository.py -from achievement_system.client.repository.activity.settings import tracked_achievement_id_setting, pinned_achievement_ids_setting, recently_progressed_achievement_ids_setting, recently_completed_achievement_ids_setting +from achievement_system.client.repository.activity.settings import tracked_achievement_ids_setting, pinned_achievement_ids_setting, recently_progressed_achievement_ids_setting, recently_completed_achievement_ids_setting from achievement_system.client.repository.repository import AchievementRepository from achievement_system.client.api.feature_flag import are_unreleased_achievements_visible, on_unreleased_achievements_visible_changed _repository = None @@ -7,7 +7,7 @@ _repository = None def initialize_repository(public_gateway, service_manager): global _repository if _repository is None: - _repository = AchievementRepository(public_gateway, service_manager, are_unreleased_achievements_visible, on_unreleased_achievements_visible_changed, tracked_achievement_id_setting, pinned_achievement_ids_setting, recently_progressed_achievement_ids_setting, recently_completed_achievement_ids_setting) + _repository = AchievementRepository(public_gateway, service_manager, are_unreleased_achievements_visible, on_unreleased_achievements_visible_changed, tracked_achievement_ids_setting, pinned_achievement_ids_setting, recently_progressed_achievement_ids_setting, recently_completed_achievement_ids_setting) def get_repository(): diff --git a/achievement_system/client/api/signal.py b/achievement_system/client/api/signal.py @@ -7,7 +7,9 @@ on_category_progressed = Signal('achievement.on_category_progressed') on_category_milestone_reached = Signal('achievement.on_category_milestone_reached') on_definitions_loaded = Signal('achievement.on_definitions_loaded') on_unreleased_achievements_visible_changed = Signal('on_unreleased_achievements_visible_changed') -on_tracked_achievement_changed = Signal('achievement.on_tracked_achievement_changed') +on_achievement_tracked = Signal('achievement.on_achievement_tracked') +on_achievement_untracked = Signal('achievement.on_achievement_untracked') +on_achievements_tracked_changed = Signal('achievement.on_achievements_tracked_changed') on_achievement_pinned = Signal('achievement.on_achievement_pinned') on_achievement_unpinned = Signal('achievement.on_achievement_unpinned') on_achievements_pinned_changed = Signal('achievement.on_achievements_pinned_changed') diff --git a/achievement_system/client/model/state/category.py b/achievement_system/client/model/state/category.py @@ -38,6 +38,13 @@ class CategoryStateAttributes(object): def reached_milestones(self): return self._reached_milestones + def is_milestone_reached(self, milestone_id): + for reached_milestone in self._reached_milestones: + if reached_milestone.identifier == milestone_id: + return True + + return False + @classmethod def from_proto(cls, category): reached_milestones = [] diff --git a/achievement_system/client/repository/activity/repository.py b/achievement_system/client/repository/activity/repository.py @@ -1,11 +1,10 @@ #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\achievement_system\client\repository\activity\repository.py import logging -from achievement_system.client.api.error import PinLimitReachedError, AlreadyPinnedError, PinNotFoundError, DefinitionNotFoundError -from achievement_system.client.api.signal import on_tracked_achievement_changed, on_achievement_pinned, on_achievement_unpinned, on_achievements_pinned_changed, on_achievement_progressed, on_achievement_completed, on_recently_progressed_achievements_changed, on_recently_completed_achievements_changed, on_definitions_loaded, on_admin_achievement_reset, on_admin_achievement_reset_all +from achievement_system.client.api.error import TrackedAchievementLimitReachedError, AchievementAlreadyTrackedError, TrackedAchievementNotFoundError, PinLimitReachedError, AlreadyPinnedError, PinNotFoundError, DefinitionNotFoundError +from achievement_system.client.api.signal import on_achievement_tracked, on_achievement_untracked, on_achievements_tracked_changed, on_achievement_pinned, on_achievement_unpinned, on_achievements_pinned_changed, on_achievement_progressed, on_achievement_completed, on_recently_progressed_achievements_changed, on_recently_completed_achievements_changed, on_definitions_loaded, on_admin_achievement_reset, on_admin_achievement_reset_all from achievement_system.client.model.definition.achievement.identifier import AchievementDefinitionIdentifier +from achievement_system.client.repository.activity.settings import legacy_tracked_achievement_id_setting from achievement_system.common.const import LOGGER_NAME -from featuremanagement.client.flag import flag_bool -from signals import Signal if False: from typing import List from carbon.common.script.sys.serviceManager import ServiceManager @@ -14,19 +13,20 @@ if False: from achievement_system.client.repository.activity.test.settings_mock import TrackedAchievementSettingMock, PinnedAchievementSettingMock, RecentlyProgressedAchievementSettingMock, RecentlyCompletedAchievementSettingMock logger = logging.getLogger(LOGGER_NAME) _PINNED_ACHIEVEMENTS_LIMIT = 100 +_TRACKED_ACHIEVEMENTS_LIMIT = 5 _RECENTLY_PROGRESSED_ACHIEVEMENTS_LIMIT = 10 _RECENTLY_COMPLETED_ACHIEVEMENTS_LIMIT = 10 class AchievementActivityRepository(object): __notifyevents__ = ['OnSessionChanged'] - def __init__(self, service_manager, tracked_achievement_setting, pinned_achievements_setting, recently_progressed_achievements_setting, recently_completed_achievements_setting): + def __init__(self, service_manager, tracked_achievements_setting, pinned_achievements_setting, recently_progressed_achievements_setting, recently_completed_achievements_setting): self._service_manager = service_manager - self._tracked_achievement_setting = tracked_achievement_setting + self._tracked_achievements_setting = tracked_achievements_setting self._pinned_achievements_setting = pinned_achievements_setting self._recently_progressed_achievements_setting = recently_progressed_achievements_setting self._recently_completed_achievements_setting = recently_completed_achievements_setting - self._tracked_achievement = None + self._tracked_achievements = [] self._pinned_achievements = [] self._recently_progressed_achievements = [] self._recently_completed_achievements = [] @@ -46,15 +46,16 @@ class AchievementActivityRepository(object): on_definitions_loaded.disconnect(self._on_definitions_loaded) def _clear_cache(self): - self._tracked_achievement = None + self._tracked_achievements = [] self._pinned_achievements = [] self._recently_progressed_achievements = [] self._recently_completed_achievements = [] def _load_settings(self): logger.info('loading achievement activity settings') - self._tracked_achievement = self._tracked_achievement_from_setting() - on_tracked_achievement_changed(self._tracked_achievement) + self._tracked_achievements = self._tracked_achievements_from_setting() + self.convert_legacy_tracked_achievement() + on_achievements_tracked_changed(self._tracked_achievements) self._pinned_achievements = self._pinned_achievements_from_setting() on_achievements_pinned_changed(self._pinned_achievements) self._recently_progressed_achievements = self._recently_progressed_achievements_from_setting() @@ -62,18 +63,46 @@ class AchievementActivityRepository(object): self._recently_completed_achievements = self._recently_completed_achievements_from_setting() on_recently_completed_achievements_changed(self._recently_completed_achievements) - def get_tracked_achievement(self): - return self._tracked_achievement - - def set_tracked_achievement(self, achievement_id): - if achievement_id != self._tracked_achievement: - self._tracked_achievement = achievement_id - self._tracked_achievement_setting.set(self._tracked_achievement_to_setting(achievement_id)) - on_tracked_achievement_changed(self._tracked_achievement) - logger.info('tracking achievement is now %s', self._tracked_achievement) + def convert_legacy_tracked_achievement(self): + legacy_tracked_achievement = self._legacy_tracked_achievement_from_setting() + if legacy_tracked_achievement is None: + legacy_tracked_achievement_id_setting.set(None) + return + if legacy_tracked_achievement in self._tracked_achievements: + legacy_tracked_achievement_id_setting.set(None) + return + self._tracked_achievements.append(legacy_tracked_achievement) + self._tracked_achievements_setting.set(self._tracked_achievements_to_setting(self._tracked_achievements)) + legacy_tracked_achievement_id_setting.set(None) + + def get_tracked_achievements(self): + return self._tracked_achievements + + def track_achievement(self, achievement_id): + if len(self._tracked_achievements) >= _TRACKED_ACHIEVEMENTS_LIMIT: + raise TrackedAchievementLimitReachedError + if achievement_id in self._tracked_achievements: + raise AchievementAlreadyTrackedError + self._tracked_achievements.append(achievement_id) + self._tracked_achievements_setting.set(self._tracked_achievements_to_setting(self._tracked_achievements)) + on_achievement_tracked(achievement_id) + on_achievements_tracked_changed(self._tracked_achievements) + logger.info('tracked achievement %s', achievement_id) + + def untrack_achievement(self, achievement_id): + if achievement_id not in self._tracked_achievements: + raise TrackedAchievementNotFoundError + self._tracked_achievements.remove(achievement_id) + self._tracked_achievements_setting.set(self._tracked_achievements_to_setting(self._tracked_achievements)) + on_achievement_untracked(achievement_id) + on_achievements_tracked_changed(self._pinned_achievements) + logger.info('untracked achievement %s', achievement_id) def is_tracked(self, achievement_id): - return self._tracked_achievement is not None and self._tracked_achievement == achievement_id + return achievement_id in self._tracked_achievements + + def has_tracked_achievements(self): + return len(self._tracked_achievements) > 0 def get_pinned_achievements(self): return self._pinned_achievements @@ -135,8 +164,8 @@ class AchievementActivityRepository(object): def _on_achievement_reset_all(self): self.admin_reset_recently_progressed_and_completed() - def _tracked_achievement_from_setting(self): - setting_value = self._tracked_achievement_setting.get() + def _legacy_tracked_achievement_from_setting(self): + setting_value = legacy_tracked_achievement_id_setting.get() if not setting_value: return None achievement_id = AchievementDefinitionIdentifier(setting_value) @@ -148,10 +177,22 @@ class AchievementActivityRepository(object): logger.info('%s was tracked but definition not found, skipping', achievement_id) return None + def _tracked_achievements_from_setting(self): + achievements_list = [] + for x in self._tracked_achievements_setting.get(): + achievement_id = AchievementDefinitionIdentifier(x) + try: + from achievement_system.client.api.repository import get_repository + get_repository().definitions.get_achievement(achievement_id) + achievements_list.append(achievement_id) + except DefinitionNotFoundError: + logger.info('%s was tracked but definition not found, skipping', achievement_id) + + return achievements_list + @staticmethod - def _tracked_achievement_to_setting(achievement_id): - if achievement_id: - return achievement_id.uuid + def _tracked_achievements_to_setting(achievement_ids): + return [ x.uuid for x in achievement_ids ] def _pinned_achievements_from_setting(self): achievements_list = [] diff --git a/achievement_system/client/repository/activity/settings.py b/achievement_system/client/repository/activity/settings.py @@ -1,6 +1,7 @@ #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\achievement_system\client\repository\activity\settings.py from clientsettings.setting import CharSettingUUID, CharSettingUUIDList -tracked_achievement_id_setting = CharSettingUUID('achievements_tracked_achievement', None) +legacy_tracked_achievement_id_setting = CharSettingUUID('achievements_tracked_achievement', None) +tracked_achievement_ids_setting = CharSettingUUIDList('achievements_tracked_achievements', []) pinned_achievement_ids_setting = CharSettingUUIDList('achievements_pinned_achievements', []) recently_progressed_achievement_ids_setting = CharSettingUUIDList('achievements_recently_progresseded_achievements', []) recently_completed_achievement_ids_setting = CharSettingUUIDList('achievements_recently_completed_achievements', []) diff --git a/achievement_system/client/repository/repository.py b/achievement_system/client/repository/repository.py @@ -38,13 +38,13 @@ class AchievementRepository(object): __startupdependencies__ = ['publicGatewaySvc'] __notifyevents__ = ['OnSessionChanged'] - def __init__(self, public_gateway, service_manager, are_unreleased_achievements_visible, on_unreleased_achievements_visible_changed, tracked_achievement_setting, pinned_achievements_setting, recently_progressed_achievements_setting, recently_completed_achievements_setting): + def __init__(self, public_gateway, service_manager, are_unreleased_achievements_visible, on_unreleased_achievements_visible_changed, tracked_achievements_setting, pinned_achievements_setting, recently_progressed_achievements_setting, recently_completed_achievements_setting): logger.info('initializing repository...') self._service_manager = service_manager self._on_unreleased_achievements_visible_changed_signal = on_unreleased_achievements_visible_changed self._are_unreleased_achievements_visible = are_unreleased_achievements_visible self._definitions_repository = AchievementDefinitionsRepository(public_gateway, are_unreleased_achievements_visible) - self._activity_repository = AchievementActivityRepository(self._service_manager, tracked_achievement_setting, pinned_achievements_setting, recently_progressed_achievements_setting, recently_completed_achievements_setting) + self._activity_repository = AchievementActivityRepository(self._service_manager, tracked_achievements_setting, pinned_achievements_setting, recently_progressed_achievements_setting, recently_completed_achievements_setting) self._character_request_messenger = AchievementRequestMessenger(public_gateway) self._notice_listener = AchievementNoticeListener(public_gateway) notice_listener_signal.on_achievement_completed_notice.connect(self._on_achievement_completed) diff --git a/achievement_system/client/ui/controller/achievement_entry.py b/achievement_system/client/ui/controller/achievement_entry.py @@ -3,7 +3,7 @@ from __future__ import division import datetime import eveicon import logging -from achievement_system.client.api.error import AlreadyPinnedError, PinLimitReachedError, PinNotFoundError +from achievement_system.client.api.error import AchievementAlreadyTrackedError, TrackedAchievementLimitReachedError, TrackedAchievementNotFoundError, AlreadyPinnedError, PinLimitReachedError, PinNotFoundError, DefinitionNotFoundError from achievement_system.client.api.repository import get_repository from achievement_system.client.ui.window.const import get_content_tag_icon, EXCLUDED_CONTRIB_METHOD_PARAM_KEYS, HISTORIC_COMPLETE_COLOR, HISTORIC_INCOMPLETE_COLOR from achievement_system.client.ui.util import get_controller_for_configured_parameter @@ -63,7 +63,10 @@ class AchievementEntryController(object): message = self.achievement_entry.attributes.flavor_text_message if message is None: return - return message.get_localized_text() + localized_text = message.get_localized_text() + if len(localized_text) == 0: + return + return localized_text @property def total_milestones(self): @@ -149,9 +152,11 @@ class AchievementEntryController(object): return self.progress_score_hint_for_milestone(self.selected_milestone_index) def progress_score_hint_for_milestone(self, milestone_index): - current_text = FmtAmt(self.progress) - target_text = FmtAmt(self.target_for_milestone_index(milestone_index)) - return '%s/%s' % (current_text, target_text) + current_value = self.progress + target_value = self.target_for_milestone_index(milestone_index) + if current_value > target_value: + current_value = target_value + return '%s/%s' % (FmtAmt(current_value), FmtAmt(target_value)) @property def selected_milestone_target(self): @@ -274,11 +279,7 @@ class AchievementEntryController(object): @property def progress_bar_color(self): - if self.percent_progress_towards_selected_milestone == 1.0: - if not self.is_historic: - return eveColor.SUCCESS_GREEN - return HISTORIC_COMPLETE_COLOR - elif self.is_completed: + if self.is_completed: if not self.is_historic: return eveColor.SUCCESS_GREEN return HISTORIC_COMPLETE_COLOR @@ -288,6 +289,14 @@ class AchievementEntryController(object): return HISTORIC_INCOMPLETE_COLOR @property + def milestone_progress_bar_color(self): + if self.percent_progress_towards_selected_milestone == 1.0: + if not self.is_historic: + return eveColor.SUCCESS_GREEN + return HISTORIC_COMPLETE_COLOR + return self.progress_bar_color + + @property def is_pinned(self): return get_repository().activity.is_pinned(self.achievement_entry.identifier) @@ -338,9 +347,23 @@ class AchievementEntryController(object): def toggle_tracked(self): if self.is_tracked: - get_repository().activity.set_tracked_achievement(None) + self.untrack() else: - get_repository().activity.set_tracked_achievement(self.achievement_entry.identifier) + self.track() + + def track(self): + try: + get_repository().activity.track_achievement(self.achievement_entry.identifier) + except AchievementAlreadyTrackedError: + logger.warning('Achievement already tracked: %s', self.achievement_entry.identifier) + except TrackedAchievementLimitReachedError: + message_player(GetByLabel('UI/Achievements/Error/TrackedAchievementLimitReached')) + + def untrack(self): + try: + get_repository().activity.untrack_achievement(self.achievement_entry.identifier) + except TrackedAchievementNotFoundError: + logger.warning('Tracked achievement not found: %s', self.achievement_entry.identifier) def get_contribution_parameters_to_display(self): exclude_list = [ x for x in EXCLUDED_CONTRIB_METHOD_PARAM_KEYS ] @@ -386,3 +409,12 @@ class AchievementEntryController(object): def _get_percent_progress_towards_milestone(self, index): current_target = self.target_for_milestone_index(index) return min(self.progress / current_target, 1.0) + + @property + def category_icon(self): + try: + category_id = self.achievement_entry.attributes.parent_category + category_attributes = get_repository().definitions.get_category(category_id) + return eveicon.get(category_attributes.icon_id) + except DefinitionNotFoundError: + return eveicon.cup diff --git a/achievement_system/client/ui/controller/reward.py b/achievement_system/client/ui/controller/reward.py @@ -1,5 +1,6 @@ #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\achievement_system\client\ui\controller\reward.py import eveicon +from achievement_system.client.api.error import GenericInternalServerError, ServiceUnavailableError from achievement_system.client.api.repository import get_repository as achievement_repository from achievement_system.client.model.definition.reward.attributes import IskRewardDefinitionAttributes, SpRewardDefinitionAttributes, ItemRewardDefinitionAttributes, TitleRewardDefinitionAttributes from achievement_system.client.model.definition.reward.type import RewardType @@ -12,11 +13,12 @@ from localization import GetByLabel class RewardData(object): - def __init__(self, reward_type, is_claimed, icon, text, hint = None): + def __init__(self, reward_type, is_granted, is_claimed, icon, text, hint = None): self.reward_type = reward_type self.icon = icon self.text = text self.hint = hint + self.is_granted = is_granted self.is_claimed = is_claimed @property @@ -49,6 +51,10 @@ class AchievementRewardController(object): return achievement_repository().definitions.get_achievement(self.identifier) @property + def state(self): + return achievement_repository().get_achievement_state(self.identifier) + + @property def name(self): return '%s - %s %s' % (self.attributes.name_message.get_localized_text(), GetByLabel('UI/Achievements/Window/Card/Milestone'), self.attributes.get_milestone_index(self.milestone_id) + 1) @@ -65,6 +71,16 @@ class AchievementRewardController(object): return achievement_repository().definitions.get_contribution_method(contribution_id) @property + def is_milestone_reached(self): + try: + state = self.state + if state is None: + return False + return state.is_milestone_reached(self.milestone_id) + except ServiceUnavailableError or GenericInternalServerError: + return False + + @property def reward_data(self): result = [] for reward_id in self.rewards: @@ -72,16 +88,8 @@ class AchievementRewardController(object): if reward_attributes is None: continue reward_type = reward_attributes.reward_type - if reward_type == RewardType.TITLE: - try: - hint = '%s: %s' % (GetByLabel('UI/Achievements/Window/Rewards/TitleReward'), title_repository().definitions.get_title(reward_attributes.title_identifier).localized_name) - except DefinitionNotFoundError: - hint = None - - else: - hint = None - is_claimed = achievement_repository().is_reward_claimed_for_achievement_milestone(self.identifier, self.milestone_id, reward_id) - result.append(RewardData(reward_type=reward_type, is_claimed=is_claimed, icon=REWARD_ICON_BY_TYPE[reward_attributes.reward_type], text=self.get_reward_text(reward_attributes), hint=hint)) + is_claimed = achievement_repository().is_reward_claimed_for_achievement_milestone(achievement_id=self.identifier, milestone_id=self.milestone_id, reward_id=reward_id) + result.append(RewardData(reward_type=reward_type, is_granted=self.is_milestone_reached, is_claimed=is_claimed, icon=REWARD_ICON_BY_TYPE[reward_attributes.reward_type], text=self.get_reward_text(reward_attributes), hint=self.get_reward_hint(reward_attributes))) return result @@ -102,7 +110,14 @@ class AchievementRewardController(object): if isinstance(reward_attributes, ItemRewardDefinitionAttributes): return '%sx %s' % (reward_attributes.amount, type_link(reward_attributes.type_id)) if isinstance(reward_attributes, TitleRewardDefinitionAttributes): - return '<b>%s</b>' % GetByLabel('UI/Achievements/Window/Rewards/TitleReward') + try: + name = title_repository().definitions.get_title(reward_attributes.title_identifier).localized_name + return GetByLabel('UI/Achievements/Window/Rewards/TitleReward', name=name) + except DefinitionNotFoundError: + return None + + def get_reward_hint(self, reward_attributes): + return self.get_reward_text(reward_attributes) class CategoryRewardController(AchievementRewardController): @@ -112,6 +127,10 @@ class CategoryRewardController(AchievementRewardController): return achievement_repository().definitions.get_category(self.identifier) @property + def state(self): + return achievement_repository().get_category_state(self.identifier) + + @property def icon(self): if self.attributes.icon_id: return eveicon.get(self.attributes.icon_id) diff --git a/achievement_system/client/ui/info_panel/__init__.py b/achievement_system/client/ui/info_panel/__init__.py @@ -1,2 +0,0 @@ -#Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\achievement_system\client\ui\info_panel\__init__.py -pass diff --git a/achievement_system/client/ui/window/card/compact_card.py b/achievement_system/client/ui/window/card/compact_card.py @@ -67,7 +67,7 @@ class CompactAchievementCard(Container): @threadutils.highlander_threaded def on_hover_area_mouse_enter(self, *args): self.is_hovered = True - uthread2.Sleep(0.3) + uthread2.Sleep(0.25) if not self.is_hovered: return self.controller.set_selected_milestone_index(self.controller.current_milestone_index) @@ -77,7 +77,7 @@ class CompactAchievementCard(Container): self.is_hovered = False def construct_labels(self): - self.labels = CompactAchievementLabels(name='labels', parent=self.content_container, align=Align.TOTOP, controller=self.controller, compact_mode=True, display_background=False) + self.labels = CompactAchievementLabels(name='labels', parent=self.content_container, align=Align.TOTOP, controller=self.controller) def construct_milestone_container(self): self.milestone_container = ContainerAutoSize(name='milestone_container', parent=self.content_container, align=Align.TOTOP, padTop=2) diff --git a/achievement_system/client/ui/window/card/components/claimed_icon.py b/achievement_system/client/ui/window/card/components/claimed_icon.py @@ -0,0 +1,18 @@ +#Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\achievement_system\client\ui\window\card\components\claimed_icon.py +import eveicon +from carbonui import Align, uiconst +from carbonui.primitives.container import Container +from carbonui.primitives.sprite import Sprite +from eve.client.script.ui import eveColor + +class ClaimedIcon(Container): + default_width = 16 + default_height = 16 + + def __init__(self, *args, **kwargs): + super(ClaimedIcon, self).__init__(*args, **kwargs) + self.construct_layout() + + def construct_layout(self): + Sprite(name='complete_icon', parent=self, align=Align.CENTER, state=uiconst.UI_DISABLED, texturePath=eveicon.circle_checkmark, color=eveColor.SUCCESS_GREEN, pos=(0, 0, 16, 16)) + Sprite(name='complete_icon_bg', parent=self, align=Align.CENTER, state=uiconst.UI_DISABLED, texturePath='res:/UI/Texture/circle-24.png', color=eveColor.BLACK, pos=(0, 0, 16, 16)) diff --git a/achievement_system/client/ui/window/card/components/contribution.py b/achievement_system/client/ui/window/card/components/contribution.py @@ -1,8 +1,29 @@ #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\achievement_system\client\ui\window\card\components\contribution.py -from carbonui import Align +import eveicon +import threadutils +from achievement_system.client.api.error import DefinitionNotFoundError +from achievement_system.client.api.repository import get_repository +from achievement_system.client.api.signal import on_achievement_completed, on_admin_achievement_reset, on_admin_achievement_reset_all +from achievement_system.client.model.definition.achievement.entry import AchievementDefinitionEntry +from achievement_system.client.model.definition.achievement.identifier import AchievementDefinitionIdentifier +from achievement_system.client.ui.controller.achievement_entry import AchievementEntryController +from achievement_system.client.ui.util import get_controller_for_configured_parameter +from carbonui import Align, TextColor, uiconst from carbonui.control.attributeContainer import AttributeContainer from carbonui.control.parametertypes.parameter_container import ParameterContainer +from carbonui.primitives.container import Container from carbonui.primitives.containerAutoSize import ContainerAutoSize +from carbonui.primitives.flowcontainer import FlowContainer +from carbonui.primitives.frame import Frame +from carbonui.primitives.sprite import Sprite +from carbonui.primitives.transform import Transform +from carbonui.text.custom import TextCustom +from carbonui.text.styles import TextBody, TextDetail +from carbonui.uianimations import animations +from carbonui.uicore import uicore +from eve.client.script.ui import eveColor +from eve.client.script.ui.control.infoIcon import CheckMarkGlyphIcon +from localization import GetByLabel class AchievementContribution(ContainerAutoSize): @@ -10,6 +31,7 @@ class AchievementContribution(ContainerAutoSize): super(AchievementContribution, self).__init__(*args, **kwargs) self.controller = controller self.construct_layout() + self.update() def construct_layout(self): self.construct_attributes() @@ -21,3 +43,164 @@ class AchievementContribution(ContainerAutoSize): def construct_parameters(self): for component_controller in self.controller.get_contribution_param_ui_controllers(): ParameterContainer(parent=self, align=Align.TOTOP, controller=component_controller, padTop=16) + + @threadutils.highlander_threaded + def update(self): + pass + + +class ChecklistContribution(ContainerAutoSize): + + def __init__(self, controller, *args, **kwargs): + super(ChecklistContribution, self).__init__(*args, **kwargs) + self.controller = controller + self.construct_layout() + self.update() + self.connect_signals() + + def Close(self): + try: + self.disconnect_signals() + finally: + super(ChecklistContribution, self).Close() + + def connect_signals(self): + on_achievement_completed.connect(self.on_achievement_completed) + on_admin_achievement_reset.connect(self.on_achievement_reset) + on_admin_achievement_reset_all.connect(self.on_achievement_reset_all) + + def disconnect_signals(self): + on_achievement_completed.disconnect(self.on_achievement_completed) + on_admin_achievement_reset.disconnect(self.on_achievement_reset) + on_admin_achievement_reset_all.disconnect(self.on_achievement_reset_all) + + def construct_layout(self): + self.label = TextBody(name='label', parent=self, align=Align.TOTOP, color=TextColor.SECONDARY, text=GetByLabel('UI/Achievements/Window/Card/ListTitle')) + self.content_container = ContainerAutoSize(name='content_container', parent=self, align=Align.TOTOP, alignMode=Align.TOTOP, padTop=4) + self.construct_icon() + self.entry_container = FlowContainer(name='entry_container', parent=self.content_container, align=Align.TOTOP, contentSpacing=(8, 8), padLeft=40) + + def construct_icon(self): + icon_container = Container(parent=self.content_container, align=Align.TOPLEFT, state=uiconst.UI_DISABLED, pos=(0, 0, 32, 32)) + Sprite(parent=icon_container, align=Align.CENTER, texturePath='res:/UI/Texture/classes/Achievements/card/checklist_frame.png', opacity=0.05, pos=(0, 0, 32, 32)) + Sprite(parent=icon_container, align=Align.CENTER, texturePath=eveicon.trophy, color=TextColor.SECONDARY, pos=(0, 0, 16, 16)) + + def reconstruct_entries(self): + self.entry_container.Flush() + for param_entry, param_config in self.controller.parameters_to_display_as_list: + component_controller = get_controller_for_configured_parameter(definition=param_entry.get_ui_controller(), configuration=param_config.get_ui_controller()) + if component_controller is None: + continue + values = component_controller.values + if values and isinstance(values, list): + total_entries = len(values) + if total_entries == 0: + return + is_odd_number_of_entries = total_entries % 2 + for index, entry in enumerate(values): + is_last_entry = index == total_entries - 1 + if is_last_entry and is_odd_number_of_entries: + width = self.entry_max_width + else: + width = ChecklistEntry.default_width + entry_controller = self.get_achievement_controller_for_entry(entry) + if entry_controller is None: + continue + ChecklistEntry(parent=self.entry_container, controller=entry_controller, width=width) + + def get_achievement_controller_for_entry(self, entry): + achievement_id = AchievementDefinitionIdentifier(entry) + if achievement_id is None: + return + try: + achievement_attributes = get_repository().definitions.get_achievement(achievement_id) + except DefinitionNotFoundError: + return + + achievement_entry = AchievementDefinitionEntry(achievement_id, achievement_attributes) + return AchievementEntryController(achievement_entry) + + @property + def entry_max_width(self): + return self.entry_container.contentSpacing[0] + ChecklistEntry.default_width * 2 + + @threadutils.highlander_threaded + def update(self): + self.reconstruct_entries() + + def on_achievement_completed(self, achievement_id): + if achievement_id == self.controller.achievement_entry.identifier: + self.update() + + def on_achievement_reset(self, achievement_id): + if achievement_id == self.controller.achievement_entry.identifier: + self.update() + + def on_achievement_reset_all(self): + self.update() + + +class ChecklistEntry(Container): + default_width = 208 + default_height = 48 + default_state = uiconst.UI_NORMAL + + def __init__(self, controller, *args, **kwargs): + super(ChecklistEntry, self).__init__(*args, **kwargs) + self.controller = controller + self.is_hovered = False + self.construct_layout() + self.update(animate=False) + + def construct_layout(self): + self.completed_glyph = CheckMarkGlyphIcon(parent=self, align=Align.TOPRIGHT, state=uiconst.UI_DISABLED, pos=(4, 4, 16, 16)) + self.content_container = Container(name='content_container', parent=self, padding=(8, 8, 8, 8)) + self.construct_icon() + self.construct_labels() + self.construct_background() + + def construct_icon(self): + icon_container = Container(name='icon_container', parent=self.content_container, align=Align.TOLEFT, width=32) + self.icon = Sprite(name='icon', parent=icon_container, align=Align.CENTER, color=TextColor.SECONDARY, pos=(0, 0, 32, 32)) + + def construct_labels(self): + label_container = ContainerAutoSize(name='label_container', parent=self.content_container, align=Align.VERTICALLY_CENTERED, padLeft=8) + self.description_label = TextDetail(name='description_label', parent=label_container, align=Align.TOTOP, text=GetByLabel('UI/Achievements/Window/Card/ChecklistAchievementDescription'), color=TextColor.SECONDARY) + self.name_wrapper = Container(name='name_wrapper', parent=label_container, align=Align.TOTOP) + self.name_label = TextCustom(name='name_label', parent=self.name_wrapper, align=Align.TOLEFT, color=TextColor.HIGHLIGHT, fontSize=16, maxLines=1, autoFadeSides=16) + + def construct_background(self): + frame_transform = Transform(name='frame_transform', parent=self, align=Align.TOALL, scalingCenter=(0.5, 0.5), scale=(-1.0, 1.0)) + self.frame = Frame(parent=frame_transform, align=Align.TOALL, texturePath='res:/UI/Texture/classes/Achievements/card/checklist_frame.png', cornerSize=16, uiScaleVertices=True) + + @threadutils.highlander_threaded + def update(self, animate = True): + is_completed = self.controller.is_completed + self.frame.color = eveColor.SUCCESS_GREEN if is_completed else eveColor.WHITE + self.update_frame_opacity(animate) + self.icon.texturePath = eveicon.trophy + self.update_labels() + self.completed_glyph.display = is_completed + + def update_frame_opacity(self, animate = True): + target_opacity = 0.2 if self.is_hovered else 0.1 + if animate: + animations.MorphScalar(obj=self.frame, attrName='opacity', startVal=self.frame.opacity, endVal=target_opacity, duration=0.25) + else: + self.frame.opacity = target_opacity + + def update_labels(self): + _, h = TextCustom.MeasureTextSize('0', fontSize=16) + self.name_wrapper.height = h + self.name_label.text = self.controller.name + + def OnClick(self, *args): + uicore.cmd.OpenAchievement(self.controller.achievement_entry.identifier) + + def OnMouseEnter(self, *args): + self.is_hovered = True + self.update_frame_opacity() + + def OnMouseExit(self, *args): + self.is_hovered = False + self.update_frame_opacity() diff --git a/achievement_system/client/ui/window/card/components/expiry.py b/achievement_system/client/ui/window/card/components/expiry.py @@ -16,10 +16,11 @@ EXPIRED_COLOR = TextColor.DANGER class AchievementExpiryTimer(ContainerAutoSize): default_height = 16 - def __init__(self, controller, display_icon = True, *args, **kwargs): + def __init__(self, controller, display_icon = True, use_verbose_text = True, *args, **kwargs): super(AchievementExpiryTimer, self).__init__(*args, **kwargs) self.controller = controller self.display_icon = display_icon + self.use_verbose_text = use_verbose_text self.construct_layout() self.update_thread = uthread2.start_tasklet(self.update_async) @@ -56,9 +57,12 @@ class AchievementExpiryTimer(ContainerAutoSize): def time_remaining_text(self): if self.controller.is_expired: return GetByLabel('UI/Achievements/Window/Card/Expired') + seconds = int(self.controller.time_remaining.total_seconds() * appConst.SEC) + time_remaining = timeIntervalFormatters.FormatTimeIntervalShortWritten(seconds) + if self.use_verbose_text: + return GetByLabel(labelNameAndPath='UI/Achievements/Window/Card/TimeRemaining', time_remaining=time_remaining) else: - seconds = int(self.controller.time_remaining.total_seconds() * appConst.SEC) - return GetByLabel(labelNameAndPath='UI/Achievements/Window/Card/TimeRemaining', time_remaining=timeIntervalFormatters.FormatTimeIntervalShortWritten(seconds)) + return time_remaining @property def timer_color(self): diff --git a/achievement_system/client/ui/window/card/components/header.py b/achievement_system/client/ui/window/card/components/header.py @@ -3,17 +3,16 @@ import threadutils from achievement_system.client.ui.window.card.components.archived import AchievementArchived from achievement_system.client.ui.window.card.components.expiry import AchievementExpiryTimer from achievement_system.client.ui.window.card.components.icon import AchievementIcon -from achievement_system.client.ui.window.card.components.progress import AchievementProgress from carbonui import Align, TextColor from carbonui.primitives.container import Container from carbonui.primitives.containerAutoSize import ContainerAutoSize -from carbonui.primitives.fill import Fill +from carbonui.primitives.stretchspritehorizontal import StretchSpriteHorizontal from carbonui.text.styles import TextBody, TextCustom -from eve.client.script.ui import eveColor -from localization import GetByLabel +from eve.client.script.ui import eveThemeColor +CIRCLE_SIZE = 164 class AchievementHeader(Container): - default_height = AchievementProgress.default_height + default_height = CIRCLE_SIZE def __init__(self, controller, *args, **kwargs): super(AchievementHeader, self).__init__(*args, **kwargs) @@ -22,33 +21,31 @@ class AchievementHeader(Container): self.update() def construct_layout(self): - left_container = Container(name='left_container', parent=self, align=Align.TOLEFT, width=AchievementProgress.default_width, height=AchievementProgress.default_height) - self.progress = AchievementProgress(name='progress', parent=left_container, align=Align.TOPLEFT, controller=self.controller) - self.icon = AchievementIcon(name='icon', parent=self.progress, align=Align.CENTERTOP, controller=self.controller, padTop=24) - right_container = ContainerAutoSize(name='right_container', parent=self, align=Align.TOTOP) - right_container.on_size_changed.connect(self.on_flavor_text_size_changed) + left_container = Container(name='left_container', parent=self, align=Align.TOLEFT, width=CIRCLE_SIZE, height=CIRCLE_SIZE) + self.icon = AchievementIcon(name='icon', parent=left_container, align=Align.CENTER, controller=self.controller) + right_container = ContainerAutoSize(name='right_container', parent=self, align=Align.TOTOP, alignMode=Align.TOTOP) + right_container.on_size_changed.connect(self.on_right_container_size_changed) if self.controller.is_time_limited: - expiry_container = Container(name='expiry_container', parent=right_container, align=Align.TOTOP, height=16, top=12) + expiry_container = Container(name='expiry_container', parent=right_container, align=Align.TOTOP_NOPUSH, height=16, top=32, padLeft=16) AchievementExpiryTimer(name='expiry_timer', parent=expiry_container, align=Align.CENTERLEFT, controller=self.controller) elif self.controller.is_historic: archived_container = Container(name='archived_container', parent=right_container, align=Align.TOTOP, height=16, top=12) AchievementArchived(name='archived', parent=archived_container, align=Align.CENTERLEFT) - self.name_plate = NamePlate(name='name_plate', parent=right_container, align=Align.TOTOP, controller=self.controller, top=34 if self.controller.is_time_limited else 62) - self.flavor_text = TextBody(name='flavor_text', parent=right_container, align=Align.TOTOP, italic=True, padding=(16, 8, 16, 0)) + self.name_plate = NamePlate(name='name_plate', parent=right_container, align=Align.TOTOP, controller=self.controller) + self.description_label = TextBody(name='description_label', parent=right_container, align=Align.TOTOP, padding=(16, -50, 16, 0)) - def on_flavor_text_size_changed(self, width, height): + def on_right_container_size_changed(self, width, height): self.height = max(self.default_height, height) @threadutils.highlander_threaded def update(self): - self.progress.update() self.icon.update() self.name_plate.update() - self.flavor_text.text = self.controller.flavor_text + self.description_label.text = self.controller.description_for_selected_milestone class NamePlate(Container): - default_height = 28 + default_height = CIRCLE_SIZE def __init__(self, controller, *args, **kwargs): super(NamePlate, self).__init__(*args, **kwargs) @@ -57,9 +54,18 @@ class NamePlate(Container): self.update() def construct_layout(self): - Fill(name='background', parent=self, color=eveColor.FOCUS_BLUE, opacity=0.1) + self.decoration = StretchSpriteHorizontal(name='decoration', parent=self, texturePath='res:/UI/Texture/classes/Achievements/card/expanded_header_ring.png', leftEdgeSize=164, rightEdgeSize=4, width=542 - CIRCLE_SIZE, height=self.default_height, padLeft=-CIRCLE_SIZE) self.label = TextCustom(name='label', parent=self, align=Align.CENTERLEFT, color=TextColor.HIGHLIGHT, fontsize=18, padLeft=16) @threadutils.highlander_threaded def update(self): self.label.text = self.controller.name + self.update_color() + + def update_color(self): + self.decoration.color = eveThemeColor.THEME_FOCUS + self.decoration.opacity = 0.2 + + def OnColorThemeChanged(self): + super(NamePlate, self).OnColorThemeChanged() + self.update_color() diff --git a/achievement_system/client/ui/window/card/components/labels.py b/achievement_system/client/ui/window/card/components/labels.py @@ -5,10 +5,9 @@ from achievement_system.client.ui.window.const import COMPACT_CARD_WIDTH, TRANSI from carbonui import Align, TextAlign, TextColor, uiconst from carbonui.control.scrollContainer import ScrollContainer from carbonui.primitives.container import Container -from carbonui.primitives.fill import Fill +from carbonui.primitives.containerAutoSize import ContainerAutoSize from carbonui.text.styles import TextBody, TextHeadline from carbonui.uianimations import animations -from eve.client.script.ui import eveColor from signals import Signal NAME_ALIGN_THRESHOLD = COMPACT_CARD_WIDTH DESCRIPTION_ALIGN_MEASURE = COMPACT_CARD_WIDTH @@ -17,11 +16,9 @@ DESCRIPTION_ALIGN_THRESHOLD = 57 class CompactAchievementLabels(Container): default_height = 102 - def __init__(self, controller, compact_mode = False, display_background = True, *args, **kwargs): + def __init__(self, controller, *args, **kwargs): super(CompactAchievementLabels, self).__init__(*args, **kwargs) self.controller = controller - self.compact_mode = compact_mode - self.display_background = display_background self.on_name_click = Signal('on_name_click') self.construct_layout() self.update() @@ -51,18 +48,10 @@ class CompactAchievementLabels(Container): self.name_label.OnClick = self.on_name_label_click self.description_container = Container(name='description_container', parent=self, align=Align.TOTOP, height=65) self.scroll_container = ScrollContainer(name='scroll_container', parent=self.description_container, padding=(0, 4, 0, 4)) - side_padding = 0 if self.compact_mode else 30 - self.description_bg_container = Container(name='description_bg_container', parent=self.description_container, opacity=0.2, padding=(-side_padding, - 0, - -side_padding, - 0), display=self.display_background) - Fill(parent=self.description_bg_container, align=Align.TOTOP, color=eveColor.WHITE, height=1) - Fill(parent=self.description_bg_container, align=Align.TOBOTTOM, color=eveColor.WHITE, height=1) - Fill(bgParent=self.description_bg_container, color=eveColor.BLACK, padding=(0, -1, 0, -1)) def construct_description(self): self.scroll_container.Flush() - self.description_label = TextBody(name='description_label', parent=self.scroll_container, align=self.description_label_align, text=self.controller.description_for_selected_milestone, textAlign=TextAlign.CENTER, color=TextColor.HIGHLIGHT) + self.description_label = TextBody(name='description_label', parent=self.scroll_container, align=self.description_label_align, text=self.description_text, textAlign=TextAlign.CENTER, color=TextColor.HIGHLIGHT) @threadutils.highlander_threaded def update(self): @@ -78,13 +67,88 @@ class CompactAchievementLabels(Container): @property def description_label_align(self): - _, text_height = TextBody.MeasureTextSize(self.controller.description, width=DESCRIPTION_ALIGN_MEASURE) + _, text_height = TextBody.MeasureTextSize(text=self.description_text, width=DESCRIPTION_ALIGN_MEASURE) if text_height > DESCRIPTION_ALIGN_THRESHOLD: return uiconst.TOTOP return uiconst.VERTICALLY_CENTERED - def animate_in(self): - animations.MorphScalar(obj=self.description_bg_container, attrName='opacity', startVal=0.0, endVal=0.2, duration=TRANSITION_DURATION) + @property + def description_text(self): + return self.controller.description_for_selected_milestone + + def on_achievement_completed(self, achievement_id): + if achievement_id == self.controller.achievement_entry.identifier: + self.update() + + def on_achievement_progressed(self, achievement_id, achievement_state): + if achievement_id == self.controller.achievement_entry.identifier: + self.update() + + def on_achievement_reset(self, achievement_id): + if achievement_id == self.controller.achievement_entry.identifier: + self.update() + + def on_achievement_reset_all(self): + self.update() + + def on_name_label_click(self, *args): + self.on_name_click() + + +class HoverAchievementLabels(ContainerAutoSize): + + def __init__(self, controller, *args, **kwargs): + super(HoverAchievementLabels, self).__init__(*args, **kwargs) + self.controller = controller + self.on_name_click = Signal('on_name_click') + self.construct_layout() + self.update() + self.connect_signals() + + def Close(self): + try: + self.disconnect_signals() + finally: + super(HoverAchievementLabels, self).Close() + + def connect_signals(self): + on_achievement_completed.connect(self.on_achievement_completed) + on_achievement_progressed.connect(self.on_achievement_progressed) + on_admin_achievement_reset.connect(self.on_achievement_reset) + on_admin_achievement_reset_all.connect(self.on_achievement_reset_all) + + def disconnect_signals(self): + on_achievement_completed.disconnect(self.on_achievement_completed) + on_achievement_progressed.disconnect(self.on_achievement_progressed) + on_admin_achievement_reset.disconnect(self.on_achievement_reset) + on_admin_achievement_reset_all.disconnect(self.on_achievement_reset_all) + + def construct_layout(self): + name_container = Container(name='name_container', parent=self, align=Align.TOTOP, height=37) + self.name_label = TextHeadline(name='name_label', parent=name_container, align=self.name_label_align, state=uiconst.UI_NORMAL, color=TextColor.HIGHLIGHT, maxLines=1, autoFadeSides=16) + self.name_label.OnClick = self.on_name_label_click + self.description_container = Container(name='description_container', parent=self, align=Align.TOTOP, clipChildren=True, height=65, padTop=4) + self.description_label = TextBody(name='description_label', parent=self.description_container, align=Align.VERTICALLY_CENTERED, textAlign=TextAlign.CENTER, color=TextColor.HIGHLIGHT) + + def animate_in(self, duration = TRANSITION_DURATION): + _, text_height = TextBody.MeasureTextSize(self.description_text, width=COMPACT_CARD_WIDTH) + animations.MorphScalar(obj=self.description_container, attrName='height', startVal=self.description_container.height, endVal=text_height, duration=duration) + + @threadutils.highlander_threaded + def update(self): + self.name_label.text = self.controller.name + self.description_label.text = self.description_text + + @property + def name_label_align(self): + text_width, _ = TextHeadline.MeasureTextSize(self.controller.name) + if text_width > NAME_ALIGN_THRESHOLD: + return uiconst.TOLEFT + return uiconst.CENTER + + @property + def description_text(self): + return self.controller.description_for_selected_milestone def on_achievement_completed(self, achievement_id): if achievement_id == self.controller.achievement_entry.identifier: diff --git a/achievement_system/client/ui/window/card/components/list_entry.py b/achievement_system/client/ui/window/card/components/list_entry.py @@ -1,25 +0,0 @@ -#Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\achievement_system\client\ui\window\card\components\list_entry.py -from carbonui import Align, TextColor -from carbonui.primitives.container import Container -from carbonui.primitives.stretchspritehorizontal import StretchSpriteHorizontal -from carbonui.text.styles import TextBody - -class ListEntry(Container): - default_height = 34 - - def __init__(self, text, is_completed, *args, **kwargs): - super(ListEntry, self).__init__(*args, **kwargs) - self.text = text - self.is_completed = is_completed - self.construct_layout() - - def construct_layout(self): - self.background_plate = StretchSpriteHorizontal(name='background_plate', parent=self, align=Align.TOALL, texturePath=self.background_texture, leftEdgeSize=5, rightEdgeSize=35) - self.label = TextBody(name='label', parent=self, align=Align.CENTERLEFT, text=self.text, color=TextColor.HIGHLIGHT, left=16) - - @property - def background_texture(self): - if self.is_completed: - return 'res:/UI/Texture/classes/Achievements/card/list_entry_bg_completed.png' - else: - return 'res:/UI/Texture/classes/Achievements/card/list_entry_bg_default.png' diff --git a/achievement_system/client/ui/window/card/components/milestones.py b/achievement_system/client/ui/window/card/components/milestones.py @@ -1,4 +1,5 @@ #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\achievement_system\client\ui\window\card\components\milestones.py +import math import threadutils from achievement_system.client.api.signal import on_achievement_completed, on_achievement_milestone_reached, on_admin_achievement_reset, on_admin_achievement_reset_all from achievement_system.client.ui.window.const import TRANSITION_DURATION, HISTORIC_COMPLETE_COLOR, HISTORIC_INCOMPLETE_COLOR @@ -8,10 +9,12 @@ from carbonui.primitives.container import Container from carbonui.primitives.containerAutoSize import ContainerAutoSize from carbonui.primitives.fill import Fill from carbonui.primitives.flowcontainer import FlowContainer +from carbonui.primitives.gridcontainer import GridContainer from carbonui.primitives.sprite import Sprite -from carbonui.text.styles import TextBody +from carbonui.text.styles import TextBody, TextDetail from carbonui.uianimations import animations from eve.client.script.ui import eveColor +from eve.client.script.ui.control.infoIcon import GlyphIcon from localization import GetByLabel BUTTON_SIZE = 16 BUTTON_PADDING = 4 @@ -23,6 +26,229 @@ DOT_MARKER_WIDTH = 4 DOT_MARKER_HEIGHT = 8 DOT_MARKER_SPACING = 8 +class MilestoneMarker(Container): + default_state = uiconst.UI_NORMAL + + def __init__(self, controller, milestone_index, *args, **kwargs): + super(MilestoneMarker, self).__init__(*args, **kwargs) + self.milestone_index = milestone_index + self.controller = controller + self.is_hovered = False + self.construct_layout() + self.update() + self.connect_signals() + + def Close(self): + try: + self.disconnect_signals() + finally: + super(MilestoneMarker, self).Close() + + def connect_signals(self): + on_achievement_completed.connect(self.on_achievement_completed) + on_admin_achievement_reset.connect(self.on_achievement_reset) + on_admin_achievement_reset_all.connect(self.on_achievement_reset_all) + on_achievement_milestone_reached.connect(self.on_achievement_milestone_reached) + self.controller.on_selected_milestone_changed.connect(self.on_selected_milestone_changed) + + def disconnect_signals(self): + on_achievement_completed.disconnect(self.on_achievement_completed) + on_admin_achievement_reset.disconnect(self.on_achievement_reset) + on_admin_achievement_reset_all.disconnect(self.on_achievement_reset_all) + on_achievement_milestone_reached.disconnect(self.on_achievement_milestone_reached) + self.controller.on_selected_milestone_changed.disconnect(self.on_selected_milestone_changed) + + def construct_layout(self): + self.fill = Fill(parent=self) + self.glyph_container = Container(parent=self, align=Align.CENTER, pos=(0, 0, 16, 16)) + + def construct_glyph(self): + self.glyph_container.Flush() + self.glyph = GlyphIcon(parent=self.glyph_container, align=Align.CENTER, state=uiconst.UI_DISABLED, frameTexture='res:/ui/Texture/classes/Menu/Icons/circleBG.png', frameColor=self.glyph_frame_color, glyphTexture=self.glyph_texture, glowAmount=self.glyph_glow_amount) + + @threadutils.highlander_threaded + def update(self): + self.fill.color = self.fill_color + self.update_fill_opacity() + self.construct_glyph() + + @threadutils.highlander_threaded + def update_fill_opacity(self): + self.fill.opacity = self.fill_opacity + + @property + def fill_color(self): + if self.is_completed: + if self.is_historic: + return HISTORIC_COMPLETE_COLOR + return eveColor.SUCCESS_GREEN + elif self.is_historic: + return HISTORIC_INCOMPLETE_COLOR + elif self.is_current: + return eveColor.FOCUS_BLUE + else: + return eveColor.WHITE + + @property + def fill_opacity(self): + if self.is_selected or self.is_hovered: + if self.is_completed: + return 0.6 + return 0.2 + elif self.is_completed: + return 0.3 + else: + return 0.1 + + @property + def glyph_texture(self): + if self.is_completed: + return 'res:/ui/Texture/classes/Menu/Icons/checkmark.png' + + @property + def glyph_frame_color(self): + if self.is_completed: + return eveColor.SUCCESS_GREEN + if self.is_current: + return eveColor.FOCUS_BLUE + return TextColor.SECONDARY + + @property + def glyph_glow_amount(self): + if self.is_completed or self.is_current: + return 0.5 + return 0 + + @property + def is_completed(self): + return self.milestone_index < self.controller.completed_milestones + + @property + def is_selected(self): + return self.milestone_index == self.controller.selected_milestone_index + + @property + def is_current(self): + return self.milestone_index == self.controller.current_milestone_index + + @property + def is_historic(self): + return self.controller.is_historic + + def on_achievement_completed(self, achievement_id): + if achievement_id == self.controller.achievement_entry.identifier: + self.update() + + def on_achievement_reset(self, achievement_id): + if achievement_id == self.controller.achievement_entry.identifier: + self.update() + + def on_achievement_reset_all(self): + self.update() + + def on_achievement_milestone_reached(self, achievement_id, milestone_id): + if achievement_id == self.controller.achievement_entry.identifier: + self.update() + + def on_selected_milestone_changed(self): + self.update() + + def OnClick(self, *args): + self.controller.set_selected_milestone_index(self.milestone_index) + + def OnMouseEnter(self, *args): + self.is_hovered = True + self.update_fill_opacity() + + def OnMouseExit(self, *args): + self.is_hovered = False + self.update_fill_opacity() + + +class MilestoneMarkerExpanded(MilestoneMarker): + + def construct_layout(self): + self.fill = Fill(parent=self) + self.glyph_container = Container(parent=self, align=Align.TOLEFT, pos=(0, 0, 16, 16), padLeft=8) + label_container = Container(name='label_container', parent=self) + self.label = TextBody(name='label', parent=label_container, align=Align.CENTERLEFT, state=uiconst.UI_NORMAL, padLeft=8) + self.label.OnClick = self.OnClick + + @threadutils.highlander_threaded + def update(self): + super(MilestoneMarkerExpanded, self).update() + self.label.text = self.controller.progress_score_text_for_milestone(self.milestone_index) + self.label.hint = self.controller.progress_score_hint_for_milestone(self.milestone_index) + + +class AchievementMilestonesHover(ContainerAutoSize): + label_container_height = 16 + label_class = TextDetail + marker_container_height = 24 + marker_class = MilestoneMarker + max_columns = 5 + + def __init__(self, controller, *args, **kwargs): + super(AchievementMilestonesHover, self).__init__(*args, **kwargs) + self.controller = controller + self.construct_layout() + self.update() + self.connect_signals() + + def Close(self): + try: + self.disconnect_signals() + finally: + super(AchievementMilestonesHover, self).Close() + + def connect_signals(self): + self.controller.on_selected_milestone_changed.connect(self.on_selected_milestone_changed) + + def disconnect_signals(self): + self.controller.on_selected_milestone_changed.disconnect(self.on_selected_milestone_changed) + + def construct_layout(self): + label_container = Container(name='label_container', parent=self, align=Align.TOTOP, height=self.label_container_height) + self.title_label = self.label_class(name='title_label', parent=label_container, align=Align.TOLEFT, text=GetByLabel('UI/Achievements/Window/Card/SelectedMilestone'), color=TextColor.SECONDARY) + self.index_label = self.label_class(name='index_label', parent=label_container, align=Align.TOLEFT, padLeft=4) + self.marker_container = GridContainer(name='marker_container', parent=self, align=uiconst.TOTOP, contentSpacing=(8, 8), padTop=4) + + def construct_markers(self): + self.marker_container.Flush() + total_milestones = self.controller.total_milestones + if total_milestones == 0: + return + self.marker_container.columns = min(total_milestones, self.max_columns) + num_rows = math.ceil(total_milestones / self.max_columns) + if num_rows > 1: + height_from_rows = num_rows * self.marker_container_height + height_from_padding = (num_rows - 1) * self.marker_container.contentSpacing[1] + self.marker_container.height = height_from_rows + height_from_padding + else: + self.marker_container.height = self.marker_container_height + for index in range(0, self.controller.total_milestones): + self.marker_class(parent=self.marker_container, milestone_index=index, controller=self.controller) + + @threadutils.highlander_threaded + def update(self): + self.update_label() + self.construct_markers() + + @threadutils.highlander_threaded + def update_label(self): + self.index_label.text = '(%s/%s)' % (self.controller.selected_milestone_index + 1, self.controller.total_milestones) + + def on_selected_milestone_changed(self): + self.update_label() + + +class AchievementMilestonesExpanded(AchievementMilestonesHover): + label_container_height = 20 + label_class = TextBody + marker_container_height = 28 + marker_class = MilestoneMarkerExpanded + + class BarAchievementMilestones(ContainerAutoSize): default_height = BAR_MARKER_HEIGHT_SELECTED diff --git a/achievement_system/client/ui/window/card/components/progress.py b/achievement_system/client/ui/window/card/components/progress.py @@ -1,38 +1,46 @@ #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\achievement_system\client\ui\window\card\components\progress.py import threadutils -from carbonui import Align, TextAlign, TextColor, uiconst +from carbonui import Align, TextColor, uiconst from carbonui.primitives.container import Container -from carbonui.text.styles import TextBody -from carbonui.util.color import Color -from eve.client.script.ui import eveColor -from eve.client.script.ui.control.gaugeCircular import GaugeCircular +from carbonui.primitives.containerAutoSize import ContainerAutoSize +from carbonui.text.styles import TextDetail, TextBody +from eve.client.script.ui.control.gauge import Gauge +from localization import GetByLabel -class AchievementProgress(Container): - default_height = 178 - default_width = 152 +class AchievementProgressHover(ContainerAutoSize): + label_container_height = 16 + label_class = TextDetail def __init__(self, controller, *args, **kwargs): - super(AchievementProgress, self).__init__(*args, **kwargs) + super(AchievementProgressHover, self).__init__(*args, **kwargs) self.controller = controller self.construct_layout() self.update() def construct_layout(self): - self.gauge = GaugeCircular(name='gauge', parent=self, align=Align.TOTOP, radius=self.default_width * 0.5, showMarker=False, colorBg=Color(*eveColor.FOCUS_BLUE).SetOpacity(0.1).GetRGBA(), glow=True, glowBrightness=0.3, padBottom=8) - label_container = Container(name='label_container', parent=self, align=Align.TOBOTTOM, height=18) - self.label = TextBody(name='label', parent=label_container, align=Align.TOTOP, state=uiconst.UI_NORMAL, textAlign=TextAlign.CENTER, color=TextColor.SECONDARY) + label_container = Container(name='label_container', parent=self, align=Align.TOTOP, height=self.label_container_height) + self.title_label = self.label_class(name='title_label', parent=label_container, align=Align.TOLEFT, text=GetByLabel('UI/Common/Progress'), color=TextColor.SECONDARY) + self.score_label = self.label_class(name='score_label', parent=label_container, align=Align.TOLEFT, state=uiconst.UI_NORMAL, padLeft=4) + self.gauge = Gauge(name='gauge', parent=self, align=Align.TOTOP, gaugeHeight=4, padTop=4) @threadutils.highlander_threaded def update(self): - self.label.text = self.controller.progress_score_text_for_selected_milestone - self.label.hint = self.controller.progress_score_hint_for_selected_milestone - self.gauge.SetValue(self.controller.percent_progress_towards_selected_milestone) - self.update_color_theme() + self.update_color() + self.update_value() - def update_color_theme(self): - color = self.controller.progress_bar_color - self.gauge.SetColor(colorStart=color, colorEnd=color) + def update_color(self): + self.gauge.SetColor(self.controller.milestone_progress_bar_color) + + def update_value(self): + self.score_label.text = '(%s)' % self.controller.progress_score_text_for_selected_milestone + self.score_label.hint = self.controller.progress_score_hint_for_selected_milestone + self.gauge.SetValue(self.controller.percent_progress_towards_selected_milestone, animate=False) def OnColorThemeChanged(self): - super(AchievementProgress, self).OnColorThemeChanged() - self.update_color_theme() + super(AchievementProgressHover, self).OnColorThemeChanged() + self.update_color() + + +class AchievementProgressExpanded(AchievementProgressHover): + label_container_height = 20 + label_class = TextBody diff --git a/achievement_system/client/ui/window/card/components/rewards.py b/achievement_system/client/ui/window/card/components/rewards.py @@ -1,85 +1,61 @@ #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\achievement_system\client\ui\window\card\components\rewards.py -import eveicon import threadutils -from achievement_system.client.api.signal import on_achievement_completed, on_achievement_progressed, on_admin_achievement_reset, on_admin_achievement_reset_all, on_achievement_milestone_reached +from achievement_system.client.api.signal import on_achievement_completed, on_achievement_progressed, on_achievement_milestone_reached, on_admin_achievement_reset, on_admin_achievement_reset_all from achievement_system.client.model.definition.reward.type import RewardType from achievement_system.client.ui.controller.reward import AchievementRewardController -from achievement_system.client.ui.window.card.components.score_icon import ScoreIcon, ScoreIconSmall +from achievement_system.client.ui.window.card.components.claimed_icon import ClaimedIcon +from achievement_system.client.ui.window.card.components.score_icon import ScoreIcon from carbonui import Align, AxisAlignment, uiconst, TextColor, TextAlign from carbonui.primitives.container import Container from carbonui.primitives.containerAutoSize import ContainerAutoSize +from carbonui.primitives.fill import Fill from carbonui.primitives.flowcontainer import FlowContainer +from carbonui.primitives.gradientSprite import GradientSprite from carbonui.primitives.sprite import Sprite -from carbonui.text.styles import TextHeadline -from eve.client.script.ui import eveColor +from carbonui.text.styles import TextDetail, TextBody +from eve.client.script.ui import eveColor, eveThemeColor from eveicon import IconData from localization import GetByLabel -class AchievementRewards(ContainerAutoSize): +class AchievementRewardsBase(ContainerAutoSize): + default_alignMode = Align.TOTOP - def __init__(self, controller, display_label = True, use_small_score = False, use_selected_milestone = True, *args, **kwargs): - super(AchievementRewards, self).__init__(*args, **kwargs) + def __init__(self, controller, *args, **kwargs): + super(AchievementRewardsBase, self).__init__(*args, **kwargs) self.controller = controller - self.display_label = display_label - self.use_small_score = use_small_score - self.use_selected_milestone = use_selected_milestone self.construct_layout() self.update() self.connect_signals() + self.on_size_changed_signal(*self.GetAbsoluteSize()) def Close(self): try: self.disconnect_signals() finally: - super(AchievementRewards, self).Close() + super(AchievementRewardsBase, self).Close() def connect_signals(self): on_achievement_completed.connect(self.on_achievement_completed) on_achievement_progressed.connect(self.on_achievement_progressed) + on_achievement_milestone_reached.connect(self.on_achievement_milestone_reached) on_admin_achievement_reset.connect(self.on_achievement_reset) on_admin_achievement_reset_all.connect(self.on_achievement_reset_all) - on_achievement_milestone_reached.connect(self.on_achievement_milestone_reached) + self.on_size_changed.connect(self.on_size_changed_signal) def disconnect_signals(self): on_achievement_completed.disconnect(self.on_achievement_completed) on_achievement_progressed.disconnect(self.on_achievement_progressed) + on_achievement_milestone_reached.disconnect(self.on_achievement_milestone_reached) on_admin_achievement_reset.disconnect(self.on_achievement_reset) on_admin_achievement_reset_all.disconnect(self.on_achievement_reset_all) - on_achievement_milestone_reached.disconnect(self.on_achievement_milestone_reached) + self.on_size_changed.disconnect(self.on_size_changed_signal) def construct_layout(self): - if self.display_label: - TextHeadline(name='label', parent=self, align=Align.TOTOP, textAlign=TextAlign.CENTER, text=GetByLabel('UI/Achievements/Window/Card/Rewards'), color=TextColor.HIGHLIGHT, padTop=-8, padBottom=2) - self.flow_container = FlowContainer(name='flow_container', parent=self, align=Align.TOTOP, contentSpacing=(12, 0), contentAlignment=AxisAlignment.CENTER, crossAxisAlignment=AxisAlignment.CENTER, height=self.rewards_height) + raise NotImplementedError @threadutils.highlander_threaded def update(self): - self.flow_container.Flush() - if self.use_selected_milestone: - rewards_to_use = self.controller.selected_milestone_rewards - else: - rewards_to_use = self.controller.current_milestone_rewards - num_rewards = len(rewards_to_use) - self.flow_container.width = num_rewards * 40 + (num_rewards - 1) * 40 - reward_ids = [ entry.identifier for entry in rewards_to_use ] - reward_controller = AchievementRewardController(identifier=self.controller.achievement_entry.identifier, milestone_id=self.controller.selected_milestone_id, rewards=reward_ids) - reward_data = reward_controller.reward_data - for data in reward_data: - RewardEntry(name='reward_entry_container', parent=self.flow_container, pickState=uiconst.TR2_SPS_ON, reward_data=data) - - self.score_icon_class(name='score_icon', parent=self.flow_container, controller=self.controller, use_selected_milestone=self.use_selected_milestone) - - @property - def rewards_height(self): - if self.use_small_score: - return 40 - return 64 - - @property - def score_icon_class(self): - if self.use_small_score: - return ScoreIconSmall - return ScoreIcon + raise NotImplementedError def on_achievement_completed(self, achievement_id): if achievement_id == self.controller.achievement_entry.identifier: @@ -89,6 +65,10 @@ class AchievementRewards(ContainerAutoSize): if achievement_id == self.controller.achievement_entry.identifier: self.update() + def on_achievement_milestone_reached(self, achievement_id, milestone_id): + if achievement_id == self.controller.achievement_entry.identifier: + self.update() + def on_achievement_reset(self, achievement_id): if achievement_id == self.controller.achievement_entry.identifier: self.update() @@ -96,14 +76,137 @@ class AchievementRewards(ContainerAutoSize): def on_achievement_reset_all(self): self.update() - def on_achievement_milestone_reached(self, achievement_id, milestone_id): - if achievement_id == self.controller.achievement_entry.identifier: - self.update() + def on_size_changed_signal(self, width, height): + pass + + +class AchievementRewardsHover(AchievementRewardsBase): + + def construct_layout(self): + content_container = ContainerAutoSize(name='content_container', parent=self, align=Align.TOTOP, padding=(8, 4, 8, 8)) + TextDetail(name='label', parent=content_container, align=Align.TOTOP, text=GetByLabel('UI/Achievements/Window/Card/Rewards'), textAlign=TextAlign.CENTER, color=TextColor.SECONDARY) + self.flow_container = FlowContainer(name='flow_container', parent=content_container, align=Align.TOTOP, contentSpacing=(12, 0), contentAlignment=AxisAlignment.CENTER, crossAxisAlignment=AxisAlignment.CENTER, padTop=8) + self.background_plate = SolidBackground(name='background_plate', parent=self, align=Align.CENTERTOP) + + @threadutils.highlander_threaded + def update(self): + self.flow_container.Flush() + rewards = self.controller.selected_milestone_rewards + reward_ids = [ entry.identifier for entry in rewards ] + reward_controller = AchievementRewardController(identifier=self.controller.achievement_entry.identifier, milestone_id=self.controller.selected_milestone_id, rewards=reward_ids) + reward_data = reward_controller.reward_data + for data in reward_data: + RewardEntry(name='reward_entry_container', parent=self.flow_container, pickState=uiconst.TR2_SPS_ON, reward_data=data) + + ScoreIcon(name='score_icon', parent=self.flow_container, controller=self.controller) + + def on_size_changed_signal(self, width, height): + self.background_plate.width = width + self.background_plate.height = height + + +class AchievementRewardsExpanded(AchievementRewardsBase): + + def construct_layout(self): + content_container = ContainerAutoSize(name='content_container', parent=self, align=Align.TOTOP, padding=(8, 8, 8, 8)) + TextBody(name='label', parent=content_container, align=Align.TOTOP, text=GetByLabel('UI/Achievements/Window/Card/Rewards'), color=TextColor.SECONDARY) + self.flow_container = FlowContainer(name='flow_container', parent=content_container, align=Align.TOTOP, contentSpacing=(8, 8), padTop=4) + self.background_plate = SolidBackground(name='background_plate', parent=self, align=Align.CENTERTOP) + + @threadutils.highlander_threaded + def update(self): + self.flow_container.Flush() + rewards = self.controller.selected_milestone_rewards + reward_ids = [ entry.identifier for entry in rewards ] + reward_controller = AchievementRewardController(identifier=self.controller.achievement_entry.identifier, milestone_id=self.controller.selected_milestone_id, rewards=reward_ids) + reward_data = reward_controller.reward_data + total_rewards = len(reward_data) + has_score_reward = self.controller.selected_milestone_score > 0 + if has_score_reward: + total_rewards += 1 + if total_rewards == 0: + return + is_odd_number_of_rewards = total_rewards % 2 == 1 + for index, data in enumerate(reward_data): + is_last_entry = index == total_rewards - 1 + use_full_width = is_last_entry and is_odd_number_of_rewards + self.add_reward(RewardEntryExpanded, data, use_full_width) + + if not has_score_reward: + return + use_full_width = is_odd_number_of_rewards + self.add_reward(RewardScoreExpanded, None, use_full_width) + + def add_reward(self, component_class, reward_data, use_full_width): + if use_full_width: + width = self.reward_max_width + else: + width = RewardEntryExpanded.default_width + component_class(name='reward_entry', parent=self.flow_container, controller=self.controller, reward_data=reward_data, is_full_width=use_full_width, width=width) + + @property + def reward_max_width(self): + return self.flow_container.contentSpacing[0] + RewardEntryExpanded.default_width * 2 + + def on_size_changed_signal(self, width, height): + self.background_plate.width = width + self.background_plate.height = height + + +class SolidBackground(Container): + default_state = uiconst.UI_DISABLED + default_opacity = 0.1 + + def __init__(self, *args, **kwargs): + super(SolidBackground, self).__init__(*args, **kwargs) + self.update() + + @threadutils.highlander_threaded + def update(self): + self.Flush() + Fill(parent=self, color=eveThemeColor.THEME_FOCUS.rgba) + + def OnColorThemeChanged(self): + super(SolidBackground, self).OnColorThemeChanged() + self.update() + + +class GradientBackground(Container): + default_state = uiconst.UI_DISABLED + default_opacity = 0.1 + + def __init__(self, *args, **kwargs): + super(GradientBackground, self).__init__(*args, **kwargs) + self.update() + + @threadutils.highlander_threaded + def update(self): + self.Flush() + DividerGradient(parent=self, align=Align.TOTOP, height=1) + DividerGradient(parent=self, align=Align.TOBOTTOM, height=1) + GradientSprite(parent=self, align=Align.TOALL, rgbData=[(0.0, eveThemeColor.THEME_FOCUS[:3]), (1.0, eveThemeColor.THEME_FOCUS[:3])], alphaData=[(0.0, 0.0), + (0.1, 1.0), + (0.9, 1.0), + (1.0, 0.0)]) + + def OnColorThemeChanged(self): + super(GradientBackground, self).OnColorThemeChanged() + self.update() + + +class DividerGradient(GradientSprite): + default_rgbData = [(0.0, eveColor.WHITE[:3]), (1.0, eveColor.WHITE[:3])] + default_alphaData = [(0.0, 0.0), + (0.1, 1.0), + (0.9, 1.0), + (1.0, 0.0)] class RewardEntry(Container): + default_state = uiconst.UI_NORMAL default_height = 40 default_width = 40 + claimed_icon_offset = -2 def __init__(self, reward_data, *args, **kwargs): super(RewardEntry, self).__init__(*args, **kwargs) @@ -112,25 +215,102 @@ class RewardEntry(Container): self.update() def construct_layout(self): - self.complete_icon = Sprite(name='complete_icon', parent=self, align=Align.TOPRIGHT, state=uiconst.UI_DISABLED, texturePath=eveicon.circle_checkmark, color=eveColor.SUCCESS_GREEN, pos=(-4, -4, 16, 16)) - self.background_texture_path = 'res:/UI/Texture/classes/Achievements/reward_background.png' - icon_size = 20 if self.reward_data.reward_type == RewardType.SP else 16 - Sprite(name='icon', parent=self, align=Align.CENTER, width=icon_size, height=icon_size, texturePath=self.reward_data.icon, pickState=uiconst.TR2_SPS_OFF) + self.claimed_icon = ClaimedIcon(name='claimed_icon', parent=self, align=Align.TOPRIGHT, pos=(self.claimed_icon_offset, + self.claimed_icon_offset, + 16, + 16)) + Sprite(name='icon', parent=self, align=Align.CENTER, state=uiconst.UI_DISABLED, texturePath=self.reward_data.icon, pos=(0, + 0, + self.icon_size, + self.icon_size)) + self.background_icon = Sprite(name='background_icon', parent=self, align=Align.CENTER, state=uiconst.UI_DISABLED, texturePath='res:/UI/Texture/classes/Achievements/reward_background.png', pos=(0, + 0, + self.default_width, + self.default_height)) @threadutils.highlander_threaded def update(self): - self.complete_icon.display = self.reward_data.is_claimed + self.claimed_icon.display = self.reward_data.is_claimed + if self.reward_data.is_granted: + self.background_icon.color = eveColor.SUCCESS_GREEN + else: + self.background_icon.color = eveThemeColor.THEME_FOCUSDARK def LoadTooltipPanel(self, tooltipPanel, *args): + label_text = self.reward_data.hint + if label_text is None: + return tooltipPanel.LoadStandardSpacing() tooltipPanel.columns = 2 - label_text = self.reward_data.hint if self.reward_data.is_title else self.reward_data.text - if self.reward_data.is_title: - tooltipPanel.AddLabelMedium(text=label_text) - return if isinstance(self.reward_data.icon, IconData): icon = self.reward_data.icon.resolve(16) else: icon = self.reward_data.icon - icon_size = 20 if self.reward_data.reward_type == RewardType.SP else 16 - tooltipPanel.AddIconLabel(icon=icon, iconSize=icon_size, label=label_text) + _, labelObj = tooltipPanel.AddIconLabel(icon=icon, iconSize=self.icon_size, iconColor=TextColor.HIGHLIGHT, label=label_text, bold=False) + if self.reward_data.is_item: + tooltipPanel.state = uiconst.UI_NORMAL + labelObj.state = uiconst.UI_NORMAL + + @property + def icon_size(self): + if self.reward_data.reward_type == RewardType.SP: + return 20 + return 16 + + def OnColorThemeChanged(self): + super(RewardEntry, self).OnColorThemeChanged() + self.update() + + +class RewardEntryExpanded(Container): + default_height = 40 + default_width = 212 + + def __init__(self, controller, reward_data, is_full_width, *args, **kwargs): + super(RewardEntryExpanded, self).__init__(*args, **kwargs) + self.controller = controller + self.reward_data = reward_data + self.is_full_width = is_full_width + self.construct_layout() + self.update() + + def construct_layout(self): + self.construct_icon() + label_container = Container(name='label_container', parent=self, align=Align.VERTICALLY_CENTERED, height=20, padLeft=8) + self.label = TextBody(name='label', parent=label_container, align=Align.TOLEFT, state=uiconst.UI_NORMAL, maxLines=1, autoFadeSides=16) + + def construct_icon(self): + self.icon = RewardEntry(name='icon', parent=self, align=Align.TOLEFT, state=uiconst.UI_DISABLED, reward_data=self.reward_data) + + @threadutils.highlander_threaded + def update(self): + self.label.text = self.reward_data.text + if self.reward_data.is_item: + if self.is_full_width: + self.label.state = uiconst.UI_NORMAL + else: + self.label.state = uiconst.UI_DISABLED + self.state = uiconst.UI_NORMAL + self.LoadTooltipPanel = lambda tooltipPanel, *args: ItemTooltipPanel(tooltipPanel, self.reward_data) + + +class RewardScoreExpanded(RewardEntryExpanded): + + def construct_icon(self): + self.icon = ScoreIcon(name='icon', parent=self, align=Align.TOLEFT, state=uiconst.UI_DISABLED, controller=self.controller) + + @threadutils.highlander_threaded + def update(self): + self.label.text = GetByLabel('UI/Achievements/Window/Card/AchievementPointsHint') + + +def ItemTooltipPanel(tooltipPanel, reward_data, *args): + tooltipPanel.LoadStandardSpacing() + tooltipPanel.columns = 2 + if isinstance(reward_data.icon, IconData): + icon = reward_data.icon.resolve(16) + else: + icon = reward_data.icon + _, labelObj = tooltipPanel.AddIconLabel(icon=icon, iconSize=16, label=reward_data.hint) + tooltipPanel.state = uiconst.UI_NORMAL + labelObj.state = uiconst.UI_NORMAL diff --git a/achievement_system/client/ui/window/card/components/score_icon.py b/achievement_system/client/ui/window/card/components/score_icon.py @@ -1,29 +1,29 @@ #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\achievement_system\client\ui\window\card\components\score_icon.py -import eveicon import threadutils +from achievement_system.client.ui.window.card.components.claimed_icon import ClaimedIcon from carbonui import Align, TextColor, uiconst from carbonui.primitives.container import Container from carbonui.primitives.sprite import Sprite from carbonui.text.styles import TextHeader -from eve.client.script.ui import eveColor +from eve.client.script.ui import eveColor, eveThemeColor from localization import GetByLabel class ScoreIcon(Container): - default_width = 64 - default_height = 64 + default_width = 42 + default_height = 40 default_state = uiconst.UI_NORMAL default_hint = GetByLabel('UI/Achievements/Window/Card/AchievementPointsHint') + claimed_icon_offset = -2 - def __init__(self, controller, use_selected_milestone = True, *args, **kwargs): + def __init__(self, controller, *args, **kwargs): super(ScoreIcon, self).__init__(*args, **kwargs) self.controller = controller - self.use_selected_milestone = use_selected_milestone self.construct_layout() self.update() def construct_layout(self): - self.complete_icon = Sprite(name='complete_icon', parent=self, align=Align.TOPRIGHT, state=uiconst.UI_DISABLED, texturePath=eveicon.circle_checkmark, color=eveColor.SUCCESS_GREEN, pos=(self.complete_icon_offset, - self.complete_icon_offset, + self.claimed_icon = ClaimedIcon(name='claimed_icon', parent=self, align=Align.TOPRIGHT, pos=(self.claimed_icon_offset, + self.claimed_icon_offset, 16, 16)) self.label = TextHeader(name='label', parent=self, align=Align.CENTER, color=TextColor.HIGHLIGHT) @@ -34,24 +34,11 @@ class ScoreIcon(Container): @threadutils.highlander_threaded def update(self): - if self.use_selected_milestone: - self.label.text = self.controller.selected_milestone_score - self.complete_icon.display = self.controller.is_selected_milestone_completed - self.display = self.controller.selected_milestone_score > 0 + if self.controller.is_selected_milestone_completed: + self.icon.color = eveColor.SUCCESS_GREEN + self.claimed_icon.display = True else: - self.label.text = self.controller.current_milestone_score - self.complete_icon.display = self.controller.is_current_milestone_completed - self.display = self.controller.current_milestone_score > 0 - - @property - def complete_icon_offset(self): - return 4 - - -class ScoreIconSmall(ScoreIcon): - default_width = 40 - default_height = 40 - - @property - def complete_icon_offset(self): - return -2 + self.icon.color = eveThemeColor.THEME_FOCUSDARK + self.claimed_icon.display = False + self.label.text = self.controller.selected_milestone_score + self.display = self.controller.selected_milestone_score > 0 diff --git a/achievement_system/client/ui/window/card/components/track_button.py b/achievement_system/client/ui/window/card/components/track_button.py @@ -1,7 +1,7 @@ #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\achievement_system\client\ui\window\card\components\track_button.py import eveicon import threadutils -from achievement_system.client.api.signal import on_tracked_achievement_changed +from achievement_system.client.api.signal import on_achievements_tracked_changed from carbonui import ButtonFrameType, ButtonVariant, Density from carbonui.control.button import Button from localization import GetByLabel @@ -26,10 +26,10 @@ class TrackButton(Button): super(TrackButton, self).Close() def connect_signals(self): - on_tracked_achievement_changed.connect(self._on_tracked_achievement_changed) + on_achievements_tracked_changed.connect(self._on_tracked_achievements_changed) def disconnect_signals(self): - on_tracked_achievement_changed.disconnect(self._on_tracked_achievement_changed) + on_achievements_tracked_changed.disconnect(self._on_tracked_achievements_changed) @threadutils.highlander_threaded def update(self, animate = True): @@ -47,7 +47,7 @@ class TrackButton(Button): self.hint = GetByLabel('UI/Achievements/Window/Card/TrackButtonHint') self.texturePath = eveicon.look_at - def _on_tracked_achievement_changed(self, _achievement_id): + def _on_tracked_achievements_changed(self, achievement_ids): self.update() def _on_click(self, *args): diff --git a/achievement_system/client/ui/window/card/expanded_card.py b/achievement_system/client/ui/window/card/expanded_card.py @@ -1,32 +1,31 @@ #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\achievement_system\client\ui\window\card\expanded_card.py import threadutils -from achievement_system.client.api.repository import get_repository from achievement_system.client.api.signal import on_achievement_completed, on_achievement_progressed, on_admin_achievement_reset, on_admin_achievement_reset_all from achievement_system.client.qa import is_qa from achievement_system.client.qa.actions import qa_complete_achievement, qa_progress_achievement, qa_reset_achievement from achievement_system.client.ui.controller.achievement_entry import AchievementEntryController -from achievement_system.client.ui.window.card.components.contribution import AchievementContribution +from achievement_system.client.ui.window.card.components.contribution import AchievementContribution, ChecklistContribution from achievement_system.client.ui.window.card.components.header import AchievementHeader -from achievement_system.client.ui.window.card.components.milestones import BarAchievementMilestones +from achievement_system.client.ui.window.card.components.milestones import AchievementMilestonesExpanded from achievement_system.client.ui.window.card.components.pin_button import PinButton -from achievement_system.client.ui.window.card.components.progress import AchievementProgress -from achievement_system.client.ui.window.card.components.rewards import AchievementRewards +from achievement_system.client.ui.window.card.components.progress import AchievementProgressExpanded +from achievement_system.client.ui.window.card.components.rewards import AchievementRewardsExpanded from achievement_system.client.ui.window.card.components.track_button import TrackButton -from carbonui import Align, uiconst +from carbonui import Align, uiconst, TextAlign, TextColor from carbonui.button.group import ButtonGroup, ButtonSizeMode from carbonui.control.contextMenu.menuData import MenuData from carbonui.primitives.container import Container from carbonui.primitives.containerAutoSize import ContainerAutoSize -from carbonui.primitives.fill import Fill -from carbonui.primitives.sprite import Sprite -from carbonui.primitives.stretchspritevertical import StretchSpriteVertical -from carbonui.text.styles import TextBody +from carbonui.primitives.frame import Frame +from carbonui.primitives.stretchspritehorizontal import StretchSpriteHorizontal +from carbonui.text.styles import TextDetail from eve.client.script.ui import eveColor from signals import Signal +CONTENT_LEFT_INSET = 54 class ExpandedAchievementCard(ContainerAutoSize): default_state = uiconst.UI_NORMAL - default_width = 500 + default_width = 567 def __init__(self, controller, *args, **kwargs): super(ExpandedAchievementCard, self).__init__(*args, **kwargs) @@ -64,69 +63,78 @@ class ExpandedAchievementCard(ContainerAutoSize): self.construct_background() self.construct_header() self.construct_content_container() - self.construct_description() - self.add_divider() + self.construct_milestones() + self.construct_progress() self.construct_contribution() - self.add_divider() self.construct_rewards() - self.construct_milestones() self.construct_buttons() + self.construct_flavor_text() def construct_background(self): background_container = Container(name='background_container', bgParent=self) - self.background_frame = StretchSpriteVertical(name='background_frame', parent=background_container, texturePath='res:/UI/Texture/classes/Achievements/card/expanded_bg_frame.png', topEdgeSize=265, bottomEdgeSize=45) - self.background_fill = StretchSpriteVertical(name='background_fill', parent=background_container, texturePath='res:/UI/Texture/classes/Achievements/card/expanded_bg_fill.png', topEdgeSize=265, bottomEdgeSize=45) - - def construct_content_container(self): - self.content_container = ContainerAutoSize(name='content_container', parent=self, align=Align.TOTOP, padding=(32, 0, 32, 50)) - - def construct_description(self): - self.description_label = TextBody(name='description_label', parent=self.content_container, align=Align.TOTOP, padTop=24) + self.background_frame = Frame(name='background_frame', parent=background_container, texturePath='res:/UI/Texture/classes/Achievements/card/expanded_bg_frame.png', cornerSize=176, uiScaleVertices=True) + self.background_fill = Frame(name='background_fill', parent=background_container, texturePath='res:/UI/Texture/classes/Achievements/card/expanded_bg_fill.png', cornerSize=176, uiScaleVertices=True) def construct_header(self): - self.header = AchievementHeader(name='header', parent=self, align=Align.TOTOP, controller=self.controller, padding=(10, 10, 17, 0)) + self.header = AchievementHeader(name='header', parent=self, align=Align.TOTOP, controller=self.controller, padding=(8, 8, 1, 0)) - def construct_progress(self): - self.progress_container = AchievementProgress(name='progress', parent=self.content_container, align=Align.TOTOP, controller=self.controller, padTop=12) - Fill(parent=self.progress_container, align=Align.TOBOTTOM, color=eveColor.WHITE, opacity=0.3, height=1) + def construct_content_container(self): + self.content_container = ContainerAutoSize(name='content_container', parent=self, align=Align.TOTOP, padding=(CONTENT_LEFT_INSET + 24, + 0, + 24, + 24)) def construct_milestones(self): if not self.controller.has_multiple_milestones: return - self.add_divider() - milestones_container = Container(name='milestones_container', parent=self.content_container, align=Align.TOTOP, height=BarAchievementMilestones.default_height, padTop=16) - self.milestones = BarAchievementMilestones(name='milestones', parent=milestones_container, align=Align.CENTERTOP, controller=self.controller) + self.milestones = AchievementMilestonesExpanded(name='milestones', parent=self.content_container, align=Align.TOTOP, controller=self.controller, padTop=20) - def construct_rewards(self): - self.rewards = AchievementRewards(name='rewards', parent=self.content_container, align=Align.TOTOP, controller=self.controller, pickState=uiconst.TR2_SPS_ON, padTop=16) + def construct_progress(self): + self.progress = AchievementProgressExpanded(name='progress', parent=self.content_container, align=Align.TOTOP, controller=self.controller, padTop=16) def construct_contribution(self): - self.contribution = AchievementContribution(name='contribution', parent=self.content_container, align=Align.TOTOP, controller=self.controller, padTop=16) + self.contribution_class(name='contribution', parent=self.content_container, align=Align.TOTOP, controller=self.controller, padTop=16) + + def construct_rewards(self): + self.rewards = AchievementRewardsExpanded(name='rewards', parent=self.content_container, align=Align.TOTOP, controller=self.controller, padTop=16) def construct_buttons(self): - button_container = Container(name='button_container', parent=self.content_container, align=Align.TOTOP, height=40, padTop=16) - button_group = ButtonGroup(name='button_group', parent=button_container, align=Align.CENTERTOP, button_size_mode=ButtonSizeMode.STRETCH, width=336) + button_group = ButtonGroup(name='button_group', parent=self.content_container, align=Align.TOTOP, button_size_mode=ButtonSizeMode.STRETCH, padTop=16) self.track_button = TrackButton(name='track_button', parent=button_group, align=Align.TOTOP, controller=self.controller) PinButton(name='pin_button', parent=button_group, align=Align.TOTOP, controller=self.controller) def add_divider(self): - Sprite(name='divider', parent=self.content_container, align=Align.TOTOP, texturePath='res:/UI/Texture/classes/Achievements/card/expanded_card_divider.png', pos=(0, 0, 400, 1), padTop=16) + StretchSpriteHorizontal(name='divider', parent=self.content_container, align=Align.TOTOP, texturePath='res:/UI/Texture/classes/Achievements/card/expanded_card_divider.png', leftEdgeSize=52, rightEdgeSize=52, opacity=0.1, height=1, padTop=16) + + def construct_flavor_text(self): + if not self.controller.has_flavor_text: + return + self.add_divider() + self.flavor_label = TextDetail(name='flavor_label', parent=self.content_container, align=Align.TOTOP, textAlign=TextAlign.CENTER, color=TextColor.SECONDARY, italic=True, padTop=14) @threadutils.highlander_threaded def update(self): self.update_background() self.header.update() - self.description_label.text = self.controller.description_for_selected_milestone + self.progress.update() self.rewards.update() + self.update_flavor_text() self.on_update_complete() def update_background(self): - if self.controller.is_completed: - self.background_frame.color = eveColor.SUCCESS_GREEN - self.background_frame.opacity = 0.4 - else: - self.background_frame.color = eveColor.WHITE - self.background_frame.opacity = 0.2 + self.background_frame.color = eveColor.WHITE + self.background_frame.opacity = 0.2 + + def update_flavor_text(self): + if not self.controller.has_flavor_text: + return + self.flavor_label.text = self.controller.flavor_text + + @property + def contribution_class(self): + if self.controller.is_checklist: + return ChecklistContribution + return AchievementContribution def on_achievement_completed(self, achievement_id): if achievement_id == self.controller.achievement_entry.identifier: diff --git a/achievement_system/client/ui/window/card/expanded_card_list.py b/achievement_system/client/ui/window/card/expanded_card_list.py @@ -1,105 +0,0 @@ -#Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\achievement_system\client\ui\window\card\expanded_card_list.py -import threadutils -from achievement_system.client.api.signal import on_achievement_completed, on_admin_achievement_reset, on_admin_achievement_reset_all -from achievement_system.client.ui.util import get_controller_for_configured_parameter -from achievement_system.client.ui.window.card.components.header import NamePlate -from achievement_system.client.ui.window.card.components.list_entry import ListEntry -from carbonui import Align, uiconst -from carbonui.primitives.container import Container -from carbonui.primitives.containerAutoSize import ContainerAutoSize -from carbonui.primitives.stretchspritevertical import StretchSpriteVertical -from eve.client.script.ui import eveColor -from localization import GetByLabel - -class ExpandedAchievementList(ContainerAutoSize): - default_state = uiconst.UI_NORMAL - default_width = 358 - default_height = 205 - - def __init__(self, controller, *args, **kwargs): - super(ExpandedAchievementList, self).__init__(*args, **kwargs) - self.controller = controller - self.construct_layout() - self.update() - self.connect_signals() - self.on_size_changed_signal(*self.GetAbsoluteSize()) - - def Close(self): - try: - self.disconnect_signals() - finally: - super(ExpandedAchievementList, self).Close() - - def connect_signals(self): - on_achievement_completed.connect(self.on_achievement_completed) - on_admin_achievement_reset.connect(self.on_achievement_reset) - on_admin_achievement_reset_all.connect(self.on_achievement_reset_all) - self.on_size_changed.connect(self.on_size_changed_signal) - - def disconnect_signals(self): - on_achievement_completed.disconnect(self.on_achievement_completed) - on_admin_achievement_reset.disconnect(self.on_achievement_reset) - on_admin_achievement_reset_all.disconnect(self.on_achievement_reset_all) - self.on_size_changed.disconnect(self.on_size_changed_signal) - - def construct_layout(self): - self.construct_background() - self.construct_content() - - def construct_background(self): - background_container = Container(name='background_container', bgParent=self) - self.background_frame = StretchSpriteVertical(name='background_frame', parent=background_container, texturePath='res:/UI/Texture/classes/Achievements/card/expanded_list_bg_frame_crop.png', topEdgeSize=5, bottomEdgeSize=5) - self.background_fill = StretchSpriteVertical(name='background_fill', parent=background_container, texturePath='res:/UI/Texture/classes/Achievements/card/expanded_list_bg_fill_crop.png', topEdgeSize=5, bottomEdgeSize=5) - - def construct_content(self): - ListNamePlate(name='name_plate', parent=self, align=Align.TOTOP, controller=self.controller, top=26) - self.content_container = ContainerAutoSize(name='content_container', parent=self, align=Align.TOTOP, padding=(26, 8, 10, 8)) - self.reconstruct_entries() - - def reconstruct_entries(self): - self.content_container.Flush() - for param_entry, param_config in self.controller.parameters_to_display_as_list: - component_controller = get_controller_for_configured_parameter(definition=param_entry.get_ui_controller(), configuration=param_config.get_ui_controller()) - if component_controller is None: - continue - values = component_controller.values - if values and isinstance(values, list): - for entry in values: - ListEntry(parent=self.content_container, align=Align.TOTOP, text=component_controller.get_entry_title(entry), is_completed=self.controller.is_checklist_item_done(entry), padBottom=2) - - @threadutils.highlander_threaded - def update(self): - self.update_background() - self.reconstruct_entries() - - def update_background(self): - if self.controller.is_completed: - self.background_frame.color = eveColor.SUCCESS_GREEN - self.background_frame.opacity = 0.4 - else: - self.background_frame.color = eveColor.WHITE - self.background_frame.opacity = 0.2 - - def on_achievement_completed(self, achievement_id): - if achievement_id == self.controller.achievement_entry.identifier: - self.update() - - def on_achievement_reset(self, achievement_id): - if achievement_id == self.controller.achievement_entry.identifier: - self.update() - - def on_achievement_reset_all(self): - self.update() - - def on_size_changed_signal(self, *args): - self.background_frame.displayWidth = self.displayWidth - self.background_frame.displayHeight = self.displayHeight - self.background_fill.displayWidth = self.displayWidth - self.background_fill.displayHeight = self.displayHeight - - -class ListNamePlate(NamePlate): - - @threadutils.highlander_threaded - def update(self): - self.label.text = GetByLabel('UI/Achievements/Window/Card/ListTitle') diff --git a/achievement_system/client/ui/window/card/expanded_card_overlay.py b/achievement_system/client/ui/window/card/expanded_card_overlay.py @@ -2,7 +2,6 @@ import threadutils from achievement_system.client.ui.controller.achievement_entry import AchievementEntryController from achievement_system.client.ui.window.card.expanded_card import ExpandedAchievementCard -from achievement_system.client.ui.window.card.expanded_card_list import ExpandedAchievementList from achievement_system.client.ui.window.const import TRANSITION_DURATION from carbonui import Align, uiconst from carbonui.control.scrollContainer import ScrollContainer @@ -54,20 +53,11 @@ class AchievementCardOverlay(Container): self.card_container = Container(name='card_container', parent=self.scroll_container, align=Align.CENTER, state=uiconst.UI_NORMAL, width=self.scroll_container_width - SCROLL_PADDING) self.card_container.OnClick = self.OnClick self.expanded_card = ExpandedAchievementCard(name='expanded_card', parent=self.card_container, align=Align.TOPLEFT, controller=self.controller) - self.construct_list() Fill(parent=self, color=eveColor.BLACK, opacity=0.85) - def construct_list(self): - if not self.controller.is_checklist: - return - self.expanded_list = ExpandedAchievementList(name='expanded_list', parent=self.card_container, align=Align.TOPRIGHT, controller=self.controller, top=47, padLeft=16) - @property def scroll_container_width(self): - if self.controller.is_checklist: - return ExpandedAchievementCard.default_width + ExpandedAchievementList.default_width + SCROLL_PADDING - else: - return ExpandedAchievementCard.default_width + SCROLL_PADDING + return ExpandedAchievementCard.default_width + SCROLL_PADDING @threadutils.highlander_threaded def update(self): diff --git a/achievement_system/client/ui/window/card/tooltip.py b/achievement_system/client/ui/window/card/tooltip.py @@ -6,42 +6,48 @@ from achievement_system.client.qa import is_qa from achievement_system.client.qa.actions import qa_complete_achievement, qa_progress_achievement, qa_reset_achievement, qa_show_hero_notification from achievement_system.client.ui.controller.achievement_entry import AchievementEntryController from achievement_system.client.ui.link.drag_data import AchievementDragData -from achievement_system.client.ui.window.card.components.expiry import AchievementExpiryTimerIcon +from achievement_system.client.ui.window.card.components.expiry import AchievementExpiryTimer from achievement_system.client.ui.window.card.components.icon import AchievementIcon -from achievement_system.client.ui.window.card.components.milestones import BarAchievementMilestones -from achievement_system.client.ui.window.card.expanded_card import AchievementRewards -from achievement_system.client.ui.window.card.components.labels import CompactAchievementLabels +from achievement_system.client.ui.window.card.components.milestones import AchievementMilestonesHover +from achievement_system.client.ui.window.card.components.labels import HoverAchievementLabels from achievement_system.client.ui.window.card.components.pin_button import CompactPinButton +from achievement_system.client.ui.window.card.components.progress import AchievementProgressHover +from achievement_system.client.ui.window.card.components.rewards import AchievementRewardsHover from achievement_system.client.ui.window.card.components.track_button import CompactTrackButton -from achievement_system.client.ui.window.const import COMPACT_CARD_WIDTH, COMPACT_CARD_TOOLTIP_WIDTH, COMPACT_CARD_TOOLTIP_HEIGHT, TRANSITION_DURATION +from achievement_system.client.ui.window.const import COMPACT_CARD_WIDTH, COMPACT_CARD_TOOLTIP_WIDTH, TRANSITION_DURATION from achievement_system.client.ui.window.signal import on_achievement_selected -from carbonui import Align, TextColor, uiconst, Density +from carbonui import Align, Density, uiconst from carbonui.button.group import ButtonGroup, ButtonSizeMode from carbonui.control.contextMenu.menuData import MenuData from carbonui.control.contextMenu.menuUtil import ClearMenuLayer from carbonui.primitives.container import Container +from carbonui.primitives.containerAutoSize import ContainerAutoSize from carbonui.primitives.sprite import Sprite +from carbonui.primitives.stretchspritevertical import StretchSpriteVertical from carbonui.primitives.transform import Transform -from carbonui.text.styles import TextHeader from carbonui.uianimations import animations from carbonui.uicore import uicore from carbonui.util.dpi import ScaleDpi from eve.client.script.ui import eveColor -from eve.client.script.ui.control.gauge import Gauge +ANIMATION_INTRO_DURATION = 0.2 +ANIMATION_SEQUENCE_TOP = -16 +ANIMATION_SEQUENCE_DURATION = 0.2 +ANIMATION_SEQUENCE_INCREASE = 0.075 +CONTENT_SIDE_PADDING = 16 -class CompactAchievementCardTooltip(Container): +class CompactAchievementCardTooltip(ContainerAutoSize): default_width = COMPACT_CARD_TOOLTIP_WIDTH - default_height = COMPACT_CARD_TOOLTIP_HEIGHT default_align = Align.TOPLEFT + default_alignMode = Align.TOTOP default_opacity = 0.0 def __init__(self, anchor, controller, *args, **kwargs): super(CompactAchievementCardTooltip, self).__init__(*args, **kwargs) - self.track_button = None - self.expiry_container = None - self.labels = None self.anchor = anchor self.controller = controller + self.content_container = None + self.labels = None + self.animation_sequence_offset = 0.0 self.construct_layout() self.update() self.connect_signals() @@ -60,8 +66,11 @@ class CompactAchievementCardTooltip(Container): on_admin_achievement_reset.connect(self.on_achievement_reset) on_admin_achievement_reset_all.connect(self.on_achievement_reset_all) self.controller.on_selected_milestone_changed.connect(self.on_selected_milestone_changed) + self.on_size_changed.connect(self.on_size_changed_signal) if self.labels is not None: self.labels.on_name_click.connect(self.on_name_click) + if self.content_container is not None: + self.content_container.on_size_changed.connect(self.on_content_size_changed_signal) def disconnect_signals(self): on_achievement_completed.disconnect(self.on_achievement_completed) @@ -69,71 +78,64 @@ class CompactAchievementCardTooltip(Container): on_admin_achievement_reset.disconnect(self.on_achievement_reset) on_admin_achievement_reset_all.disconnect(self.on_achievement_reset_all) self.controller.on_selected_milestone_changed.disconnect(self.on_selected_milestone_changed) + self.on_size_changed.disconnect(self.on_size_changed_signal) if self.labels is not None: self.labels.on_name_click.disconnect(self.on_name_click) + if self.content_container is not None: + self.content_container.on_size_changed.disconnect(self.on_content_size_changed_signal) def construct_layout(self): self.construct_containers() self.construct_icon() self.construct_labels() - self.construct_button_container() self.construct_milestones() - self.construct_buttons() - self.construct_rewards() self.construct_progress() + self.construct_rewards() + self.construct_buttons() self.construct_expiry() self.construct_hover_area() def construct_containers(self): - side_padding = (self.default_width - COMPACT_CARD_WIDTH) * 0.5 - self.content_container = Container(name='content_container', parent=self, padding=(side_padding, + self.content_container = ContainerAutoSize(name='content_container', parent=self, align=Align.TOTOP, alignMode=Align.TOTOP, padding=(CONTENT_SIDE_PADDING, 8, - side_padding, - 8)) + CONTENT_SIDE_PADDING, + 22)) self.background_container = TooltipBackground(name='background_container', parent=self, controller=self.controller) def construct_icon(self): - self.icon_transform = Transform(name='icon_transform', parent=self.content_container, align=Align.CENTERTOP, scalingCenter=(0.5, 0.5), pos=(0, 28, 128, 128)) - self.icon = AchievementIcon(name='icon', parent=self.icon_transform, align=Align.CENTER, controller=self.controller) + self.icon_container = Container(name='icon_container', parent=self.content_container, align=Align.TOTOP, height=128, top=36) + self.icon = AchievementIcon(name='icon', parent=self.icon_container, align=Align.CENTER, controller=self.controller) def construct_labels(self): - self.labels = CompactAchievementLabels(name='labels', parent=self.content_container, align=Align.TOTOP, controller=self.controller, top=164) - - def construct_button_container(self): - self.button_container = Container(name='button_container', parent=self.content_container, align=Align.TOTOP, height=24, top=-50, opacity=0.0) + self.labels = HoverAchievementLabels(name='labels', parent=self.content_container, align=Align.TOTOP, controller=self.controller, padding=(self.compact_padding, + 8, + self.compact_padding, + 0)) def construct_milestones(self): if not self.controller.has_multiple_milestones: return - BarAchievementMilestones(name='milestones', parent=self.button_container, align=Align.TOLEFT, controller=self.controller, padRight=16) + self.milestones = AchievementMilestonesHover(name='milestones', parent=self.content_container, align=Align.TOTOP, controller=self.controller, top=-50, padTop=8, opacity=0.0) - def construct_buttons(self): - button_group = ButtonGroup(name='button_group', parent=self.button_container, align=Align.TOTOP, density=Density.COMPACT, button_size_mode=ButtonSizeMode.STRETCH) - self.track_button = CompactTrackButton(name='track_button', parent=button_group, controller=self.controller) - CompactPinButton(name='pin_button', parent=button_group, controller=self.controller) + def construct_progress(self): + self.progress = AchievementProgressHover(name='progress', parent=self.content_container, align=Align.TOTOP, controller=self.controller, top=ANIMATION_SEQUENCE_TOP, padTop=16, opacity=0.0) def construct_rewards(self): - self.rewards_container = Container(name='rewards_container', parent=self.content_container, align=Align.CENTERTOP, opacity=0.0, width=self.default_width - self.content_padding * 2, height=40, top=250) - self.rewards = AchievementRewards(name='rewards', parent=self.rewards_container, align=Align.TOTOP, controller=self.controller, display_label=False, use_small_score=True) + self.rewards = AchievementRewardsHover(name='rewards', parent=self.content_container, align=Align.TOTOP, controller=self.controller, top=ANIMATION_SEQUENCE_TOP, padTop=16, opacity=0.0) - def construct_progress(self): - self.progress_container = Container(name='progress_container', parent=self.content_container, align=Align.CENTERTOP, opacity=0.0, width=self.default_width - self.content_padding * 2, height=36, top=300) - label_container = Container(name='label_container', parent=self.progress_container, align=Align.TOTOP, height=28, padBottom=4) - self.progress_score_label = TextHeader(name='progress_score_label', parent=label_container, align=Align.CENTER, state=uiconst.UI_NORMAL, color=TextColor.HIGHLIGHT) - self.progress_bar = Gauge(name='progress_bar', parent=self.progress_container, align=Align.TOTOP, gaugeHeight=4) + def construct_buttons(self): + self.button_group = ButtonGroup(name='button_group', parent=self.content_container, align=Align.TOTOP, density=Density.COMPACT, button_size_mode=ButtonSizeMode.STRETCH, top=ANIMATION_SEQUENCE_TOP, padTop=16, opacity=0.0) + CompactTrackButton(name='track_button', parent=self.button_group, controller=self.controller) + CompactPinButton(name='pin_button', parent=self.button_group, controller=self.controller) def construct_expiry(self): if not self.controller.is_time_limited: return - self.expiry_container = Container(name='expiry_container', parent=self.content_container, align=Align.CENTERTOP, width=self.default_width - self.content_padding * 2, height=16, top=375, opacity=0.0) - AchievementExpiryTimerIcon(name='expiry_icon', parent=self.expiry_container, align=Align.CENTER, controller=self.controller) + self.expiry_container = Container(name='expiry_container', parent=self.content_container, align=Align.TOTOP, height=AchievementExpiryTimer.default_height, top=ANIMATION_SEQUENCE_TOP, padTop=16, opacity=0.0) + AchievementExpiryTimer(name='expiry_timer', parent=self.expiry_container, align=Align.CENTER, controller=self.controller, use_verbose_text=False) def construct_hover_area(self): - hover_area_height = 368 if self.controller.is_time_limited else 324 - self.hover_area = Container(name='hover_area', parent=self.content_container, align=Align.CENTERTOP, state=uiconst.UI_NORMAL, pos=(0, - 28, - 224, - hover_area_height), bgColor=(0.0, 1.0, 0.0, 1.0), opacity=0.0) + self.hover_area = Container(name='hover_area', parent=self.content_container, align=Align.CENTER, state=uiconst.UI_NORMAL, opacity=0.0) self.hover_area.OnClick = self.on_hover_area_click self.hover_area.MakeDragObject() self.hover_area.GetDragData = lambda : AchievementDragData(self.controller.achievement_entry.identifier) @@ -164,6 +166,14 @@ class CompactAchievementCardTooltip(Container): def on_name_click(self, *args): self.on_hover_area_click() + def on_size_changed_signal(self, width, height): + self.background_container.width = width + self.background_container.height = height + + def on_content_size_changed_signal(self, width, height): + self.hover_area.width = width + self.hover_area.height = height + @threadutils.highlander_threaded def update(self): self.background_container.update() @@ -175,26 +185,24 @@ class CompactAchievementCardTooltip(Container): self.animate_in() def update_progress(self): - self.progress_score_label.text = self.controller.progress_score_text_for_selected_milestone - self.progress_score_label.hint = self.controller.progress_score_hint_for_current_milestone - self.progress_bar.SetColor(self.controller.progress_bar_color) - self.progress_bar.SetValue(self.controller.percent_progress_towards_selected_milestone, animate=False) + self.progress.update() def animate_in(self): self.opacity = 1.0 - animations.MorphVector2(obj=self.icon_transform, attrName='scale', startVal=self.icon_transform.scale, endVal=(0.75, 0.75), duration=TRANSITION_DURATION) - animations.MorphScalar(obj=self.icon_transform, attrName='top', startVal=self.icon_transform.top, endVal=-4, duration=TRANSITION_DURATION) - animations.MorphScalar(obj=self.labels, attrName='top', startVal=self.labels.top, endVal=120, duration=TRANSITION_DURATION) - animations.FadeIn(self.button_container, duration=TRANSITION_DURATION) - animations.MorphScalar(obj=self.button_container, attrName='top', startVal=self.button_container.top, endVal=12, duration=TRANSITION_DURATION) - animations.FadeIn(self.rewards_container, duration=TRANSITION_DURATION) - animations.MorphScalar(obj=self.rewards_container, attrName='top', startVal=self.rewards_container.top, endVal=276, duration=TRANSITION_DURATION) - animations.FadeIn(self.progress_container, duration=TRANSITION_DURATION) - animations.MorphScalar(obj=self.progress_container, attrName='top', startVal=self.progress_container.top, endVal=328, duration=TRANSITION_DURATION) - if self.expiry_container is not None: - animations.FadeIn(self.expiry_container, duration=TRANSITION_DURATION) - animations.MorphScalar(obj=self.expiry_container, attrName='top', startVal=self.expiry_container.top, endVal=380, duration=TRANSITION_DURATION) - self.labels.animate_in() + animations.MorphScalar(obj=self.icon_container, attrName='top', startVal=self.icon_container.top, endVal=16, duration=ANIMATION_INTRO_DURATION) + self.labels.animate_in(duration=ANIMATION_INTRO_DURATION) + if self.controller.has_multiple_milestones: + self.animate_sequence_component(self.milestones) + self.animate_sequence_component(self.progress) + self.animate_sequence_component(self.rewards) + self.animate_sequence_component(self.button_group) + if self.controller.is_time_limited: + self.animate_sequence_component(self.expiry_container) + + def animate_sequence_component(self, component): + animations.FadeIn(obj=component, duration=ANIMATION_SEQUENCE_DURATION, timeOffset=self.animation_sequence_offset) + animations.MorphScalar(obj=component, attrName='top', startVal=component.top, endVal=0, duration=ANIMATION_SEQUENCE_DURATION, timeOffset=self.animation_sequence_offset) + self.animation_sequence_offset += ANIMATION_SEQUENCE_INCREASE @threadutils.highlander_threaded def poll_async(self): @@ -223,15 +231,15 @@ class CompactAchievementCardTooltip(Container): return is_inside_x and is_inside_y @property - def content_padding(self): - return 8 + (self.default_width - COMPACT_CARD_WIDTH) * 0.5 + def compact_padding(self): + return (self.default_width - COMPACT_CARD_WIDTH) * 0.5 - CONTENT_SIDE_PADDING def SetPosition(self, left, top): anchor_left, anchor_top, anchor_width, anchor_height = self.anchor.GetAbsolute() center_left = anchor_left + anchor_width * 0.5 center_top = anchor_top + anchor_height * 0.5 self.left = center_left - self.width * 0.5 - self.top = center_top - 100 + self.top = center_top - 108 def GetMenu(self): menu_data = MenuData() @@ -244,9 +252,7 @@ class CompactAchievementCardTooltip(Container): class TooltipBackground(Transform): - default_width = COMPACT_CARD_TOOLTIP_WIDTH - default_height = COMPACT_CARD_TOOLTIP_HEIGHT - default_opacity = 0.0 + default_opacity = 1.0 default_scalingCenter = (0.5, 0.5) default_scale = (0.8, 0.8) @@ -255,24 +261,35 @@ class TooltipBackground(Transform): self.controller = controller self.construct_layout() self.update() + self.connect_signals() + + def Close(self): + try: + self.disconnect_signals() + finally: + super(TooltipBackground, self).Close() + + def connect_signals(self): + self.on_size_changed.connect(self.on_size_changed_signal) + + def disconnect_signals(self): + self.on_size_changed.disconnect(self.on_size_changed_signal) def construct_layout(self): - Sprite(parent=self, align=Align.CENTERTOP, state=uiconst.UI_DISABLED, texturePath='res:/UI/Texture/classes/Achievements/card_frame_beacon.png', pos=(-60, -21, 42, 42)) - Sprite(parent=self, align=Align.CENTERTOP, state=uiconst.UI_DISABLED, texturePath='res:/UI/Texture/classes/Achievements/card_frame_beacon.png', pos=(60, -21, -42, 42)) - decoration_container = Container(name='decoration_container', parent=self, align=Align.TOTOP, height=113, top=10) - Sprite(parent=decoration_container, align=Align.CENTER, state=uiconst.UI_DISABLED, texturePath='res:/UI/Texture/classes/Achievements/compact_card_side_decoration.png', pos=(-108, 0, 25, 113)) - Sprite(parent=decoration_container, align=Align.CENTER, state=uiconst.UI_DISABLED, texturePath='res:/UI/Texture/classes/Achievements/compact_card_side_decoration.png', pos=(108, 0, -25, 113)) - self.background_frame = Sprite(parent=self, align=Align.TOPLEFT, state=uiconst.UI_DISABLED, texturePath='res:/UI/Texture/classes/Achievements/card/tooltip_bg_frame.png', pos=(0, - 0, - COMPACT_CARD_TOOLTIP_WIDTH, - COMPACT_CARD_TOOLTIP_HEIGHT)) - Sprite(parent=self, align=Align.TOPLEFT, state=uiconst.UI_DISABLED, texturePath='res:/UI/Texture/classes/Achievements/card/tooltip_bg_fill.png', opacity=0.95, pos=(0, - 0, - COMPACT_CARD_TOOLTIP_WIDTH, - COMPACT_CARD_TOOLTIP_HEIGHT)) + Sprite(parent=self, align=Align.CENTERTOP, texturePath='res:/UI/Texture/classes/Achievements/card_frame_beacon.png', pos=(-114, 67, 42, 42)) + Sprite(parent=self, align=Align.CENTERTOP, texturePath='res:/UI/Texture/classes/Achievements/card_frame_beacon.png', pos=(114, 67, -42, 42)) + self.background_frame = StretchSpriteVertical(parent=self, texturePath='res:/UI/Texture/classes/Achievements/card/tooltip_bg_frame.png', topEdgeSize=114, bottomEdgeSize=26) + self.background_fill = StretchSpriteVertical(parent=self, texturePath='res:/UI/Texture/classes/Achievements/card/tooltip_bg_fill.png', topEdgeSize=114, bottomEdgeSize=26) @threadutils.highlander_threaded def update(self): self.background_frame.color = eveColor.SUCCESS_GREEN if self.controller.is_completed else eveColor.WHITE - animations.FadeIn(self, duration=TRANSITION_DURATION * 0.5) - animations.MorphVector2(obj=self, attrName='scale', startVal=self.scale, endVal=(1.0, 1.0), duration=TRANSITION_DURATION * 0.5) + duration = TRANSITION_DURATION * 0.5 + animations.FadeIn(self, duration=duration) + animations.MorphVector2(obj=self, attrName='scale', startVal=self.scale, endVal=(1.0, 1.0), duration=duration) + + def on_size_changed_signal(self, width, height): + self.background_frame.width = width + self.background_frame.height = height + self.background_fill.width = width + self.background_fill.height = height diff --git a/achievement_system/client/ui/window/const.py b/achievement_system/client/ui/window/const.py @@ -7,8 +7,7 @@ from metadata.common.content_tags import ContentTags from parameter_types.const import ParameterType COMPACT_CARD_WIDTH = 222 COMPACT_CARD_HEIGHT = 276 -COMPACT_CARD_TOOLTIP_WIDTH = 294 -COMPACT_CARD_TOOLTIP_HEIGHT = 450 +COMPACT_CARD_TOOLTIP_WIDTH = 280 DEFAULT_CONTENT_TAG_ICON = 'res:/UI/Texture/classes/Achievements/tag_icons/activity_tag_default.png' ICON_BY_CONTENT_TAG = {ContentTags.activity_combat: DEFAULT_CONTENT_TAG_ICON, ContentTags.activity_donation: DEFAULT_CONTENT_TAG_ICON, @@ -43,7 +42,6 @@ def get_content_tag_icon(content_tags): @Enum class NavigationEntryID(object): - ACHIEVEMENTS = 'achievements' ARCHIVED = 'archived' OVERVIEW = 'overview' diff --git a/achievement_system/client/ui/window/page/achievements/achievements_page.py b/achievement_system/client/ui/window/page/achievements/achievements_page.py @@ -45,27 +45,37 @@ class AchievementsPage(Container): self.split_view.on_expanded_changed.disconnect(self.side_navigation.on_expanded_changed) def construct_layout(self): + are_definitions_loading = get_repository().are_definitions_loading() + are_definitions_loaded = get_repository().are_definitions_loaded() self.split_view = SideNavigationSplitView(name='split_view', parent=self, is_always_expanded_setting=achievements_side_navigation_expanded, expanded_panel_width=240) - self.failure_container = AlertContainer(name='failure_container', parent=self.split_view.content, opacity=0.0 if get_repository().are_definitions_loaded() or get_repository().are_definitions_loading() else 1.0, align=Align.TOTOP_NOPUSH, title=GetByLabel('UI/Achievements/Window/FailureToLoadTitle'), title_color=TextColor.WARNING, description=GetByLabel('UI/Achievements/Window/FailureToLoadDescription'), button_icon=eveicon.refresh, button_label=GetByLabel('UI/Achievements/Window/FailureToLoadButton'), button_action=lambda *args: self._on_synchronize_clicked(), button_variant=ButtonVariant.GHOST, padding=(16, 16, 16, 16)) - self.loading_sprite = LoadingWheel(parent=self.split_view.content, align=uiconst.CENTER, opacity=1.0 if get_repository().are_definitions_loading() else 0.0) - self.content_container = Container(name='content_container', parent=self.split_view.content, opacity=1.0 if get_repository().are_definitions_loaded() else 0.0, padding=(16, 16, 16, 0)) + self.failure_container = AlertContainer(name='failure_container', parent=self.split_view.content, state=uiconst.UI_DISABLED if are_definitions_loaded or are_definitions_loading else AlertContainer.default_state, opacity=0.0 if are_definitions_loaded or are_definitions_loading else 1.0, align=Align.TOTOP_NOPUSH, title=GetByLabel('UI/Achievements/Window/FailureToLoadTitle'), title_color=TextColor.WARNING, description=GetByLabel('UI/Achievements/Window/FailureToLoadDescription'), button_icon=eveicon.refresh, button_label=GetByLabel('UI/Achievements/Window/FailureToLoadButton'), button_action=lambda *args: self._on_synchronize_clicked(), button_variant=ButtonVariant.GHOST, padding=(16, 16, 16, 16)) + self.loading_sprite = LoadingWheel(parent=self.split_view.content, align=uiconst.CENTER, opacity=1.0 if are_definitions_loading else 0.0) + self.content_container = Container(name='content_container', parent=self.split_view.content, opacity=1.0 if are_definitions_loaded else 0.0, padding=(16, 16, 16, 0)) self.side_navigation = AchievementsNavigation(name='side_navigation', parent=self.split_view.panel, is_always_expanded_setting=achievements_side_navigation_expanded, is_expanded_func=self.split_view.is_expanded, expand_func=self.split_view.expand_panel) def _on_synchronize_clicked(self): animations.FadeIn(self.loading_sprite) - animations.FadeOut(self.failure_container) + self.hide_failure_container() get_repository().reload_definitions() def _on_definitions_loaded(self): animations.FadeOut(self.loading_sprite) if get_repository().are_definitions_loaded(): - animations.FadeOut(self.failure_container) + self.hide_failure_container() animations.FadeIn(self.content_container) else: - animations.FadeIn(self.failure_container) + self.show_failure_container() animations.FadeOut(self.content_container) self.side_navigation.reload() + def show_failure_container(self): + animations.FadeIn(self.failure_container) + self.failure_container.state = AlertContainer.default_state + + def hide_failure_container(self): + animations.FadeOut(self.failure_container) + self.failure_container.state = uiconst.UI_DISABLED + def on_category_selected(self, category_id): self.create_page(category_id) diff --git a/achievement_system/client/ui/window/page/achievements/navigation/const.py b/achievement_system/client/ui/window/page/achievements/navigation/const.py @@ -3,13 +3,11 @@ from achievement_system.client.api.repository import get_repository from achievement_system.client.model.definition.category.identifier import CategoryDefinitionIdentifier from achievement_system.client.model.definition.category.ui_annotations import CustomUiClassType from achievement_system.client.ui.window.const import NavigationEntryID -from achievement_system.client.ui.window.page.achievements.navigation.page.achievements import AchievementsPage from achievement_system.client.ui.window.page.achievements.navigation.page.archived import ArchivedPage from achievement_system.client.ui.window.page.achievements.navigation.page.category import CategoryPage from achievement_system.client.ui.window.page.achievements.navigation.page.category_campaigns import CustomCategoryPageMilitaryCampaigns from achievement_system.client.ui.window.page.achievements.navigation.page.overview import OverviewPage page_class_by_navigation_id = {NavigationEntryID.OVERVIEW: OverviewPage, - NavigationEntryID.ACHIEVEMENTS: AchievementsPage, NavigationEntryID.ARCHIVED: ArchivedPage} custom_category_page_class_by_type = {CustomUiClassType.MILITARY_CAMPAIGNS: CustomCategoryPageMilitaryCampaigns} diff --git a/achievement_system/client/ui/window/page/achievements/navigation/page/achievements.py b/achievement_system/client/ui/window/page/achievements/navigation/page/achievements.py @@ -1,79 +0,0 @@ -#Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\achievement_system\client\ui\window\page\achievements\navigation\page\achievements.py -import logging -from achievement_system.client.api.error import DefinitionNotFoundError -from achievement_system.client.api.repository import get_repository -from achievement_system.client.model.definition.category.roots import AchievementCategoryRoot -from achievement_system.client.ui.controller.achievement_entry import AchievementEntryController -from achievement_system.client.ui.window.card.compact_card import CompactAchievementCard -from achievement_system.common.const import LOGGER_NAME -from carbonui import Align, TextColor -from carbonui.control.scrollContainer import ScrollContainer -from carbonui.primitives.container import Container -from carbonui.primitives.flowcontainer import FlowContainer -from carbonui.text.styles import TextHeader, TextBody -from eve.client.script.ui.control.loadingContainer import LoadingContainer -from localization import GetByLabel -logger = logging.getLogger(LOGGER_NAME) - -class AchievementsPage(Container): - - def __init__(self, *args, **kwargs): - super(AchievementsPage, self).__init__(*args, **kwargs) - self._loading_thread = None - self.construct_layout() - self.load_card_data() - - def Close(self): - try: - self.kill_loading_thread() - finally: - super(AchievementsPage, self).Close() - - def kill_loading_thread(self): - if self._loading_thread is not None: - self._loading_thread.kill() - self._loading_thread = None - - def construct_layout(self): - self.construct_name() - self.construct_description() - self.construct_loading_container() - self.construct_card_grid() - - def construct_name(self): - name_container = Container(name='name_container', parent=self, align=Align.TOTOP, height=38) - self.name_label = TextHeader(name='name_label', parent=name_container, align=Align.TOLEFT, text='Achievements') - - def construct_description(self): - description_container = Container(name='description_container', parent=self, align=Align.TOTOP, height=27, padTop=-16) - self.description_label = TextBody(name='description_label', parent=description_container, align=Align.TOLEFT, text='Achievements track your progress and reward your dedication.') - - def construct_loading_container(self): - self.loading_container = LoadingContainer(parent=self, failureStateMessage=GetByLabel('UI/Achievements/Error/InternalError'), failureStateMessageColor=TextColor.NORMAL, retryBtnLabel=GetByLabel('UI/Achievements/Error/RetryButton'), errorLoggingEnabled=False) - - def construct_card_grid(self): - scroll_container = ScrollContainer(name='scroll_container', parent=self.loading_container) - self.card_grid = FlowContainer(name='card_grid', parent=scroll_container, align=Align.TOTOP, contentSpacing=(32, 16)) - - def load_card_data(self): - self.loading_container.LoadContent(loadCallback=self.load_card_data_async) - - def load_card_data_async(self): - self.populate_card_grid() - - def populate_card_grid(self): - self.card_grid.Flush() - entries = self.achievement_entries - for entry in entries: - CompactAchievementCard(parent=self.card_grid, controller=AchievementEntryController(entry)) - - @property - def achievement_entries(self): - try: - definitions = get_repository().definitions - category_identifier = definitions.get_root_category(AchievementCategoryRoot.CHALLENGES) - logger.info('Retrieving attributes for root category %s' % AchievementCategoryRoot.CHALLENGES) - return definitions.get_achievement_entries_recursive(category_identifier) - except DefinitionNotFoundError as e: - logger.exception(e.message) - raise e diff --git a/achievement_system/client/ui/window/page/rewards/entry.py b/achievement_system/client/ui/window/page/rewards/entry.py @@ -6,6 +6,7 @@ import gametime import math import threadutils import uthread2 +from achievement_system.client.model.definition.reward.type import RewardType from carbonui import Align, ButtonStyle, Density, PickState, TextColor, uiconst from carbonui.control.button import Button from carbonui.primitives.container import Container @@ -18,14 +19,17 @@ from carbonui.util.color import Color from eve.client.script.ui import eveColor from eve.client.script.ui.control.gauge import Gauge from eve.client.script.ui.control.tooltips import TooltipPanel +from eveicon import IconData from eveui.animation.curve import CurveType from localization import GetByLabel +from menucheckers import SessionChecker GLOW_IDLE = 0.5 GLOW_HOVER = 1.0 OPACITY_IDLE = 0.1 OPACITY_HOVER = 0.2 FLAIR_SIZE = 300 DEFAULT_FLAIR_TEXTURE = 'res:/UI/Texture/Shared/CareerPaths/unclassified_flair.png' +REWARD_WIDTH_RATIO = 0.45 class RewardClaimButton(Button): default_display = True @@ -195,7 +199,7 @@ class AchievementRewardEntry(Container): self.flair_cont = Container(name='flairCont', parent=self, pickState=PickState.OFF, clipChildren=True) def construct_right_wrapper(self): - self._right_wrapper = Container(name='right_wrapper', parent=self.content, align=Align.TORIGHT_PROP, width=0.36) + self._right_wrapper = Container(name='right_wrapper', parent=self.content, align=Align.TORIGHT_PROP, width=REWARD_WIDTH_RATIO) def construct_left_layout(self): self.left_container_outer = Container(name='left_container_outer', parent=self.content, align=Align.TOALL, clipChildren=True) @@ -224,12 +228,13 @@ class AchievementRewardEntry(Container): self.right_container = Container(name='right_container', parent=self._right_wrapper, align=Align.TOALL, padLeft=16, padRight=16) def construct_right_side(self): - cta_cont = ContainerAutoSize(name='cta_cont', parent=self.right_container, align=Align.TORIGHT, padLeft=4) + cta_cont = ContainerAutoSize(name='cta_cont', parent=self.right_container, align=Align.TORIGHT, padLeft=8) self._claim_button = RewardClaimButton(name='claim_button', parent=cta_cont, align=Align.CENTERLEFT, density=Density.COMPACT, func=lambda *_: self._on_claim(entry=self)) self._claim_button.set_claimable() if self._expiration_time is not None: ExpirationIcon(name='expiration_icon', parent=self.right_container, align=Align.TORIGHT, expiration_time=self._expiration_time, padLeft=4) self.right_content_container = Container(name='right_content_container', parent=self.right_container, align=Align.TOALL, clipChildren=True) + self.rewards_container = ContainerAutoSize(name='rewards_container', parent=self.right_content_container, align=Align.TOLEFT) def construct_underlay(self): Frame(bgParent=self, texturePath='res:/UI/Texture/classes/Opportunities/card_mask.png', cornerSize=16, color=(0, 0, 0, 0.9)) @@ -250,9 +255,22 @@ class AchievementRewardEntry(Container): self.update_gauge(animate=False) def update_rewards(self): - self.right_content_container.Flush() - for reward in self.controller.reward_data: + self.rewards_container.Flush() + reward_data = self.controller.reward_data + has_multiple_rewards = len(reward_data) > 1 + has_item_reward = False + for reward in reward_data: self.add_reward(reward) + if reward.is_item: + has_item_reward = True + + if has_multiple_rewards or has_item_reward: + self.rewards_container.state = uiconst.UI_NORMAL + self.rewards_container.LoadTooltipPanel = lambda tooltipPanel, *args: RewardsTooltip(tooltipPanel=tooltipPanel, reward_data=reward_data) + if has_item_reward: + self._claim_button.GetHint = self.claim_button_item_hint + else: + self._claim_button.GetHint = lambda : None def update_gauge(self, animate = True): color = eveColor.SUCCESS_GREEN if self._progress >= 1.0 else eveColor.CRYO_BLUE @@ -262,9 +280,15 @@ class AchievementRewardEntry(Container): self._gauge_label.color = color def add_reward(self, reward): - cont = ContainerAutoSize(parent=self.right_content_container, align=Align.TOLEFT, state=uiconst.UI_NORMAL if reward.hint else uiconst.UI_PICKCHILDREN, hint=reward.hint, padRight=8) + cont = ContainerAutoSize(parent=self.rewards_container, align=Align.TOLEFT, padRight=8) Sprite(parent=cont, align=Align.CENTERLEFT, state=uiconst.UI_DISABLED, pos=(0, 0, 16, 16), texturePath=reward.icon) - self.reward_label = TextBody(parent=cont, align=Align.CENTERLEFT, state=uiconst.UI_NORMAL if reward.is_item else uiconst.UI_PICKCHILDREN, left=20, maxLines=1, autoFadeSides=16, text=reward.text, color=TextColor.NORMAL) + self.reward_label = TextBody(parent=cont, align=Align.CENTERLEFT, state=uiconst.UI_DISABLED if reward.is_item else uiconst.UI_PICKCHILDREN, left=20, maxLines=1, autoFadeSides=16, text=reward.hint if reward.is_title else reward.text, color=TextColor.NORMAL) + + def claim_button_item_hint(self): + if SessionChecker(session, sm).IsPilotDocked(): + return GetByLabel('UI/Achievements/Window/Rewards/ClaimItemHintDocked') + else: + return GetByLabel('UI/Achievements/Window/Rewards/ClaimItemHintUndocked') def OnMouseEnter(self, *args): eveui.Sound.entry_hover.play() @@ -278,3 +302,20 @@ class AchievementRewardEntry(Container): eveui.animate(self._left_line, 'glowBrightness', GLOW_IDLE, duration=0.2) eveui.animate(self._bg_flair, 'glowBrightness', 0.0, duration=0.2) eveui.animate(self._bg_flair, 'rotation', end_value=self._bg_flair.rotation + 0.025, duration=0.2) + + +def RewardsTooltip(tooltipPanel, reward_data): + tooltipPanel.LoadStandardSpacing() + tooltipPanel.columns = 2 + for reward in reward_data: + label_text = reward.hint + if label_text is None: + continue + if isinstance(reward.icon, IconData): + icon = reward.icon.resolve(16) + else: + icon = reward.icon + _, labelObj = tooltipPanel.AddIconLabel(icon=icon, iconSize=20 if reward.reward_type == RewardType.SP else 16, label=label_text) + if reward.is_item: + tooltipPanel.state = uiconst.UI_NORMAL + labelObj.state = uiconst.UI_NORMAL diff --git a/achievement_system/client/ui/window/page/rewards/info_container.py b/achievement_system/client/ui/window/page/rewards/info_container.py @@ -0,0 +1,64 @@ +#Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\achievement_system\client\ui\window\page\rewards\info_container.py +import threadutils +from carbonui import Align, Density, uiconst +from carbonui.control.button import Button +from carbonui.primitives.container import Container +from carbonui.primitives.containerAutoSize import ContainerAutoSize +from carbonui.primitives.frame import Frame +from carbonui.primitives.sprite import Sprite +from carbonui.text.styles import TextBody +from eve.client.script.ui import eveThemeColor, eveColor +from eve.client.script.ui.shared.neocom.characterSheetWindow import CharacterSheetWindow +from localization import GetByLabel + +class InfoContainer(Container): + + def __init__(self, text, *args, **kwargs): + super(InfoContainer, self).__init__(*args, **kwargs) + self.text = text + self.construct_layout() + self.update() + + def construct_layout(self): + content_container = Container(name='content_container', parent=self, align=Align.VERTICALLY_CENTERED, height=16) + icon_container = Container(name='icon_container', parent=content_container, align=Align.TOLEFT, pos=(0, 0, 16, 16), padLeft=8) + self.icon_circle = Sprite(name='icon_circle', parent=icon_container, align=Align.CENTER, texturePath='res:/UI/Texture/classes/Achievements/info_container/info_icon_circle.png', outputMode=uiconst.OUTPUT_COLOR_AND_GLOW, pos=(0, 0, 16, 16)) + Sprite(name='icon_symbol', parent=icon_container, align=Align.CENTER, texturePath='res:/UI/Texture/classes/Achievements/info_container/info_icon_symbol.png', pos=(0, 0, 2, 6)) + button_container = ContainerAutoSize(name='button_container', parent=content_container, align=Align.TORIGHT, height=24, padding=(8, 0, 8, 0)) + Button(name='character_sheet_button', parent=button_container, align=Align.VERTICALLY_CENTERED, label=GetByLabel('UI/Achievements/Window/Rewards/OpenCharacterSheet'), density=Density.COMPACT, func=self.open_character_sheet) + self.label_container = Container(name='label_container', parent=content_container, align=Align.VERTICALLY_CENTERED, padLeft=8) + self.label = TextBody(name='label', parent=self.label_container, align=Align.TOLEFT, shadowColor=eveColor.BLACK, maxLines=1, autoFadeSides=16) + self.corner = Sprite(name='corner', parent=self, align=Align.TOPLEFT, texturePath='res:/UI/Texture/classes/Achievements/info_container/info_corner.png', pos=(0, 0, 8, 8)) + self.frame = Frame(name='frame', parent=self, texturePath='res:/UI/Texture/classes/Achievements/info_container/info_frame.png', cornerSize=13) + + @threadutils.highlander_threaded + def update(self): + self.update_background() + self.update_icon() + self.update_label() + + def update_background(self): + self.corner.color = eveThemeColor.THEME_FOCUS + self.frame.color = eveThemeColor.THEME_FOCUSDARK + self.frame.opacity = 0.6 + + def update_icon(self): + self.icon_circle.color = eveThemeColor.THEME_FOCUS + self.icon_circle.glowBrightness = 0.5 + + def update_label(self): + self.label.text = self.text + _, h = TextBody.MeasureTextSize(self.text, maxLines=1) + self.label_container.height = h + + @threadutils.highlander_threaded + def open_character_sheet(self, *args): + CharacterSheetWindow.OpenDecorationsToTitles() + + def OnColorThemeChanged(self): + super(InfoContainer, self).OnColorThemeChanged() + self.update() + + def OnGlobalFontSizeChanged(self): + super(InfoContainer, self).OnGlobalFontSizeChanged() + self.update() diff --git a/achievement_system/client/ui/window/page/rewards/rewards_page.py b/achievement_system/client/ui/window/page/rewards/rewards_page.py @@ -7,6 +7,7 @@ from achievement_system.client.api.signal import on_achievement_milestone_reward from achievement_system.client.ui.controller.reward import AchievementRewardController, CategoryRewardController from achievement_system.client.ui.window.const import WindowState, TRANSITION_DURATION from achievement_system.client.ui.window.page.rewards.entry import AchievementRewardEntry +from achievement_system.client.ui.window.page.rewards.info_container import InfoContainer from achievement_system.client.ui.window.signal import on_window_state_changed from carbonui import Align, uiconst, TextAlign from carbonui.control.scrollContainer import ScrollContainer @@ -39,7 +40,9 @@ class RewardsPage(Container): on_achievement_milestone_reward_claimed.connect(self.on_achievement_milestone_reward_claimed_signal) def construct_layout(self): - self.scroll_container = ScrollContainer(name='scroll_container', parent=self, padding=(8, 0, 8, 0)) + content_container = Container(name='content_container', parent=self, padding=(8, 0, 8, 0)) + self.info_container = InfoContainer(name='info_container', parent=content_container, align=Align.TOTOP, text=GetByLabel('UI/Achievements/Window/Rewards/ClaimedTitlesInfo'), height=32) + self.scroll_container = ScrollContainer(name='scroll_container', parent=content_container, padTop=16) @threadutils.highlander_threaded def update(self): diff --git a/behaviors/actions/combattargets.py b/behaviors/actions/combattargets.py @@ -540,7 +540,7 @@ class GetMyMinOptimalAndFalloff(Task): def _get_my_min_optimal_and_falloff(self): effect_optimal, effect_falloff = self._get_my_min_effect_range() weapon_optimal, weapon_falloff = self._get_my_min_weapon_range() - if not weapon_optimal or effect_optimal and effect_optimal < weapon_optimal: + if not weapon_optimal or effect_optimal and (effect_optimal < weapon_optimal or effect_optimal == weapon_optimal and effect_falloff < weapon_falloff): logger.debug('Behavior=%s for entity_type=%s setting min optimal=%s and falloff=%s from combat effect', self.behaviorTree.GetBehaviorId(), self.context.mySlimItem.typeID, effect_optimal, effect_falloff) return (effect_optimal, effect_falloff) logger.debug('Behavior=%s for entity_type=%s setting min optimal=%s and falloff=%s from weapons', self.behaviorTree.GetBehaviorId(), self.context.mySlimItem.typeID, weapon_optimal, weapon_falloff) @@ -556,7 +556,7 @@ class GetMyMinOptimalAndFalloff(Task): if effect_optimal == 0.0: logger.error('Badly authored effect: %s for behavior NPC range picks - no range assigned to it.', effect_id) continue - if effect_optimal < minimum_optimal or minimum_optimal == 0.0: + if minimum_optimal == 0.0 or effect_optimal < minimum_optimal or effect_optimal == minimum_optimal and effect_falloff < minimum_falloff: minimum_optimal = effect_optimal minimum_falloff = effect_falloff diff --git a/behaviors/entity.py b/behaviors/entity.py @@ -15,6 +15,7 @@ from ballpark.const import DESTINY_MODE_WARP from eveexceptions import UserError from inventorycommon.const import ownerNone from inventorycommon.util import IsNPC +from dogma import const as dogmaConst from spacecomponents.common.helper import HasCargoBayComponent logger = logging.getLogger(__name__) INVULNERABLE_LABEL = 'BehaviorWarp' @@ -53,12 +54,13 @@ class BehaviorEntity(EntityWrapper): if self.mode == DESTINY_MODE_WARP: raise NPCWarpError('Already Warping') destination = self.ballpark.AdjustDstByJitter(destination, jitterRadius) - if IsBallIntersectingAnyWarpDisruptionField(self.ballpark, self.id): - raise NpcWarpBubbledError('Warp bubble disruptor') - try: - destination = self.ballpark.ApplyWarpDisruptors(self.id, self.GetPosition(), destination, warpAtRange) - except UserError: - raise NpcWarpPathBubbledError('Warp path too short due to bubble disruptor') + if not self.ballpark.dogmaLM.GetAttributeValue(self.id, dogmaConst.attributeWarpBubbleImmune): + if IsBallIntersectingAnyWarpDisruptionField(self.ballpark, self.id): + raise NpcWarpBubbledError('Warp bubble disruptor') + try: + destination = self.ballpark.ApplyWarpDisruptors(self.id, self.GetPosition(), destination, warpAtRange) + except UserError: + raise NpcWarpPathBubbledError('Warp path too short due to bubble disruptor') self.ballpark.bubbleKeepAliveController.add_bubble_keep_alive_ball_at_coordinates(self.id, destination) self.ballpark.EntityWarpStart(self.id, pos=destination, makeItReal=True, notWarpingException=NPCWarpError, minRange=warpAtRange, warpSpeed=warpSpeed) diff --git a/carbon/common/lib/whitelist.py b/carbon/common/lib/whitelist.py @@ -3,7 +3,7 @@ import exceptions import blue from eveprefs import boot whitelist = '\n blue.DBRowDescriptor\n blue.DBRow\n\n eveexceptions.SQLError\n eveexceptions.UserError\n eveexceptions.CancelSessionChange\n eveexceptions.UnmarshalError\n eveexceptions.ConnectionError\n eveexceptions.ServiceNotFound\n \n stackless_response_router.exceptions.TimeoutException\n\n carbon.common.script.sys.crowset.CRowset\n carbon.common.script.sys.crowset.CIndexedRowset\n carbon.common.script.sys.crowset.CFilterRowset\n\n exceptions.AttributeError\n exceptions.IndexError\n exceptions.ValueError\n exceptions.KeyError\n exceptions.WindowsError\n exceptions.ReferenceError\n exceptions.RuntimeError\n exceptions.IOError\n\n exceptions.GPSException\n exceptions.GPSTransportClosed\n exceptions.GPSBadAddress\n exceptions.GPSAddressOccupied\n\n carbon.common.script.net.GPSExceptions.GPSException\n carbon.common.script.net.GPSExceptions.GPSTransportClosed\n carbon.common.script.net.GPSExceptions.GPSBadAddress\n carbon.common.script.net.GPSExceptions.GPSAddressOccupied\n\n carbon.common.script.net.machoNetExceptions.MachoException\n carbon.common.script.net.machoNetExceptions.MachoWrappedException\n carbon.common.script.net.machoNetExceptions.ProxyRedirect\n carbon.common.script.net.machoNetExceptions.UberMachoException\n carbon.common.script.net.machoNetExceptions.UnMachoDestination\n carbon.common.script.net.machoNetExceptions.UnMachoChannel\n carbon.common.script.net.machoNetExceptions.WrongMachoNode\n\n xmlrpclib.Fault\n\n carbon.common.script.net.machoNetPacket.CallReq\n carbon.common.script.net.machoNetPacket.CallRsp\n carbon.common.script.net.machoNetPacket.ErrorResponse\n carbon.common.script.net.machoNetPacket.IdentificationReq\n carbon.common.script.net.machoNetPacket.IdentificationRsp\n carbon.common.script.net.machoNetAddress.MachoAddress\n carbon.common.script.net.machoNetPacket.Notification\n carbon.common.script.net.machoNetPacket.PingReq\n carbon.common.script.net.machoNetPacket.PingRsp\n carbon.common.script.net.machoNetPacket.SessionChangeNotification\n carbon.common.script.net.machoNetPacket.SessionInitialStateNotification\n carbon.common.script.net.machoNetPacket.TransportClosed\n\n carbon.common.script.net.objectCaching.CacheOK\n carbon.common.script.net.objectCaching.CachedMethodCallResult\n carbon.common.script.net.objectCaching.CachedObject\n\n carbon.common.script.net.cachedObject.CachedObject\n utillib.KeyVal\n carbon.common.script.net.moniker.Moniker\n carbon.common.script.net.moniker.Moniker\n carbon.common.script.util.format.PasswordString\n carbon.common.script.sys.row.Row\n carbon.common.script.net.moniker.UpdateMoniker\n\n __builtin__.str\n __builtin__.unicode\n __builtin__.set\n\n collections.OrderedDict\n collections.defaultdict\n collections.deque\n\n localizationUtil.LocalizationSafeString\n\n eve.common.script.paperDoll.paperDollDefinitions.SculptingRow\n eve.common.script.paperDoll.paperDollDefinitions.ModifierRow\n eve.common.script.paperDoll.paperDollDefinitions.ColorSelectionRow\n eve.common.script.paperDoll.paperDollDefinitions.AppearanceRow\n\n machonethelpers.argchecker.ValidateArgTypeException\n \n\n fsd.schemas.loaders.objectLoader.ObjectLoader\n fsd.schemas.path.FsdDataPathObject\n fsd.schemas.binaryLoader.LoaderState\n fsd.schemas.loaders.dictLoader.DictLoader\n \n raffles.common.raffle.Raffle\n raffles.common.ticket.Ticket\n raffles.common.raffle_data.RaffleCreationData\n raffles.RafflesError\n raffles.RaffleNotFoundError\n raffles.TicketUnavailableError\n raffles.NotEnoughISKError\n raffles.FailureToDeliverItemError\n raffles.FetchError\n raffles.InventoryError\n raffles.CreateError\n raffles.PurchaseError\n \n kiring.common.errors.KiringRedeemingCodeException\n kiring.common.errors.KiringRedeemingCodeNotValidException\n kiring.common.errors.KiringRedeemingCodeUsedException\n kiring.common.errors.KiringRedeemingCodeTypeUsedException\n\n contracts.contractStruct.ContractStruct\n\n uuid.UUID\n' -whitelist += '\n foo.SlimItem\n\n eve.common.script.util.slimItem.SlimItem\n\n eve.common.script.sys.eveCfg.Standings\n\n eve.common.script.sys.rowset.RowDict\n eve.common.script.sys.rowset.RowList\n\n eve.common.script.sys.rowset.Rowset\n eve.common.script.sys.rowset.FilterRowset\n eve.common.script.sys.rowset.IndexRowset\n eve.common.script.sys.rowset.IndexedRows\n eve.common.script.sys.eveCfg.StackSize\n eve.common.script.sys.eveCfg.Singleton\n eve.common.script.util.pagedCollection.PagedResultSet\n\n dogma.exceptions.EmbarkOnlineError\n\n evewar.util.War\n eve.common.script.universe.locationWrapper.SolarSystemWrapper\n\n industry.job.Location\n industry.const.Error\n industry.const.Reference\n\n crimewatch.corp_aggression.settings.AggressionSettings\n\n shipskins.LicensedSkin\n\n eve.common.script.dogma.effect.BrainEffect\n dogma.attributes.Attribute\n dogma.attributes.SkillLevelAttribute\n dogma.attributes.ChargedAttribute\n dogma.attributes.HeatAttribute\n dogma.attributes.StackingNurfedAttribute\n dogma.attributes.LiteralAttribute\n dogma.attributes.BrainLiteralAttribute\n \n datetime.datetime\n datetime.date\n\n projectdiscovery.common.exceptions.NoActiveClassificationTaskError\n projectdiscovery.common.exceptions.UnexpectedMmosResultError\n projectdiscovery.common.exceptions.TooFewPolygonsMmosResultError\n projectdiscovery.common.exceptions.TooFewVerticesMmosResultError\n projectdiscovery.common.exceptions.NoConnectionToAPIError\n projectdiscovery.common.exceptions.MissingKeyError\n\n marketutil.BestByOrder\n marketutil.OrderAllData\n\n seasons.common.challenge.Challenge\n seasons.common.exceptions.ChallengeForCharacterNotFoundError\n seasons.common.exceptions.NotEnoughChallengeTypesAvailableError\n seasons.common.exceptions.ChallengeTypeNotFoundError\n \n explorationscanner.common.cosmicAnomalyInfo.CosmicAnomalyInfo\n explorationscanner.common.signatureInfo.SignatureInfo\n explorationscanner.common.structureInfo.StructureInfo\n explorationscanner.common.staticSiteInfo.StaticSiteInfo\n \n evedungeons.common.dungeonInfo.DungeonInfo\n\n agency.common.contentdata.CustomContentData\n \n fastcheckout.common.errors.FastCheckoutDisabled\n\n characterskills.common.character_skill_entry.CharacterSkillEntry\n \n npcs.npccorporations.CorporationTicker\n\n characterenergy.characterEnergyState.CharacterEnergyState\n characterenergy.characterEnergyState.InsufficientEnergyError\n solarsysteminterference.solarsystemInterferenceState.SolarsystemInterferenceState\n solarsysteminterference.solarsystemInterferenceState.ExcessInterferenceError\n \n structures.structureHangarViewState.StructureHangarViewState\n \n factionwarfare.occupationState.OccupationState\n factionwarfare.victoryPointState.VictoryPointState\n factionwarfare.advantageState.AdvantageState\n \n shipcosmetics.structs._modules._logo.ShipCosmeticLogo\n shipcosmetics.structs._fitting._group.ShipCosmeticFittingGroup\n shipcosmetics.structs._fitting._fitting.ShipCosmeticFitting\n shipcosmetics.structs._license._logo.ShipLogoLicense\n \n shipcaster.landingPadData.LandingPadData\n \n deathzone.targetTrackingState.TargetTrackingState\n\n pirateinsurgency.campaignClientSnapshot.CampaignClientSnapshot\n \n lpOffers.exceptions.TransfersDisabledError\n \n sovereignty.data_types.SovHubInfo\n sovereignty.data_types.SovClaimInfo\n\n dotWeapons.common.dotAppInfo.DotApplicationInfo\n\n evedungeons.common.instance_identifier.DungeonInstanceIdentifier\n' +whitelist += '\n foo.SlimItem\n\n eve.common.script.util.slimItem.SlimItem\n\n eve.common.script.sys.eveCfg.Standings\n\n eve.common.script.sys.rowset.RowDict\n eve.common.script.sys.rowset.RowList\n\n eve.common.script.sys.rowset.Rowset\n eve.common.script.sys.rowset.FilterRowset\n eve.common.script.sys.rowset.IndexRowset\n eve.common.script.sys.rowset.IndexedRows\n eve.common.script.sys.eveCfg.StackSize\n eve.common.script.sys.eveCfg.Singleton\n eve.common.script.util.pagedCollection.PagedResultSet\n\n dogma.exceptions.EmbarkOnlineError\n\n evewar.util.War\n eve.common.script.universe.locationWrapper.SolarSystemWrapper\n\n industry.job.Location\n industry.const.Error\n industry.const.Reference\n\n crimewatch.corp_aggression.settings.AggressionSettings\n\n shipskins.LicensedSkin\n\n eve.common.script.dogma.effect.BrainEffect\n dogma.attributes.Attribute\n dogma.attributes.SkillLevelAttribute\n dogma.attributes.ChargedAttribute\n dogma.attributes.HeatAttribute\n dogma.attributes.StackingNurfedAttribute\n dogma.attributes.LiteralAttribute\n dogma.attributes.BrainLiteralAttribute\n \n datetime.datetime\n datetime.date\n\n projectdiscovery.common.exceptions.NoActiveClassificationTaskError\n projectdiscovery.common.exceptions.UnexpectedMmosResultError\n projectdiscovery.common.exceptions.TooFewPolygonsMmosResultError\n projectdiscovery.common.exceptions.TooFewVerticesMmosResultError\n projectdiscovery.common.exceptions.NoConnectionToAPIError\n projectdiscovery.common.exceptions.MissingKeyError\n\n marketutil.BestByOrder\n marketutil.OrderAllData\n\n seasons.common.challenge.Challenge\n seasons.common.exceptions.ChallengeForCharacterNotFoundError\n seasons.common.exceptions.NotEnoughChallengeTypesAvailableError\n seasons.common.exceptions.ChallengeTypeNotFoundError\n \n explorationscanner.common.cosmicAnomalyInfo.CosmicAnomalyInfo\n explorationscanner.common.signatureInfo.SignatureInfo\n explorationscanner.common.structureInfo.StructureInfo\n explorationscanner.common.staticSiteInfo.StaticSiteInfo\n \n evedungeons.common.dungeonInfo.DungeonInfo\n\n agency.common.contentdata.CustomContentData\n \n fastcheckout.common.errors.FastCheckoutDisabled\n\n characterskills.common.character_skill_entry.CharacterSkillEntry\n \n npcs.npccorporations.CorporationTicker\n\n characterenergy.characterEnergyState.CharacterEnergyState\n characterenergy.characterEnergyState.InsufficientEnergyError\n solarsysteminterference.solarsystemInterferenceState.SolarsystemInterferenceState\n solarsysteminterference.solarsystemInterferenceState.ExcessInterferenceError\n \n structures.structureHangarViewState.StructureHangarViewState\n \n factionwarfare.occupationState.OccupationState\n factionwarfare.victoryPointState.VictoryPointState\n factionwarfare.advantageState.AdvantageState\n \n shipcosmetics.structs._modules._logo.ShipCosmeticLogo\n shipcosmetics.structs._fitting._group.ShipCosmeticFittingGroup\n shipcosmetics.structs._fitting._fitting.ShipCosmeticFitting\n shipcosmetics.structs._license._logo.ShipLogoLicense\n \n shipcaster.landingPadData.LandingPadData\n \n deathzone.targetTrackingState.TargetTrackingState\n\n pirateinsurgency.campaignClientSnapshot.CampaignClientSnapshot\n \n lpOffers.exceptions.TransfersDisabledError\n \n sovereignty.data_types.SovHubInfo\n sovereignty.data_types.SovClaimInfo\n\n dotWeapons.common.dotAppInfo.DotApplicationInfo\n\n evedungeons.common.instance_identifier.DungeonInstanceIdentifier\n jumpbridge.common.jump_bridge_authorized_info.JumpBridgeAuthorizedInfo\n' if boot.role == 'server': whitelist += '\n agent.StandardMissionDetails\n agent.HeraldryMissionDetails\n agent.ResearchMissionDetails\n agent.StorylineMissionDetails\n agent.EpicArcMissionDetails\n agent.OfferDetails\n agent.LoyaltyPoints\n agent.Agent\n agent.Credits\n agent.Item\n agent.Entity\n agent.Objective\n agent.FetchObjective\n agent.EncounterObjective\n agent.DungeonObjective\n agent.TransportObjective\n agent.AgentObjective\n agent.Reward\n agent.TimeBonusReward\n agent.MissionReferral\n agent.Location\n agent.ItemDeclarationError\n agent.ItemResolutionFailure\n agent.TransferItemFailure\n\n eve.server.script.mgt.npc.agents.services.standardMissionDetails.StandardMissionDetails\n eve.server.script.mgt.npc.agents.services.standardMissionDetails.HeraldryMissionDetails\n eve.server.script.mgt.npc.agents.services.standardMissionDetails.ResearchMissionDetails\n eve.server.script.mgt.npc.agents.services.standardMissionDetails.StorylineMissionDetails\n eve.server.script.mgt.npc.agents.services.standardMissionDetails.EpicArcMissionDetails\n eve.server.script.mgt.npc.agents.services.standardMissionDetails.OfferDetails\n eve.server.script.mgt.npc.agents.items.LoyaltyPoints\n eve.server.script.mgt.npc.agents.items.Agent\n eve.server.script.mgt.npc.agents.items.Credits\n eve.server.script.mgt.npc.agents.items.Item\n eve.server.script.mgt.npc.agents.items.Entity\n eve.server.script.mgt.npc.agents.items.Objective\n eve.server.script.mgt.npc.agents.items.FetchObjective\n eve.server.script.mgt.npc.agents.items.EncounterObjective\n eve.server.script.mgt.npc.agents.items.DungeonObjective\n eve.server.script.mgt.npc.agents.items.TransportObjective\n eve.server.script.mgt.npc.agents.items.AgentObjective\n eve.server.script.mgt.npc.agents.items.Reward\n eve.server.script.mgt.npc.agents.items.TimeBonusReward\n eve.server.script.mgt.npc.agents.items.MissionReferral\n eve.server.script.mgt.npc.agents.items.Location\n eve.server.script.mgt.npc.agents.exceptions.ItemDeclarationError\n eve.server.script.mgt.npc.agents.exceptions.ItemResolutionFailure\n eve.server.script.mgt.npc.agents.exceptions.TransferItemFailure\n\n sys.A\n sys.AgentString\n sys.AgentUnicode\n\n eve.common.script.sys.strangeStrings.A\n eve.common.script.sys.strangeStrings.AgentString\n eve.common.script.sys.strangeStrings.AgentUnicode\n\n scriber.hermes.Notification\n scriber.hermes.ReadStatus\n\n externalQueue.actions.ExternalActionException\n npcs.server.rewards.rewards.GroupRewardData\n npcs.server.rewards.rewards.DisqualificationData\n\n operations.common.const.RewardToken\n operations.common.const.SkillRewardToken \n\n raffles.server.PendingRaffle\n \n skills.server.exceptions.SkillBundleInjectionFailed\n skills.server.exceptions.MultiSkillBundleInjectForbidden\n \n evefitting.errors.FittingDoesNotExistError\n evefitting.errors.FittingIsNotValid\n \n externalQueue.utils.FilterGenerator\n \n behaviors.blackboards.scopes.Scope\n \n voidspace.server.content_manager.PlayerLocationInfo\n ballpark.gridallocationmanager.SolarSystemFullException\n ballpark.gridallocationmanager.GridAlreadyAllocatedError\n \n storylines.server.airnpe.AirNpeStartData\n \n nodegraph.server.atoms.atom_service.AtomNotFoundError\n nodegraph.server.atoms.atom_service.AtomRemoteMethodNotSupportedError \n \n shipcaster.launcherData.LauncherData\n \n lpOffers.exceptions.InsufficientBalanceError\n lpOffers.exceptions.MissingCorpRoleError\n lpOffers.exceptions.WrongCorporationMembershipError\n\n pirateinsurgency.server.campaignServerSnapshot.CampaignServerSnapshot\n \n assetholding.server.inventory.exceptions.HoldItemsFailed\n assetholding.server.inventory.exceptions.SpawnItemsFailed\n\n sovereignty.hub.server.errors.ItemCannotBeAddedToSovHubError\n sovereignty.skyhook.server.errors.CannotActivateError\n sovereignty.skyhook.server.errors.CannotAccessReagentsError\n \n spacecomponents.server.components.mercenaryDen.MercenaryDenNotFound\n spacecomponents.server.components.mercenaryDen.ValidateStartRequestFailed\n \n sovereignty.radius_dungeon_distribution.server.radius_dungeon_distribution_solarsystem.RadiusDungeonDistributionInstance\n evedungeons.server.scan_data.ScanData\n ' if boot.role == 'client': diff --git a/characterSettingsStorage/characterSettingsConsts.py b/characterSettingsStorage/characterSettingsConsts.py @@ -6,11 +6,6 @@ MAIL_SHOW_POPUP = 'mail_showNotification' MAIL_BLINK_TAB = 'mail_blinkTab' MAIL_GET_SEARCH_WND = 'mail_getSearchWnd' MAILS_PER_PAGE = 'mail_perPageNumber' -PERSONAL_AUTOPAYMENT = 'personalAutopayment' -JUMPBRIDGE_AUTOPAYMENT = 'jumpbridgeAutopayment' -JUMPBRIDGE_AUTOPAYMENT_CB = 'jumpbridgeAutopaymentCB' -JUMPBRIDGE_AUTOPAYMENT_VALUE = 'jumpbridgeAutopaymentValue' -PERSONAL_AUTOPAYMENTS_AVAILABLE = [JUMPBRIDGE_AUTOPAYMENT] UI_ELEMENTS_REVEALED = 'uiElementsRevealed' PREVENT_UI_HIDING = 'preventUiHiding' DISABLE_EMERGENCY_WARP = 'emergencyWarpDisabled' diff --git a/dogma/const.py b/dogma/const.py @@ -1415,6 +1415,7 @@ attributeMaxDirectionalScanRange = 5796 attributeOreBasicType = 2711 attributeAsteroidMetaLevel = 2699 attributePhaseStabilizerConnected = 6042 +attributeBaseJumpBridgeCapacitorCost = 6364 subsystemBonusAmarrElectronic = 1507 subsystemBonusGallenteElectronic = 1517 subsystemBonusCaldariElectronic = 1516 diff --git a/eve/client/script/ui/control/infoIcon.py b/eve/client/script/ui/control/infoIcon.py @@ -134,6 +134,7 @@ class GlyphIcon(Container): self.glyphTexture = attributes.get('glyphTexture', self.default_glyphTexture) self.frameColor = attributes.get('frameColor', self.default_frameColor) self.glyphColor = attributes.get('glyphColor', self.default_glyphColor) + self.glowAmount = attributes.get('glowAmount', self.default_glowAmount) self.func = attributes.get('func', None) self.ConstructLayout() @@ -142,6 +143,8 @@ class GlyphIcon(Container): 0, self.height, self.width), glowAmount=self.default_glowAmount) + if not self.glyphTexture: + return self.glyph = Sprite(name='glyph', parent=self, align=uiconst.CENTER, state=uiconst.UI_DISABLED, texturePath=self.glyphTexture, color=self.glyphColor, pos=(0, 0, self.height, diff --git a/eve/client/script/ui/control/tooltips.py b/eve/client/script/ui/control/tooltips.py @@ -348,18 +348,18 @@ class TooltipPanel(PointerPanel): self.AddCell(mainContainer, **keywords) return (sprite, label) - def AddIconLabel(self, icon, label, iconSize = 32, padBottom = 0): + def AddIconLabel(self, icon, label, iconSize = 32, padBottom = 0, bold = True, iconColor = Sprite.default_color): self.FillRow() iconObj = Sprite(pos=(0, 0, iconSize, - iconSize), align=uiconst.CENTERLEFT) + iconSize), align=uiconst.CENTERLEFT, color=iconColor) iconObj.LoadIcon(icon, ignoreSize=True) self.AddCell(iconObj, cellPadding=(-3, 0, 7, padBottom)) - labelObj = self.AddLabelMedium(text=label, align=uiconst.CENTERLEFT, bold=True, cellPadding=(0, + labelObj = self.AddLabelMedium(text=label, align=uiconst.CENTERLEFT, bold=bold, cellPadding=(0, 0, 7, padBottom)) diff --git a/eve/client/script/ui/control/typeList/link.py b/eve/client/script/ui/control/typeList/link.py @@ -7,10 +7,12 @@ CATEGORY_ID_SCHEME = 'categoryIdLink' def _parse_url(url): _, args = url.split(':') try: - _id, header_text = args.split('//', 1) + _id, header_text, window_caption = args.split('//', 2) if header_text == 'None': header_text = None - return (int(_id), header_text) + if window_caption == 'None': + window_caption = None + return (int(_id), header_text, window_caption) except ValueError: return (None, None) @@ -19,14 +21,14 @@ def register_type_list_link_handlers(registry): registry.register(scheme=TYPE_LIST_SCHEME, handler=handle_type_list_link, color_info=default_with_subtle_color_info) -def format_type_list_url(type_list_id, header_text = None): - return u'{}:{}//{}'.format(TYPE_LIST_SCHEME, type_list_id, header_text) +def format_type_list_url(type_list_id, header_text = None, window_caption = None): + return u'{}:{}//{}//{}'.format(TYPE_LIST_SCHEME, type_list_id, header_text, window_caption) def handle_type_list_link(url): from eve.client.script.ui.control.typeList.type_list_window import TypeListWindow - type_list_id, header_text = _parse_url(url) - TypeListWindow.OpenTypeList(type_list_id, header_text=header_text) + type_list_id, header_text, window_caption = _parse_url(url) + TypeListWindow.OpenTypeList(type_list_id, header_text=header_text, window_caption=window_caption) def register_group_id_link_handlers(registry): diff --git a/eve/client/script/ui/services/menusvc.py b/eve/client/script/ui/services/menusvc.py @@ -6,6 +6,7 @@ import eveformat import eveicon import utillib from eve.devtools.script import devtools_util +from jumpbridge.client.jumpBridge import GetJumpBridgeComponent from player_messaging.client.ui_message import prompt_player_fsd_dialog import webbrowser from stargate.client.localGates import FindLocalStargate, FindLocalJumpGateForDestinationPath @@ -2106,6 +2107,12 @@ class MenuSvc(Service): @staticmethod def ReallyJumpThroughStructureJumpBridge(structureID): + bp = sm.StartService('michelle').GetBallpark() + if bp is None: + return + shipSlimItem = bp.GetInvItem(session.shipid) + jumpBridge = GetJumpBridgeComponent(bp, structureID) + jumpBridge.ValidateJumpAttempt(shipSlimItem.itemID, shipSlimItem.typeID) didJumpThrough = sm.StartService('sessionMgr').PerformSessionChange('jump', sm.RemoteSvc('structureJumpBridgeMgr').CmdJumpThroughStructureStargate, structureID) if didJumpThrough: sm.GetService('starmap').RemoveWaypointIfFirst(structureID) diff --git a/eve/client/script/ui/shared/fleet/fleetCompositionWnd.py b/eve/client/script/ui/shared/fleet/fleetCompositionWnd.py @@ -1,5 +1,6 @@ #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\fleet\fleetCompositionWnd.py from collections import defaultdict +import dogma.data import evetypes import localization from carbonui import uiconst, TextColor @@ -7,6 +8,8 @@ from carbonui.control.button import Button from carbonui.control.dragResizeCont import DragResizeCont from carbonui.primitives.container import Container from carbonui.primitives.containerAutoSize import ContainerAutoSize +from dogma.attributes.format import GetFormattedAttributeAndValue +from dogma.const import attributeBaseJumpBridgeCapacitorCost from eve.client.script.ui.control import eveLabel, eveScroll from eve.client.script.ui.control.entries.generic import Generic from eve.client.script.ui.control.entries.util import GetFromClass @@ -179,10 +182,22 @@ class FleetComposition(Window): numByShipGroupID[evetypes.GetGroupID(kv.shipTypeID)] += 1 byTypeScrollList = [] + totalCost = 0 + unknownJumpCostLocalization = localization.GetByLabel('UI/Fleet/FleetComposition/UnknownJumpCost') for shipTypeID, numShip in numByShipTypeID.iteritems(): sort_key = 'sort_%s' % localization.GetByLabel('UI/Fleet/FleetComposition/NumShips') + base_jump_cost = dogma.data.get_type_attribute(shipTypeID, attributeBaseJumpBridgeCapacitorCost) + if base_jump_cost is not None: + group_base_jump_cost = base_jump_cost * numShip + totalCost += group_base_jump_cost + formatted_jump_cost_text = GetFormattedAttributeAndValue(attributeBaseJumpBridgeCapacitorCost, group_base_jump_cost).value + else: + formatted_jump_cost_text = unknownJumpCostLocalization entry = GetFromClass(FleetCompSummaryEntry, {'typeID': shipTypeID, - 'label': '<t>'.join([evetypes.GetName(shipTypeID), evetypes.GetGroupName(shipTypeID), '<right>%s</right>' % numShip]), + 'label': '<t>'.join([evetypes.GetName(shipTypeID), + evetypes.GetGroupName(shipTypeID), + '<right>%s</right>' % numShip, + '<right>%s</right>' % formatted_jump_cost_text]), sort_key: numShip}) byTypeScrollList.append(entry) @@ -193,13 +208,27 @@ class FleetComposition(Window): byGroupScrollList.append(entry) if unknownNum: - entry = GetFromClass(Generic, {'label': '<t>'.join([localization.GetByLabel('UI/Fleet/FleetComposition/UnknownShipTypeID'), '', '<right>%s</right>' % unknownNum]), + entry = GetFromClass(Generic, {'label': '<t>'.join([localization.GetByLabel('UI/Fleet/FleetComposition/UnknownShipTypeID'), + '', + '<right>%s</right>' % unknownNum, + '']), 'sort_%s' % localization.GetByLabel('UI/Fleet/FleetComposition/NumShips'): unknownNum}) byTypeScrollList.append(entry) entry = GetFromClass(Generic, {'label': '<t>'.join([localization.GetByLabel('UI/Fleet/FleetComposition/UnknownShipTypeID'), '<right>%s</right>' % unknownNum]), 'sort_%s' % localization.GetByLabel('UI/Fleet/FleetComposition/NumShips'): unknownNum}) byGroupScrollList.append(entry) - headers = [localization.GetByLabel('UI/Fleet/FleetComposition/ShipType'), localization.GetByLabel('UI/Fleet/FleetComposition/ShipGroup'), localization.GetByLabel('UI/Fleet/FleetComposition/NumShips')] + formatted_total_cost_text = GetFormattedAttributeAndValue(attributeBaseJumpBridgeCapacitorCost, totalCost).value + total_text = localization.GetByLabel('UI/Fleet/FleetComposition/UpwellJumpCostTotal', totalCost=formatted_total_cost_text) + entry = GetFromClass(Generic, {'label': '<t>'.join(['', + '', + '', + '<right>%s</right>' % total_text]), + 'sort_%s' % localization.GetByLabel('UI/Fleet/FleetComposition/NumShips'): unknownNum}) + byTypeScrollList.append(entry) + headers = [localization.GetByLabel('UI/Fleet/FleetComposition/ShipType'), + localization.GetByLabel('UI/Fleet/FleetComposition/ShipGroup'), + localization.GetByLabel('UI/Fleet/FleetComposition/NumShips'), + localization.GetByLabel('UI/Fleet/FleetComposition/BaseUpwellJumpCost')] self.fleetSummaryTypeScroll.Load(headers=headers, contentList=byTypeScrollList) headers = [localization.GetByLabel('UI/Fleet/FleetComposition/ShipGroup'), localization.GetByLabel('UI/Fleet/FleetComposition/NumShips')] self.fleetSummaryGroupScroll.Load(headers=headers, contentList=byGroupScrollList) diff --git a/eve/client/script/ui/shared/info/infoConst.py b/eve/client/script/ui/shared/info/infoConst.py @@ -30,6 +30,7 @@ TYPE_DESIGN_ELEMENTS = 'type_design_elements' TYPE_PHASE_STABILIZER = 'type_phase_stabilizer' TYPE_PHASED_ASTEROID = 'type_phased_asteroid' TYPE_MATERIAL = 'type_material' +TYPE_JUMP_BRIDGE = 'type_jumpbridge' TYPE_STARGATE = 'type_stargate' TYPE_CONTROLTOWER = 'type_controltower' TYPE_STATION = 'type_station' @@ -101,7 +102,8 @@ infoTypeByGroupID = {const.groupCharacter: TYPE_CHARACTER, const.groupShipSkinDesignComponents: TYPE_DESIGN_ELEMENTS, const.groupMobilePhaseAnchor: TYPE_PHASE_STABILIZER, const.groupPhasedAsteroids: TYPE_PHASED_ASTEROID, - const.groupAsteroidBelt: TYPE_ASTEROID_BELT} + const.groupAsteroidBelt: TYPE_ASTEROID_BELT, + const.groupStructureJumpBridge: TYPE_JUMP_BRIDGE} for skinGroup in const.SHIP_SKIN_GROUPS: infoTypeByGroupID[skinGroup] = TYPE_SKINLICENSE @@ -219,6 +221,7 @@ TAB_FREELANCE_PROJECTS = 'tab_freelance_projects' TAB_PHASE_STABILIZER_MECHANICS = 'tab_phase_stabilizer_mechanics' TAB_PHASE_ASTEROID_MECHANICS = 'tab_phase_asteroid_mechanics' TAB_ASTEROID_BELT_ORE_TYPES = 'tab_asteroid_belt_ore_types' +TAB_JUMP_BRIDGE_MECHANICS = 'tab_jump_bridge_mechanics' DATA_BUTTONS = 'buttons' INFO_TABS = ((TAB_TRAITS, [], 'UI/InfoWindow/TabNames/Traits'), (TAB_BIO, [], 'UI/InfoWindow/TabNames/Bio'), @@ -287,4 +290,5 @@ INFO_TABS = ((TAB_TRAITS, [], 'UI/InfoWindow/TabNames/Traits'), (TAB_FREELANCE_PROJECTS, [], 'UI/Metadata/ContentTags/FreelanceProjects'), (TAB_PHASE_STABILIZER_MECHANICS, [], 'UI/Inflight/SpaceComponents/PhaseStabilizer/Info/Mechanics'), (TAB_PHASE_ASTEROID_MECHANICS, [], 'UI/Inflight/SpaceComponents/PhaseStabilizer/Info/Mechanics'), - (TAB_ASTEROID_BELT_ORE_TYPES, [], 'UI/Agency/OreTypesInBelt')) + (TAB_ASTEROID_BELT_ORE_TYPES, [], 'UI/Agency/OreTypesInBelt'), + (TAB_JUMP_BRIDGE_MECHANICS, [], 'UI/Inflight/SpaceComponents/JumpBridge/Info/Mechanics')) diff --git a/eve/client/script/ui/shared/info/infoContentBase.py b/eve/client/script/ui/shared/info/infoContentBase.py @@ -122,6 +122,7 @@ from .panels.panelAsteroidBeltOreTypes import PanelAsteroidBeltOreTypes from .panels.panelCertificateSkills import PanelCertificateSkills from .panels.panelIndustry import PanelIndustry from .panels.panelItemIndustry import PanelItemIndustry +from .panels.panelJumpBridgeMechanics import PanelJumpBridgeMechanics from .panels.panelMastery import PanelMastery from .panels.panelMutatorUsedWith import PanelMutatorUsedWith from .panels.panelNotes import PanelNotes @@ -1013,6 +1014,8 @@ class InfoWindowMonolith(InfoContentBase): return PanelPhasedAsteroidMechanics(parent=self.mainContentCont, itemID=self.item_id, typeID=self.item_id) if tabType == TAB_ASTEROID_BELT_ORE_TYPES: return PanelAsteroidBeltOreTypes(parent=self.mainContentCont, asteroid_belt_id=self.item_id) + if tabType == TAB_JUMP_BRIDGE_MECHANICS: + return PanelJumpBridgeMechanics(parent=self.mainContentCont, typeID=self.type_id) def SetUniqueUiNamesForTabs(self, tabs): tabNamesAndPointers = [(localization.GetByLabel('UI/InfoWindow/TabNames/Variations'), pConst.UNIQUE_NAME_VARIATION_TAB)] diff --git a/eve/client/script/ui/shared/info/infosvc.py b/eve/client/script/ui/shared/info/infosvc.py @@ -2461,6 +2461,8 @@ class Info(Service): content.dynamicTabs.append(TAB_PHASE_ASTEROID_MECHANICS) elif content.IsType(TYPE_MATERIAL): self.UpdateDataMaterial(content, typeID, itemID) + elif content.IsType(TYPE_JUMP_BRIDGE): + content.dynamicTabs.append(TAB_JUMP_BRIDGE_MECHANICS) if self.HasVariations(typeID): content.dynamicTabs.append(TAB_VARIATIONS) if self.IsIndustryItem(typeID): diff --git a/eve/client/script/ui/shared/info/panels/panelJumpBridgeMechanics.py b/eve/client/script/ui/shared/info/panels/panelJumpBridgeMechanics.py @@ -0,0 +1,66 @@ +#Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\info\panels\panelJumpBridgeMechanics.py +import carbonui.const as uiconst +from carbonui import Align +from carbonui.text.styles import TextBody +from carbonui.button.const import HEIGHT_NORMAL +from carbonui.control.scrollContainer import ScrollContainer +from carbonui.primitives.container import Container +from carbonui.primitives.containerAutoSize import ContainerAutoSize +from carbonui.primitives.fill import Fill +from carbonui.primitives.sprite import Sprite +from eve.client.script.ui.control.eveLabel import EveLabelMedium +from localization import GetByLabel + +class PanelJumpBridgeMechanics(Container): + + def ApplyAttributes(self, attributes): + super(PanelJumpBridgeMechanics, self).ApplyAttributes(attributes) + self.typeID = attributes.typeID + + def Load(self): + self.Flush() + self.scrollContainer = ScrollContainer(parent=self, padding=uiconst.defaultPadding) + self.AddJumpRestrictionsCont() + self.AddCapacitorUsageCont() + + def AddBulletin(self, parent, text, bulletNumber = None, maxLines = None): + textCont = ContainerAutoSize(name='textCont', parent=parent, align=uiconst.TOTOP, alignMode=Align.TOTOP) + padTop = 0 + padLeft = 16 + bulletLabel = TextBody(parent=textCont, padTop=padTop, text=text, align=uiconst.TOTOP, padLeft=padLeft, maxLines=maxLines) + _, activationHeight = bulletLabel.MeasureTextSize(text, maxLines=1) + iconSize = 8 + bulletinCont = Container(parent=textCont, align=uiconst.TOPLEFT, pos=(0, + 0, + 16, + activationHeight)) + if bulletNumber: + bulletLabel = TextBody(parent=bulletinCont, text='%s.' % bulletNumber, align=uiconst.CENTERLEFT) + else: + Sprite(parent=bulletinCont, pos=(0, + padTop, + iconSize, + iconSize), align=Align.CENTER, texturePath='res:/ui/texture/icons/3_8_1.png', state=uiconst.UI_DISABLED) + + def AddJumpRestrictionsCont(self): + text = GetByLabel('UI/Inflight/SpaceComponents/JumpBridge/Info/JumpRestrictionsText') + textList = text.splitlines(False) + self.AddMultiBulletinSection(GetByLabel('UI/Inflight/SpaceComponents/JumpBridge/Info/JumpRestrictions'), textList) + + def AddCapacitorUsageCont(self): + text = GetByLabel('UI/Inflight/SpaceComponents/JumpBridge/Info/CapacitorUsageText') + textList = text.splitlines(False) + self.AddMultiBulletinSection(GetByLabel('UI/Inflight/SpaceComponents/JumpBridge/Info/CapacitorUsage'), textList) + + def AddMultiBulletinSection(self, headerText, textList, showNumbers = False): + AddHeader(self.scrollContainer, headerText, padTop=8) + c = ContainerAutoSize(name='bulletinCont', parent=self.scrollContainer, align=uiconst.TOTOP, alignMode=Align.TOTOP, padding=8) + for i, text in enumerate(textList): + bulletNumber = i + 1 if showNumbers else None + self.AddBulletin(c, text=text, bulletNumber=bulletNumber) + + +def AddHeader(parent, headerText, padTop = 0): + c = ContainerAutoSize(name='headerCont', parent=parent, align=uiconst.TOTOP, minHeight=HEIGHT_NORMAL, padTop=padTop) + EveLabelMedium(text=headerText, parent=c, left=8, top=0, state=uiconst.UI_DISABLED, maxLines=1, align=uiconst.CENTERLEFT) + Fill(bgParent=c, opacity=0.05, padBottom=1) diff --git a/eve/client/script/ui/shared/info/shipInfoPanels/panelAttributes.py b/eve/client/script/ui/shared/info/shipInfoPanels/panelAttributes.py @@ -235,7 +235,10 @@ class PanelAttributes(PanelBase): 'valueFunc': GetAlignTimeFromAgilityAndMass, 'parameterAttributes': {'agility': const.attributeAgility, 'mass': const.attributeMass}}, - 'normalAttributes': [const.attributeMaxVelocity, const.attributeMass, const.attributeAgility], + 'normalAttributes': [const.attributeMaxVelocity, + const.attributeMass, + const.attributeAgility, + const.attributeBaseJumpBridgeCapacitorCost], 'constructedAttributes': [(const.attributeBaseWarpSpeed, lambda typeID, itemID: sm.GetService('info').GetWarpSpeedData(typeID, itemID))]} shipAttributes['targeting'] = {'groupName': GetByLabel('UI/Fitting/FittingWindow/Targeting'), 'normalAttributes': [const.attributeMaxTargetRange, diff --git a/eve/client/script/ui/shared/infoPanels/infoPanelAchievement.py b/eve/client/script/ui/shared/infoPanels/infoPanelAchievement.py @@ -3,28 +3,34 @@ import eveicon import threadutils from achievement_system.client.api.error import DefinitionNotFoundError from achievement_system.client.api.repository import get_repository -from achievement_system.client.api.signal import on_tracked_achievement_changed, on_achievement_progressed, on_achievement_completed, on_achievement_milestone_reached, on_admin_achievement_reset, on_admin_achievement_reset_all, on_achievement_milestone_reward_claimed +from achievement_system.client.api.signal import on_achievement_tracked, on_achievement_untracked, on_achievement_progressed, on_achievement_completed, on_achievement_milestone_reached, on_admin_achievement_reset, on_admin_achievement_reset_all, on_achievement_milestone_reward_claimed from achievement_system.client.model.definition.achievement.entry import AchievementDefinitionEntry -from achievement_system.client.model.definition.achievement.identifier import AchievementDefinitionIdentifier from achievement_system.client.ui.controller.achievement_entry import AchievementEntryController -from achievement_system.client.ui.link.create_achievement_link import create_achievement_link_light from achievement_system.client.ui.window.const import TRANSITION_DURATION from achievement_system.client.ui.window.window import AchievementsWindow from carbon.common.script.util.format import FmtAmt -from carbonui import Align, ButtonFrameType, Density, TextColor, uiconst +from carbonui import Align, ButtonFrameType, Density, TextColor, uiconst, PickState, ButtonStyle +from carbonui.button.menu import MenuButtonIcon from carbonui.control.button import Button +from carbonui.control.contextMenu.menuData import MenuData from carbonui.primitives.container import Container from carbonui.primitives.containerAutoSize import ContainerAutoSize from carbonui.primitives.fill import Fill -from carbonui.text.styles import TextHeader, TextBody +from carbonui.primitives.gridcontainer import GridContainer +from carbonui.primitives.sprite import Sprite +from carbonui.text.styles import TextBody, TextDetail from carbonui.uianimations import animations +from carbonui.uiconst import OutputMode from eve.client.script.ui import eveColor +from eve.client.script.ui.control.eveLabel import EveLabelLarge from eve.client.script.ui.control.gauge import Gauge from eve.client.script.ui.shared.infoPanels.InfoPanelBase import InfoPanelBase from eve.client.script.ui.shared.infoPanels.const import infoPanelConst, infoPanelUIConst from localization import GetByLabel +from signals import Signal from uihider import UiHiderMixin from uihighlighting.uniqueNameConst import UNIQUE_NAME_ACHIEVEMENT_INFO_PANEL +on_infopanel_achievement_expanded = Signal('on_infopanel_achievement_expanded') class InfoPanelAchievement(UiHiderMixin, InfoPanelBase): __guid__ = 'uicls.InfoPanelAchievement' @@ -34,63 +40,45 @@ class InfoPanelAchievement(UiHiderMixin, InfoPanelBase): label = 'UI/Achievements/Window/Title' default_iconTexturePath = 'res:/UI/Texture/WindowIcons/achievements.png' default_mode = infoPanelConst.MODE_NORMAL - default_are_objectives_collapsable = False def ApplyAttributes(self, attributes): super(InfoPanelAchievement, self).ApplyAttributes(attributes) - self._tracked_achievement_id = None - self._connect_signals() - self._create_header() - self._update_panel() + self.construct_layout() + self.connect_signals() def Close(self): - self._disconnect_signals() - super(InfoPanelAchievement, self).Close() + try: + self.disconnect_signals() + finally: + super(InfoPanelAchievement, self).Close() - def _connect_signals(self): - on_tracked_achievement_changed.connect(self._update_tracked_achievement) + def connect_signals(self): + on_achievement_tracked.connect(self.on_achievement_tracked) - def _disconnect_signals(self): - on_tracked_achievement_changed.disconnect(self._update_tracked_achievement) + def disconnect_signals(self): + on_achievement_tracked.disconnect(self.on_achievement_tracked) + + def construct_layout(self): + self.mainCont.padTop = 4 + self.headerCls(name='header_label', parent=self.headerCont, align=uiconst.CENTERLEFT, text=GetByLabel('UI/Achievements/Window/Title')) + tracked_achievement_ids = get_repository().activity.get_tracked_achievements() + auto_expand = len(tracked_achievement_ids) == 1 + for achievement_id in tracked_achievement_ids: + self.add_achievement(achievement_id, auto_expand) @staticmethod def IsAvailable(): - return get_repository().activity.get_tracked_achievement() is not None - - def _update_tracked_achievement(self, achievement_id): - if achievement_id != self._tracked_achievement_id: - self._update_panel() - - def _update_panel(self): - self.mainCont.Flush() - self._tracked_achievement_id = get_repository().activity.get_tracked_achievement() - controller = self.get_achievement_entry_controller(self._tracked_achievement_id) - if controller is not None: - TrackedAchievement(name='tracked_achievement', parent=self.mainCont, align=Align.TOTOP, controller=controller) - self._update_header_text() - - def _create_header(self): - self.headerCont.Flush() - self.title_label = self.headerCls(name='title_label', parent=self.headerCont, align=uiconst.CENTERLEFT, state=uiconst.UI_NORMAL) - - def _update_header_text(self): - if self._tracked_achievement_id is None: - title_text = GetByLabel(self.label) - else: - tracked_achievement = get_repository().definitions.get_achievement(self._tracked_achievement_id) - title_text = create_achievement_link_light(achievement_id=self._tracked_achievement_id, name=tracked_achievement.name_message.get_localized_text()) - self.title_label.text = title_text + return get_repository().activity.has_tracked_achievements() def ConstructHeaderButton(self): button = self.ConstructSimpleHeaderButton() button.OnClick = self.on_header_button_click - def on_header_button_click(self, *args): - wnd = AchievementsWindow.GetIfOpen() - if wnd and not wnd.destroyed: - wnd.Maximize() - else: - AchievementsWindow.Open() + def add_achievement(self, achievement_id, auto_expand = False): + controller = self.get_achievement_entry_controller(achievement_id) + if controller is None: + return + TrackedAchievement(name='tracked_achievement', parent=self.mainCont, align=Align.TOTOP, controller=controller, auto_expand=auto_expand, padBottom=8) def get_achievement_entry_controller(self, achievement_id): if achievement_id is None: @@ -103,13 +91,24 @@ class InfoPanelAchievement(UiHiderMixin, InfoPanelBase): achievement_entry = AchievementDefinitionEntry(achievement_id, achievement_attributes) return AchievementEntryController(achievement_entry) + def on_header_button_click(self, *args): + wnd = AchievementsWindow.GetIfOpen() + if wnd and not wnd.destroyed: + wnd.Maximize() + else: + AchievementsWindow.Open() + + def on_achievement_tracked(self, achievement_id): + self.add_achievement(achievement_id, auto_expand=True) + class TrackedAchievement(ContainerAutoSize): - def __init__(self, controller, *args, **kwargs): + def __init__(self, controller, auto_expand = False, *args, **kwargs): super(TrackedAchievement, self).__init__(*args, **kwargs) self.controller = controller - self.is_expanded = True + self.auto_expand = auto_expand + self.is_expanded = False self.construct_layout() self.update(animate=False) self.connect_signals() @@ -127,6 +126,9 @@ class TrackedAchievement(ContainerAutoSize): on_achievement_completed.connect(self.on_achievement_completed) on_achievement_milestone_reached.connect(self.on_milestone_reached) on_achievement_milestone_reward_claimed.connect(self.on_achievement_milestone_reward_claimed) + on_achievement_untracked.connect(self.on_achievement_untracked) + on_infopanel_achievement_expanded.connect(self.on_infopanel_achievement_expanded) + self.on_size_changed.connect(self.on_size_changed_signal) def disconnect_signals(self): on_achievement_progressed.disconnect(self.on_achievement_progressed) @@ -135,70 +137,72 @@ class TrackedAchievement(ContainerAutoSize): on_achievement_completed.disconnect(self.on_achievement_completed) on_achievement_milestone_reached.disconnect(self.on_milestone_reached) on_achievement_milestone_reward_claimed.disconnect(self.on_achievement_milestone_reward_claimed) + on_achievement_untracked.disconnect(self.on_achievement_untracked) + on_infopanel_achievement_expanded.disconnect(self.on_infopanel_achievement_expanded) + self.on_size_changed.disconnect(self.on_size_changed_signal) def construct_layout(self): - Fill(bgParent=self, color=eveColor.BLACK, opacity=0.25) - self.content_container = ContainerAutoSize(name='content_container', parent=self, align=uiconst.TOTOP, padding=(8, 8, 8, 8)) + self.content_container = ContainerAutoSize(name='content_container', parent=self, align=uiconst.TOTOP, alignMode=Align.TOTOP) self.construct_header() self.construct_details() def construct_header(self): - header_container = ContainerAutoSize(name='header_container', parent=self.content_container, align=Align.TOTOP, state=uiconst.UI_NORMAL) - header_container.OnClick = self.on_header_clicked - label_container = Container(name='label_container', parent=header_container, align=Align.TOTOP, height=28) - self.progress_label = TextHeader(name='progress_label', parent=label_container, align=Align.CENTER, color=TextColor.HIGHLIGHT) - self.progress_bar = Gauge(name='progress_bar', parent=header_container, align=Align.TOTOP, gaugeHeight=4, padTop=4) + self.header_container = Container(name='header_container', parent=self.content_container, align=Align.TOTOP) + Fill(bgParent=self.header_container, color=eveColor.BLACK, opacity=0.35) + header_contents = Container(name='header_contents', parent=self.header_container, padding=(8, 0, 8, 0)) + header_icon_container = Container(name='header_icon_container', parent=header_contents, align=Align.TOLEFT, width=16) + self.header_icon = Sprite(name='header_icon', parent=header_icon_container, align=Align.CENTER, color=eveColor.WHITE, outputMode=OutputMode.COLOR_AND_GLOW, glowBrightness=0.0, opacity=0.75, hint=GetByLabel('UI/Achievements/ViewCategory'), pos=(0, 0, 16, 16)) + self.header_icon.OnClick = self.on_header_icon_click + self.header_icon.OnMouseEnter = self.on_header_icon_enter + self.header_icon.OnMouseExit = self.on_header_icon_exit + self.menu_container = Container(name='menu_container', parent=header_contents, align=Align.TORIGHT, clipChildren=True, width=0) + MenuButtonIcon(name='menu_button_icon', parent=self.menu_container, align=Align.CENTERRIGHT, get_menu_func=self.get_options_menu, hint=None, width=16) + self.header_label_container = Container(name='header_label_container', parent=header_contents, align=Align.VERTICALLY_CENTERED, padLeft=8) + self.header_progress_label = EveLabelLarge(name='header_progress_label', parent=self.header_label_container, align=Align.TORIGHT, state=uiconst.UI_NORMAL, padLeft=8) + self.header_progress_label.OnClick = self.on_header_clicked + self.header_name_label = EveLabelLarge(name='header_name_label', parent=self.header_label_container, align=Align.VERTICALLY_CENTERED, color=TextColor.HIGHLIGHT, maxLines=1, showEllipsis=True) + header_interaction_container = Container(name='header_interaction_container', parent=self.header_container, state=uiconst.UI_NORMAL) + header_interaction_container.OnClick = self.on_header_clicked def construct_details(self): - self.details_container = Container(name='details_container', parent=self.content_container, align=Align.TOTOP, clipChildren=True, height=0, padTop=4) - self.description_label = TextBody(parent=self.details_container, name='description_label', align=Align.TOTOP_NOPUSH) - self.button_container = Container(name='button_container', parent=self.details_container, align=Align.TOTOP_NOPUSH, height=24, opacity=0.0) - Button(parent=self.button_container, name='untrack_button', align=Align.TORIGHT, hint=GetByLabel('UI/Achievements/Window/Card/UntrackButtonHint'), texturePath=eveicon.camera_untrack, iconSize=24, func=self.on_untrack_button_clicked, width=24) - self.claim_button = Button(parent=self.button_container, name='claim_button', align=Align.TOTOP, label=GetByLabel('UI/Achievements/Window/Rewards/ClaimRewards'), density=Density.COMPACT, frame_type=ButtonFrameType.CUT_BOTTOM_LEFT, func=self.on_claim_rewards_clicked, height=24) + self.details_container = Container(name='details_container', parent=self.content_container, align=Align.TOTOP, clipChildren=True, height=0) + Fill(bgParent=self.details_container, color=eveColor.BLACK, opacity=0.25) + self.details_contents = ContainerAutoSize(name='details_contents', parent=self.details_container, align=Align.TOTOP, padding=(8, 4, 8, 0)) + self.description_label = TextBody(parent=self.details_contents, name='description_label', align=Align.TOTOP) + if self.controller.has_multiple_milestones: + self.milestones = Milestones(name='milestones', parent=self.details_contents, align=Align.TOTOP, controller=self.controller, padTop=8) + self.progress = Progress(name='progress', parent=self.details_contents, align=Align.TOTOP, controller=self.controller, padTop=8) + self.construct_claim_button() + + def construct_claim_button(self): + self.claim_button = ClaimButton(parent=self.details_contents, name='claim_button', align=Align.TOTOP, padTop=16, display=False) @threadutils.highlander_threaded def update(self, animate = True): - if self.controller is None: - self.details_container.display = False - return - self.update_progress() + self.update_header() self.update_details(animate) - def update_progress(self): - progress = self.controller.progress - target = self.controller.target_for_milestone_index(self.controller.current_milestone_index) - if target <= 100000: - progress_text = FmtAmt(progress) - target_text = FmtAmt(target) - else: - progress_text = FmtAmt(progress, fmt='sn') - target_text = FmtAmt(target, fmt='sn') - self.progress_label.text = '%s/%s' % (progress_text, target_text) - self.progress_bar.SetColor(self.controller.progress_bar_color) - self.progress_bar.SetValue(self.controller.percent_progress_towards_current_milestone) + def update_header(self): + name_text = self.controller.name + _, header_text_height = EveLabelLarge.MeasureTextSize(name_text) + self.header_label_container.height = header_text_height + self.header_container.height = header_text_height + 16 + self.header_icon.texturePath = self.controller.category_icon + self.header_name_label.text = name_text + self.header_progress_label.text = self.controller.progress_score_text_for_current_milestone + self.header_progress_label.hint = self.controller.progress_score_hint_for_current_milestone + self.header_progress_label.display = not self.is_expanded def update_details(self, animate): self.description_label.text = self.controller.description - if self.controller.is_completed and self.controller.has_unclaimed_rewards: - self.button_container.state = uiconst.UI_PICKCHILDREN - if animate: - animations.FadeIn(self.button_container, duration=TRANSITION_DURATION) - animations.FadeOut(self.description_label, duration=TRANSITION_DURATION) - self.animate_details_container() - else: - self.button_container.opacity = 1.0 - self.description_label.opacity = 0.0 - self.details_container.height = self.details_target_height + if self.controller.has_multiple_milestones: + self.milestones.update() + self.progress.update() + self.claim_button.display = self.controller.is_completed and self.controller.has_unclaimed_rewards + if animate: + self.animate_details_container() else: - self.button_container.state = uiconst.UI_DISABLED - if animate: - animations.FadeOut(self.button_container, duration=TRANSITION_DURATION) - animations.FadeIn(self.description_label, duration=TRANSITION_DURATION) - self.animate_details_container() - else: - self.button_container.opacity = 0.0 - self.description_label.opacity = 1.0 - self.details_container.height = self.details_target_height + self.details_container.height = self.details_target_height def animate_details_container(self): animations.MorphScalar(obj=self.details_container, attrName='height', startVal=self.details_container.height, endVal=self.details_target_height, duration=TRANSITION_DURATION) @@ -207,15 +211,49 @@ class TrackedAchievement(ContainerAutoSize): def details_target_height(self): if not self.is_expanded: return 0 - if self.controller.is_completed and self.controller.has_unclaimed_rewards: - return self.button_container.height measure_width = infoPanelUIConst.PANELWIDTH - infoPanelUIConst.LEFTPAD - 16 _, text_height = TextBody.MeasureTextSize(self.controller.description, width=measure_width) - return text_height + if self.controller.is_completed and self.controller.has_unclaimed_rewards: + text_height += self.claim_button.height + self.claim_button.padTop + if self.controller.has_multiple_milestones: + text_height += self.milestones.height + self.milestones.padTop + return text_height + 12 + self.progress.height + self.progress.padTop + + def get_options_menu(self): + data = MenuData() + data.AddEntry(text=GetByLabel('UI/Achievements/ViewDetails'), func=self.on_menu_view_details) + data.AddEntry(text=GetByLabel('UI/Common/Untrack'), func=self.on_menu_untrack, texturePath=eveicon.camera_untrack) + return data + + def on_menu_view_details(self, *args): + AchievementsWindow.open_achievement(self.controller.achievement_entry.identifier) + wnd = AchievementsWindow.GetIfOpen() + if wnd: + wnd.Maximize() - def on_header_clicked(self): + def on_menu_untrack(self, *args): + self.controller.untrack() + + def on_size_changed_signal(self, width, height): + if not self.auto_expand: + return + self.auto_expand = False + self.on_header_clicked() + + def on_header_clicked(self, *args): self.is_expanded = not self.is_expanded self.update() + if self.is_expanded: + on_infopanel_achievement_expanded(self.controller.achievement_entry.identifier) + + def on_header_icon_click(self, *args): + AchievementsWindow.open_category(self.controller.achievement_entry.attributes.parent_category) + + def on_header_icon_enter(self, *args): + animations.MorphScalar(obj=self.header_icon, attrName='glowBrightness', startVal=self.header_icon.glowBrightness, endVal=0.3, duration=TRANSITION_DURATION * 0.5) + + def on_header_icon_exit(self, *args): + animations.MorphScalar(obj=self.header_icon, attrName='glowBrightness', startVal=self.header_icon.glowBrightness, endVal=0.0, duration=TRANSITION_DURATION * 0.5) def on_achievement_progressed(self, achievement_id, achievement_state): if achievement_id == self.controller.achievement_entry.identifier: @@ -236,13 +274,117 @@ class TrackedAchievement(ContainerAutoSize): def on_reset_all(self): self.update() - def on_claim_rewards_clicked(self, *args): - AchievementsWindow.open_unclaimed_rewards() - def on_untrack_button_clicked(self, *args): - get_repository().activity.set_tracked_achievement(None) + self.controller.untrack() def on_achievement_milestone_reward_claimed(self, achievement_id, milestone_id): if achievement_id == self.controller.achievement_entry.identifier: if self.controller.is_completed and not self.controller.has_unclaimed_rewards: - get_repository().activity.set_tracked_achievement(None) + self.controller.untrack() + + def on_achievement_untracked(self, achievement_id): + if achievement_id == self.controller.achievement_entry.identifier: + self.Close() + + def on_infopanel_achievement_expanded(self, achievement_id): + if achievement_id != self.controller.achievement_entry.identifier: + self.is_expanded = False + self.update() + + def OnMouseEnter(self, *args): + animations.MorphScalar(obj=self.menu_container, attrName='width', startVal=self.menu_container.width, endVal=20, duration=TRANSITION_DURATION * 0.5) + + def OnMouseExit(self, *args): + animations.MorphScalar(obj=self.menu_container, attrName='width', startVal=self.menu_container.width, endVal=0, duration=TRANSITION_DURATION * 0.5) + + def OnGlobalFontSizeChanged(self): + super(TrackedAchievement, self).OnGlobalFontSizeChanged() + self.update() + + +class Milestones(ContainerAutoSize): + default_alignMode = Align.TOTOP + + def __init__(self, controller, *args, **kwargs): + super(Milestones, self).__init__(*args, **kwargs) + self.controller = controller + self.construct_layout() + + def construct_layout(self): + label_container = ContainerAutoSize(name='label_container', parent=self, align=Align.TOTOP, alignMode=Align.TOTOP) + self.progress_label = TextDetail(name='progress_label', parent=label_container, align=Align.TORIGHT, padLeft=8) + TextDetail(name='title_label', parent=label_container, align=Align.TOTOP, text=GetByLabel('UI/Achievements/Window/Card/CurrentMilestone')) + self.marker_container = GridContainer(name='marker_container', parent=self, align=uiconst.TOTOP, height=4, contentSpacing=(4, 4), padTop=4) + + def construct_markers(self): + self.marker_container.Flush() + total_milestones = self.controller.total_milestones + if total_milestones == 0: + return + self.marker_container.columns = min(total_milestones, 5) + for index in range(0, self.controller.total_milestones): + is_completed = index < self.controller.completed_milestones + is_current = index == self.controller.current_milestone_index + if is_completed: + color = eveColor.SUCCESS_GREEN + elif is_current: + color = eveColor.FOCUS_BLUE + else: + color = eveColor.WHITE + if is_completed or is_current: + opacity = 1.0 + glow_brightness = 0.5 + else: + opacity = 0.2 + glow_brightness = 0.0 + Fill(parent=self.marker_container, color=color, outputMode=OutputMode.COLOR_AND_GLOW, glowBrightness=glow_brightness, opacity=opacity) + + @threadutils.highlander_threaded + def update(self): + self.progress_label.text = '(%s/%s)' % (self.controller.current_milestone_index + 1, self.controller.total_milestones) + self.construct_markers() + + +class Progress(ContainerAutoSize): + default_alignMode = Align.TOTOP + + def __init__(self, controller, *args, **kwargs): + super(Progress, self).__init__(*args, **kwargs) + self.controller = controller + self.construct_layout() + + def construct_layout(self): + label_container = ContainerAutoSize(name='label_container', parent=self, align=Align.TOTOP, alignMode=Align.TOTOP) + self.progress_label = TextDetail(name='progress_label', parent=label_container, align=Align.TORIGHT, state=uiconst.UI_NORMAL, padLeft=8) + TextDetail(name='title_label', parent=label_container, align=Align.TOTOP, text=GetByLabel('UI/Achievements/Progress')) + self.progress_bar = Gauge(name='progress_bar', parent=self, align=Align.TOTOP, gaugeHeight=4, padTop=4) + + @threadutils.highlander_threaded + def update(self): + progress = self.controller.progress + target = self.controller.target_for_milestone_index(self.controller.current_milestone_index) + if target <= 100000: + progress_text = FmtAmt(progress) + target_text = FmtAmt(target) + else: + progress_text = FmtAmt(progress, fmt='sn') + target_text = FmtAmt(target, fmt='sn') + self.progress_label.hint = self.controller.progress_score_hint_for_current_milestone + self.progress_label.text = '%s/%s' % (progress_text, target_text) + self.progress_bar.SetColor(self.controller.progress_bar_color) + self.progress_bar.SetValue(self.controller.percent_progress_towards_current_milestone) + + +class ClaimButton(Button): + default_pickState = PickState.ON + default_label = GetByLabel('UI/Achievements/Window/Rewards/ClaimRewards') + default_density = Density.COMPACT + default_style = ButtonStyle.SUCCESS + default_frame_type = ButtonFrameType.CUT_BOTTOM_LEFT_RIGHT + + def __init__(self, *args, **kwargs): + super(ClaimButton, self).__init__(*args, **kwargs) + self.func = self.on_claim_rewards_clicked + + def on_claim_rewards_clicked(self, *args): + AchievementsWindow.open_unclaimed_rewards() diff --git a/eve/client/script/ui/shared/infoPanels/infoPanelSvc.py b/eve/client/script/ui/shared/infoPanels/infoPanelSvc.py @@ -7,6 +7,7 @@ import log import telemetry import uthread import uthread2 +from achievement_system.client.api.signal import on_achievements_tracked_changed from carbon.common.script.sys import service from carbon.common.script.util import commonutils from carbon.common.script.util.timerstuff import AutoTimer @@ -21,15 +22,12 @@ from eve.client.script.ui.shared.infoPanels.const import infoPanelConst from eve.client.script.ui.shared.infoPanels.const import infoPanelUIConst from eve.client.script.ui.shared.infoPanels.infoPanelContainer import InfoPanelContainer from eve.client.script.ui.shared.infoPanels.milestoneTimer.milestoneTimer import MilestoneTimer -from eve.common.lib import appConst as const from eve.common.script.sys import idCheckers from eveformat.client import solar_system_security_status -from achievement_system.client.api.signal import on_tracked_achievement_changed from jobboard.client import job_board_signals from milestones.common.constants import MILESTONE_REWARD_MINUTES, MILESTONE_HUNDRED_AND_TWENTY_MINUTES_ID from operations.common.const import OPERATION_CATEGORY_RECOMMENDATIONS from uthread2 import StartTasklet -from spacecomponents.common.components.linkWithShip import LINKSTATE_RUNNING MISSION_INFO_PANEL_UPDATE_DELAY_MSEC = 1000 OPERATION_INFO_PANEL_UPDATE_DELAY_MSEC = 1000 RECOMMENDATION_INFO_PANEL_UPDATE_DELAY_SEC = 0.5 @@ -153,7 +151,7 @@ class InfoPanelSvc(service.Service): job_board_signals.on_job_board_feature_availability_changed.connect(self.OnJobBoardAvailabilityChanged) job_board_signals.on_tracked_jobs_changed.connect(self.OnTrackedJobsChanged) colorblind.on_colorblind_mode_changed.connect(self.OnColorBlindModeChanged) - on_tracked_achievement_changed.connect(self.OnTrackedAchievementChanged) + on_achievements_tracked_changed.connect(self.OnTrackedAchievementChanged) def DisconnectSignals(self): on_cp_goal_tracking_added.disconnect(self.OnCareerProgramTrackingUpdated) @@ -161,7 +159,7 @@ class InfoPanelSvc(service.Service): job_board_signals.on_job_board_feature_availability_changed.disconnect(self.OnJobBoardAvailabilityChanged) job_board_signals.on_tracked_jobs_changed.disconnect(self.OnTrackedJobsChanged) colorblind.on_colorblind_mode_changed.disconnect(self.OnColorBlindModeChanged) - on_tracked_achievement_changed.disconnect(self.OnTrackedAchievementChanged) + on_achievements_tracked_changed.disconnect(self.OnTrackedAchievementChanged) @telemetry.ZONE_FUNCTION def OnSessionChanged(self, isRemote, sess, change): @@ -473,7 +471,7 @@ class InfoPanelSvc(service.Service): def OnCareerProgramTrackingUpdated(self, *args, **kwargs): self.UpdatePanel(infoPanelConst.PANEL_CAREER_PROGRAM) - def OnTrackedAchievementChanged(self, *args, **kwargs): + def OnTrackedAchievementChanged(self, achievement_ids): self.UpdatePanel(infoPanelConst.PANEL_ACHIEVEMENT) def OnJobBoardAvailabilityChanged(self, *args, **kwargs): diff --git a/eve/client/script/ui/shared/neocom/characterSheetWindow.py b/eve/client/script/ui/shared/neocom/characterSheetWindow.py @@ -361,6 +361,12 @@ class CharacterSheetWindow(Window): cls._OpenPanel(PANEL_DECORATIONS) @classmethod + def OpenDecorationsToTitles(cls): + from eve.client.script.ui.shared.neocom.charsheet.decorationsPanel import DecorationsPanel + DecorationsPanel._class_pending_open_titles = True + cls._OpenPanel(PANEL_DECORATIONS) + + @classmethod def OpenDecorationsToTitle(cls, title_uuid_str): from eve.client.script.ui.shared.neocom.charsheet.decorationsPanel import DecorationsPanel DecorationsPanel._class_pending_title_uuid = title_uuid_str diff --git a/eve/client/script/ui/shared/neocom/charsheet/decorationsPanel.py b/eve/client/script/ui/shared/neocom/charsheet/decorationsPanel.py @@ -19,6 +19,7 @@ PANEL_TITLES = 'mydecorations_titles' class DecorationsPanel(Container): default_name = 'DecorationsPanel' + _class_pending_open_titles = False _class_pending_title_uuid = None __notifyevents__ = ['OnRankChange', 'OnUpdatedMedalsAvailable', @@ -40,6 +41,8 @@ class DecorationsPanel(Container): self.decoMedalList = None self.decoRankList = None self.decoTitleList = None + self._pending_open_titles = DecorationsPanel._class_pending_open_titles + DecorationsPanel._class_pending_open_titles = False self._pending_scroll_title_uuid = DecorationsPanel._class_pending_title_uuid DecorationsPanel._class_pending_title_uuid = None self._title_blinker = None @@ -55,6 +58,10 @@ class DecorationsPanel(Container): self.mydecorationstabs.SelectByID(PANEL_TITLES) if self._pending_scroll_title_uuid is not None and self.display and self._is_ancestor_chain_displayed(): self.ShowMyTitles() + elif self._pending_open_titles: + self._pending_open_titles = False + self.mydecorationstabs.SelectByID(PANEL_TITLES) + self.ShowMyTitles() else: self.mydecorationstabs.AutoSelect() diff --git a/eve/client/script/ui/shared/neocom/wallet/panels/personal/personalISKPanel.py b/eve/client/script/ui/shared/neocom/wallet/panels/personal/personalISKPanel.py @@ -5,7 +5,6 @@ from eve.client.script.ui.shared.neocom.wallet.panels.ISKPanel import ISKPanel from eve.client.script.ui.shared.neocom.wallet.panels.personal.giveIskPanel import GiveIskPanel from eve.client.script.ui.shared.neocom.wallet.panels.personal.overviewPanel import OverviewPanel from eve.client.script.ui.shared.neocom.wallet.panels.personal.personalMarketTransactionsPanel import PersonalMarketTransactionsPanel -from eve.client.script.ui.shared.neocom.wallet.panels.personal.personalPaySettingsPanel import PersonalPaySettingsPanel from eve.client.script.ui.shared.neocom.wallet.panels.personal.personalSharesPanel import PersonalSharesPanel from eve.client.script.ui.shared.neocom.wallet.panels.personal.personalTransactionsPanel import PersonalTransactionsPanel from localization import GetByLabel @@ -34,10 +33,6 @@ class PersonalISKPanel(ISKPanel): 'panel': self.sharesPanel, 'code': self, 'tabID': walletConst.PANEL_SHARES}, - {'label': GetByLabel('UI/Wallet/WalletWindow/PersonalAutoPayment'), - 'panel': self.paySettings, - 'code': self, - 'tabID': walletConst.PANEL_PAYSETTINGS}, {'label': GetByLabel('UI/Wallet/WalletWindow/GiveMoney'), 'panel': self.giveIskPanel, 'code': self, @@ -49,7 +44,6 @@ class PersonalISKPanel(ISKPanel): self.sharesTabs = None self.marketTransactionsPanel = PersonalMarketTransactionsPanel(parent=self, state=uiconst.UI_HIDDEN) self.sharesPanel = PersonalSharesPanel(parent=self, state=uiconst.UI_HIDDEN) - self.paySettings = PersonalPaySettingsPanel(parent=self, state=uiconst.UI_HIDDEN) self.giveIskPanel = GiveIskPanel(parent=self, state=uiconst.UI_HIDDEN) def GetIskBalance(self): diff --git a/eve/client/script/ui/shared/neocom/wallet/panels/personal/personalPaySettingsPanel.py b/eve/client/script/ui/shared/neocom/wallet/panels/personal/personalPaySettingsPanel.py @@ -1,76 +0,0 @@ -#Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\shared\neocom\wallet\panels\personal\personalPaySettingsPanel.py -from carbonui import uiconst -from carbonui.button.group import ButtonGroup -from carbonui.control.button import Button -from carbonui.primitives.container import Container -from characterSettingsStorage.characterSettingsConsts import JUMPBRIDGE_AUTOPAYMENT, JUMPBRIDGE_AUTOPAYMENT_CB, JUMPBRIDGE_AUTOPAYMENT_VALUE, PERSONAL_AUTOPAYMENT, PERSONAL_AUTOPAYMENTS_AVAILABLE -from characterSettingsStorage.characterSettingsObject import CharacterSettingsObject -from eve.client.script.ui.control.entries.util import GetFromClass -from eve.client.script.ui.control.eveScroll import Scroll -from eve.client.script.ui.shared.neocom.wallet.checkboxWithInputFieldEntry import CheckBoxWithInputField -from localization import GetByLabel -from player_messaging.client.ui_message import prompt_player_fsd_dialog -BUTTON_LABEL = GetByLabel('UI/Commands/Apply') - -def GetTooltipForJB(tooltipPanel, *args): - tooltipPanel.LoadGeneric1ColumnTemplate() - tooltipPanel.state = uiconst.UI_NORMAL - text = GetByLabel('UI/Wallet/WalletWindow/ActivateJumpGateTooltip') - tooltipPanel.AddLabelMedium(text=text, align=uiconst.TOPLEFT, wrapWidth=200) - - -class PersonalPaySettingsPanel(Container): - default_name = 'PersonalPaySettingsPanel' - _apply_button = None - - def ApplyAttributes(self, attributes): - super(PersonalPaySettingsPanel, self).ApplyAttributes(attributes) - self.scroll = Scroll(parent=self, align=uiconst.TOALL) - self.scroll.HideBackground() - self.personalAutoPayButtons = ButtonGroup(name='personalAutoPayButtons', parent=self, state=uiconst.UI_PICKCHILDREN, align=uiconst.TOBOTTOM, idx=0) - self._apply_button = Button(parent=self.personalAutoPayButtons, label=BUTTON_LABEL, func=self.SubmitPersonalAutomaticPaymentSettings, args=()) - - def OnTabSelect(self): - self._apply_button.Blink(on_off=0) - self.SetPersonalAutopaymentSettingsIfNeeded() - self.personalAutoPayButtons.display = True - scrolllist = [] - configName = JUMPBRIDGE_AUTOPAYMENT - isChecked = self.personalAutopaymentsObject.GetSingleValue(JUMPBRIDGE_AUTOPAYMENT_CB, False) - value = self.personalAutopaymentsObject.GetSingleValue(JUMPBRIDGE_AUTOPAYMENT_VALUE, 0) - scrolllist.append(GetFromClass(CheckBoxWithInputField, {'label': GetByLabel('UI/Wallet/WalletWindow/ActivateJumpGate'), - 'checked': isChecked, - 'cfgname': configName, - 'cfgNameCb': JUMPBRIDGE_AUTOPAYMENT_CB, - 'cfgNameValue': JUMPBRIDGE_AUTOPAYMENT_VALUE, - 'moreTooltip': GetTooltipForJB, - 'OnChange': self.OnPersonalAutoPaymentChanged, - 'currentValue': value, - 'unitString': GetByLabel('UI/Common/ISK')})) - self.scroll.Load(contentList=scrolllist) - - def SetPersonalAutopaymentSettingsIfNeeded(self): - if getattr(self, 'personalAutopaymentsObject', None) is None: - yamlString = self.FetchPersonalAutopaymentSettingsToServer() - self.personalAutopaymentsObject = CharacterSettingsObject(yamlString) - - def FetchPersonalAutopaymentSettingsToServer(self): - yamlString = sm.GetService('characterSettings').Get(PERSONAL_AUTOPAYMENT) - return yamlString - - def SubmitPersonalAutomaticPaymentSettings(self, *args): - for eachNode in self.scroll.GetNodes(): - cfgname = eachNode.cfgname - if cfgname not in PERSONAL_AUTOPAYMENTS_AVAILABLE: - prompt_player_fsd_dialog('CustomInfo', {'info': 'Trying to save a payment not in the list, fix your stuff!'}) - raise RuntimeError() - isChecked = eachNode.checked - value = eachNode.get('currentValue', 0) - self.personalAutopaymentsObject.SetSingleValue(eachNode.cfgNameCb, isChecked) - self.personalAutopaymentsObject.SetSingleValue(eachNode.cfgNameValue, value) - - newYamlString = self.personalAutopaymentsObject.GetYamlStringForServer() - sm.GetService('characterSettings').Save(PERSONAL_AUTOPAYMENT, newYamlString) - - def OnPersonalAutoPaymentChanged(self, *args): - self._apply_button.Blink() diff --git a/eve/client/script/ui/shared/theatersOfWar/campaigns/panels/achievement_banner.py b/eve/client/script/ui/shared/theatersOfWar/campaigns/panels/achievement_banner.py @@ -115,7 +115,7 @@ def get_reward_data_dict_for_controller(reward_controller): hint = '' text = reward_controller.get_reward_text(reward_attributes) if reward_type == RewardType.TITLE: - hint = GetByLabel('UI/Achievements/Window/Rewards/TitleReward') + hint = GetByLabel('UI/Achievements/Window/Rewards/Title') if title_repository().definitions is None: continue try: @@ -131,8 +131,9 @@ def get_reward_data_dict_for_controller(reward_controller): hint = GetByLabel('UI/Common/SkillPoints') elif reward_type == RewardType.ISK: hint = GetByLabel('UI/Common/ISK') + is_granted = reward_controller.is_milestone_reached is_claimed = achievement_repository().is_reward_claimed_for_achievement_milestone(reward_controller.identifier, reward_controller.milestone_id, reward_id) - reward_data = RewardData(reward_type=reward_type, is_claimed=is_claimed, icon=icon, text=text, hint=hint) + reward_data = RewardData(reward_type=reward_type, is_granted=is_granted, is_claimed=is_claimed, icon=icon, text=text, hint=hint) result[reward_id] = reward_data return result diff --git a/eve/client/script/ui/structure/structureBrowser/extaColumnUtil.py b/eve/client/script/ui/structure/structureBrowser/extaColumnUtil.py @@ -69,6 +69,8 @@ class ExtraColumnProvider(object): def FormatColumnValue(value, valueType, settingID): if settingID == structures.SETTING_HOUSING_CAN_DOCK: return bool(value is not None) + if settingID == structures.SETTING_JUMP_BRIDGE_ACTIVATION: + return bool(value is not None) if valueType == structures.SETTINGS_TYPE_INT: return int(value) if valueType == structures.SETTINGS_TYPE_PERCENTAGE: diff --git a/eveProto/generated/eve/achievement/definition/version/api/requests_pb2.py b/eveProto/generated/eve/achievement/definition/version/api/requests_pb2.py @@ -5,21 +5,28 @@ from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database _sym_db = _symbol_database.Default() from eveProto.generated.eve import eve_pb2 as eve_dot_eve__pb2 +from eveProto.generated.eve.quasar.admin import admin_pb2 as eve_dot_quasar_dot_admin_dot_admin__pb2 from eveProto.generated.eve import semanticversion_pb2 as eve_dot_semanticversion__pb2 from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 -DESCRIPTOR = _descriptor.FileDescriptor(name='eve/achievement/definition/version/api/requests.proto', package='eve.achievement.definition.version.api', syntax='proto3', serialized_options='ZQgithub.com/ccpgames/eve-proto-go/generated/eve/achievement/definition/version/api', create_key=_descriptor._internal_create_key, serialized_pb='\n5eve/achievement/definition/version/api/requests.proto\x12&eve.achievement.definition.version.api\x1a\reve/eve.proto\x1a\x19eve/semanticversion.proto\x1a\x1fgoogle/protobuf/timestamp.proto"\r\n\x0bListRequest"D\n\x0cListResponse\x124\n\x08versions\x18\x01 \x03(\x0b2".eve.semanticversion.Specification"\x15\n\x13GetScheduledRequest"\xa1\x02\n\x14GetScheduledResponse\x12c\n\x11scheduled_version\x18\x01 \x01(\x0b2F.eve.achievement.definition.version.api.GetScheduledResponse.ScheduledH\x00\x12\x1e\n\x14no_scheduled_version\x18\x02 \x01(\x08H\x00\x1aw\n\tScheduled\x123\n\x07version\x18\x01 \x01(\x0b2".eve.semanticversion.Specification\x125\n\x11release_timestamp\x18\x02 \x01(\x0b2\x1a.google.protobuf.TimestampB\x0b\n\tscheduled"\x1a\n\x18GetDefaultVersionRequest"P\n\x19GetDefaultVersionResponse\x123\n\x07version\x18\x01 \x01(\x0b2".eve.semanticversion.Specification"\x19\n\x17GetTenantVersionRequest"O\n\x18GetTenantVersionResponse\x123\n\x07version\x18\x01 \x01(\x0b2".eve.semanticversion.Specification"5\n\x1aListTenantOverridesRequest\x12\x17\n\x04page\x18\x01 \x01(\x0b2\t.eve.Page"\xaf\x02\n\x1bListTenantOverridesResponse\x12e\n\toverrides\x18\x01 \x03(\x0b2R.eve.achievement.definition.version.api.ListTenantOverridesResponse.TenantOverride\x12 \n\tnext_page\x18\x02 \x01(\x0b2\r.eve.NextPage\x1a\x86\x01\n\x0eTenantOverride\x12\x0e\n\x06tenant\x18\x01 \x01(\t\x123\n\x07version\x18\x02 \x01(\x0b2".eve.semanticversion.Specification\x12/\n\x0bupdate_time\x18\x03 \x01(\x0b2\x1a.google.protobuf.TimestampBSZQgithub.com/ccpgames/eve-proto-go/generated/eve/achievement/definition/version/apib\x06proto3', dependencies=[eve_dot_eve__pb2.DESCRIPTOR, eve_dot_semanticversion__pb2.DESCRIPTOR, google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR]) -_LISTREQUEST = _descriptor.Descriptor(name='ListRequest', full_name='eve.achievement.definition.version.api.ListRequest', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[], extensions=[], nested_types=[], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[], serialized_start=172, serialized_end=185) -_LISTRESPONSE = _descriptor.Descriptor(name='ListResponse', full_name='eve.achievement.definition.version.api.ListResponse', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[_descriptor.FieldDescriptor(name='versions', full_name='eve.achievement.definition.version.api.ListResponse.versions', index=0, number=1, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key)], extensions=[], nested_types=[], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[], serialized_start=187, serialized_end=255) -_GETSCHEDULEDREQUEST = _descriptor.Descriptor(name='GetScheduledRequest', full_name='eve.achievement.definition.version.api.GetScheduledRequest', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[], extensions=[], nested_types=[], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[], serialized_start=257, serialized_end=278) -_GETSCHEDULEDRESPONSE_SCHEDULED = _descriptor.Descriptor(name='Scheduled', full_name='eve.achievement.definition.version.api.GetScheduledResponse.Scheduled', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[_descriptor.FieldDescriptor(name='version', full_name='eve.achievement.definition.version.api.GetScheduledResponse.Scheduled.version', index=0, number=1, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor(name='release_timestamp', full_name='eve.achievement.definition.version.api.GetScheduledResponse.Scheduled.release_timestamp', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key)], extensions=[], nested_types=[], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[], serialized_start=438, serialized_end=557) -_GETSCHEDULEDRESPONSE = _descriptor.Descriptor(name='GetScheduledResponse', full_name='eve.achievement.definition.version.api.GetScheduledResponse', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[_descriptor.FieldDescriptor(name='scheduled_version', full_name='eve.achievement.definition.version.api.GetScheduledResponse.scheduled_version', index=0, number=1, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor(name='no_scheduled_version', full_name='eve.achievement.definition.version.api.GetScheduledResponse.no_scheduled_version', index=1, number=2, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key)], extensions=[], nested_types=[_GETSCHEDULEDRESPONSE_SCHEDULED], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[_descriptor.OneofDescriptor(name='scheduled', full_name='eve.achievement.definition.version.api.GetScheduledResponse.scheduled', index=0, containing_type=None, create_key=_descriptor._internal_create_key, fields=[])], serialized_start=281, serialized_end=570) -_GETDEFAULTVERSIONREQUEST = _descriptor.Descriptor(name='GetDefaultVersionRequest', full_name='eve.achievement.definition.version.api.GetDefaultVersionRequest', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[], extensions=[], nested_types=[], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[], serialized_start=572, serialized_end=598) -_GETDEFAULTVERSIONRESPONSE = _descriptor.Descriptor(name='GetDefaultVersionResponse', full_name='eve.achievement.definition.version.api.GetDefaultVersionResponse', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[_descriptor.FieldDescriptor(name='version', full_name='eve.achievement.definition.version.api.GetDefaultVersionResponse.version', index=0, number=1, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key)], extensions=[], nested_types=[], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[], serialized_start=600, serialized_end=680) -_GETTENANTVERSIONREQUEST = _descriptor.Descriptor(name='GetTenantVersionRequest', full_name='eve.achievement.definition.version.api.GetTenantVersionRequest', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[], extensions=[], nested_types=[], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[], serialized_start=682, serialized_end=707) -_GETTENANTVERSIONRESPONSE = _descriptor.Descriptor(name='GetTenantVersionResponse', full_name='eve.achievement.definition.version.api.GetTenantVersionResponse', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[_descriptor.FieldDescriptor(name='version', full_name='eve.achievement.definition.version.api.GetTenantVersionResponse.version', index=0, number=1, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key)], extensions=[], nested_types=[], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[], serialized_start=709, serialized_end=788) -_LISTTENANTOVERRIDESREQUEST = _descriptor.Descriptor(name='ListTenantOverridesRequest', full_name='eve.achievement.definition.version.api.ListTenantOverridesRequest', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[_descriptor.FieldDescriptor(name='page', full_name='eve.achievement.definition.version.api.ListTenantOverridesRequest.page', index=0, number=1, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key)], extensions=[], nested_types=[], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[], serialized_start=790, serialized_end=843) -_LISTTENANTOVERRIDESRESPONSE_TENANTOVERRIDE = _descriptor.Descriptor(name='TenantOverride', full_name='eve.achievement.definition.version.api.ListTenantOverridesResponse.TenantOverride', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[_descriptor.FieldDescriptor(name='tenant', full_name='eve.achievement.definition.version.api.ListTenantOverridesResponse.TenantOverride.tenant', index=0, number=1, type=9, cpp_type=9, label=1, has_default_value=False, default_value=''.decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor(name='version', full_name='eve.achievement.definition.version.api.ListTenantOverridesResponse.TenantOverride.version', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor(name='update_time', full_name='eve.achievement.definition.version.api.ListTenantOverridesResponse.TenantOverride.update_time', index=2, number=3, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key)], extensions=[], nested_types=[], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[], serialized_start=1015, serialized_end=1149) -_LISTTENANTOVERRIDESRESPONSE = _descriptor.Descriptor(name='ListTenantOverridesResponse', full_name='eve.achievement.definition.version.api.ListTenantOverridesResponse', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[_descriptor.FieldDescriptor(name='overrides', full_name='eve.achievement.definition.version.api.ListTenantOverridesResponse.overrides', index=0, number=1, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor(name='next_page', full_name='eve.achievement.definition.version.api.ListTenantOverridesResponse.next_page', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key)], extensions=[], nested_types=[_LISTTENANTOVERRIDESRESPONSE_TENANTOVERRIDE], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[], serialized_start=846, serialized_end=1149) +DESCRIPTOR = _descriptor.FileDescriptor(name='eve/achievement/definition/version/api/requests.proto', package='eve.achievement.definition.version.api', syntax='proto3', serialized_options='ZQgithub.com/ccpgames/eve-proto-go/generated/eve/achievement/definition/version/api', create_key=_descriptor._internal_create_key, serialized_pb='\n5eve/achievement/definition/version/api/requests.proto\x12&eve.achievement.definition.version.api\x1a\reve/eve.proto\x1a\x1ceve/quasar/admin/admin.proto\x1a\x19eve/semanticversion.proto\x1a\x1fgoogle/protobuf/timestamp.proto"\r\n\x0bListRequest"D\n\x0cListResponse\x124\n\x08versions\x18\x01 \x03(\x0b2".eve.semanticversion.Specification"\x15\n\x13GetScheduledRequest"\xa1\x02\n\x14GetScheduledResponse\x12c\n\x11scheduled_version\x18\x01 \x01(\x0b2F.eve.achievement.definition.version.api.GetScheduledResponse.ScheduledH\x00\x12\x1e\n\x14no_scheduled_version\x18\x02 \x01(\x08H\x00\x1aw\n\tScheduled\x123\n\x07version\x18\x01 \x01(\x0b2".eve.semanticversion.Specification\x125\n\x11release_timestamp\x18\x02 \x01(\x0b2\x1a.google.protobuf.TimestampB\x0b\n\tscheduled"\x1a\n\x18GetDefaultVersionRequest"P\n\x19GetDefaultVersionResponse\x123\n\x07version\x18\x01 \x01(\x0b2".eve.semanticversion.Specification"\x19\n\x17GetTenantVersionRequest"O\n\x18GetTenantVersionResponse\x123\n\x07version\x18\x01 \x01(\x0b2".eve.semanticversion.Specification"5\n\x1aListTenantOverridesRequest\x12\x17\n\x04page\x18\x01 \x01(\x0b2\t.eve.Page"\xe1\x02\n\x1bListTenantOverridesResponse\x12e\n\toverrides\x18\x01 \x03(\x0b2R.eve.achievement.definition.version.api.ListTenantOverridesResponse.TenantOverride\x12 \n\tnext_page\x18\x02 \x01(\x0b2\r.eve.NextPage\x1a\xb8\x01\n\x0eTenantOverride\x12\x0e\n\x06tenant\x18\x01 \x01(\t\x123\n\x07version\x18\x02 \x01(\x0b2".eve.semanticversion.Specification\x12/\n\x0bupdate_time\x18\x03 \x01(\x0b2\x1a.google.protobuf.Timestamp\x120\n\radmin_context\x18\x04 \x01(\x0b2\x19.eve.quasar.admin.ContextBSZQgithub.com/ccpgames/eve-proto-go/generated/eve/achievement/definition/version/apib\x06proto3', dependencies=[eve_dot_eve__pb2.DESCRIPTOR, + eve_dot_quasar_dot_admin_dot_admin__pb2.DESCRIPTOR, + eve_dot_semanticversion__pb2.DESCRIPTOR, + google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR]) +_LISTREQUEST = _descriptor.Descriptor(name='ListRequest', full_name='eve.achievement.definition.version.api.ListRequest', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[], extensions=[], nested_types=[], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[], serialized_start=202, serialized_end=215) +_LISTRESPONSE = _descriptor.Descriptor(name='ListResponse', full_name='eve.achievement.definition.version.api.ListResponse', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[_descriptor.FieldDescriptor(name='versions', full_name='eve.achievement.definition.version.api.ListResponse.versions', index=0, number=1, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key)], extensions=[], nested_types=[], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[], serialized_start=217, serialized_end=285) +_GETSCHEDULEDREQUEST = _descriptor.Descriptor(name='GetScheduledRequest', full_name='eve.achievement.definition.version.api.GetScheduledRequest', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[], extensions=[], nested_types=[], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[], serialized_start=287, serialized_end=308) +_GETSCHEDULEDRESPONSE_SCHEDULED = _descriptor.Descriptor(name='Scheduled', full_name='eve.achievement.definition.version.api.GetScheduledResponse.Scheduled', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[_descriptor.FieldDescriptor(name='version', full_name='eve.achievement.definition.version.api.GetScheduledResponse.Scheduled.version', index=0, number=1, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor(name='release_timestamp', full_name='eve.achievement.definition.version.api.GetScheduledResponse.Scheduled.release_timestamp', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key)], extensions=[], nested_types=[], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[], serialized_start=468, serialized_end=587) +_GETSCHEDULEDRESPONSE = _descriptor.Descriptor(name='GetScheduledResponse', full_name='eve.achievement.definition.version.api.GetScheduledResponse', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[_descriptor.FieldDescriptor(name='scheduled_version', full_name='eve.achievement.definition.version.api.GetScheduledResponse.scheduled_version', index=0, number=1, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor(name='no_scheduled_version', full_name='eve.achievement.definition.version.api.GetScheduledResponse.no_scheduled_version', index=1, number=2, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key)], extensions=[], nested_types=[_GETSCHEDULEDRESPONSE_SCHEDULED], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[_descriptor.OneofDescriptor(name='scheduled', full_name='eve.achievement.definition.version.api.GetScheduledResponse.scheduled', index=0, containing_type=None, create_key=_descriptor._internal_create_key, fields=[])], serialized_start=311, serialized_end=600) +_GETDEFAULTVERSIONREQUEST = _descriptor.Descriptor(name='GetDefaultVersionRequest', full_name='eve.achievement.definition.version.api.GetDefaultVersionRequest', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[], extensions=[], nested_types=[], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[], serialized_start=602, serialized_end=628) +_GETDEFAULTVERSIONRESPONSE = _descriptor.Descriptor(name='GetDefaultVersionResponse', full_name='eve.achievement.definition.version.api.GetDefaultVersionResponse', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[_descriptor.FieldDescriptor(name='version', full_name='eve.achievement.definition.version.api.GetDefaultVersionResponse.version', index=0, number=1, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key)], extensions=[], nested_types=[], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[], serialized_start=630, serialized_end=710) +_GETTENANTVERSIONREQUEST = _descriptor.Descriptor(name='GetTenantVersionRequest', full_name='eve.achievement.definition.version.api.GetTenantVersionRequest', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[], extensions=[], nested_types=[], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[], serialized_start=712, serialized_end=737) +_GETTENANTVERSIONRESPONSE = _descriptor.Descriptor(name='GetTenantVersionResponse', full_name='eve.achievement.definition.version.api.GetTenantVersionResponse', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[_descriptor.FieldDescriptor(name='version', full_name='eve.achievement.definition.version.api.GetTenantVersionResponse.version', index=0, number=1, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key)], extensions=[], nested_types=[], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[], serialized_start=739, serialized_end=818) +_LISTTENANTOVERRIDESREQUEST = _descriptor.Descriptor(name='ListTenantOverridesRequest', full_name='eve.achievement.definition.version.api.ListTenantOverridesRequest', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[_descriptor.FieldDescriptor(name='page', full_name='eve.achievement.definition.version.api.ListTenantOverridesRequest.page', index=0, number=1, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key)], extensions=[], nested_types=[], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[], serialized_start=820, serialized_end=873) +_LISTTENANTOVERRIDESRESPONSE_TENANTOVERRIDE = _descriptor.Descriptor(name='TenantOverride', full_name='eve.achievement.definition.version.api.ListTenantOverridesResponse.TenantOverride', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[_descriptor.FieldDescriptor(name='tenant', full_name='eve.achievement.definition.version.api.ListTenantOverridesResponse.TenantOverride.tenant', index=0, number=1, type=9, cpp_type=9, label=1, has_default_value=False, default_value=''.decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor(name='version', full_name='eve.achievement.definition.version.api.ListTenantOverridesResponse.TenantOverride.version', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor(name='update_time', full_name='eve.achievement.definition.version.api.ListTenantOverridesResponse.TenantOverride.update_time', index=2, number=3, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor(name='admin_context', full_name='eve.achievement.definition.version.api.ListTenantOverridesResponse.TenantOverride.admin_context', index=3, number=4, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key)], extensions=[], nested_types=[], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[], serialized_start=1045, serialized_end=1229) +_LISTTENANTOVERRIDESRESPONSE = _descriptor.Descriptor(name='ListTenantOverridesResponse', full_name='eve.achievement.definition.version.api.ListTenantOverridesResponse', filename=None, file=DESCRIPTOR, containing_type=None, create_key=_descriptor._internal_create_key, fields=[_descriptor.FieldDescriptor(name='overrides', full_name='eve.achievement.definition.version.api.ListTenantOverridesResponse.overrides', index=0, number=1, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor(name='next_page', full_name='eve.achievement.definition.version.api.ListTenantOverridesResponse.next_page', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key)], extensions=[], nested_types=[_LISTTENANTOVERRIDESRESPONSE_TENANTOVERRIDE], enum_types=[], serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[], serialized_start=876, serialized_end=1229) _LISTRESPONSE.fields_by_name['versions'].message_type = eve_dot_semanticversion__pb2._SPECIFICATION _GETSCHEDULEDRESPONSE_SCHEDULED.fields_by_name['version'].message_type = eve_dot_semanticversion__pb2._SPECIFICATION _GETSCHEDULEDRESPONSE_SCHEDULED.fields_by_name['release_timestamp'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP @@ -34,6 +41,7 @@ _GETTENANTVERSIONRESPONSE.fields_by_name['version'].message_type = eve_dot_seman _LISTTENANTOVERRIDESREQUEST.fields_by_name['page'].message_type = eve_dot_eve__pb2._PAGE _LISTTENANTOVERRIDESRESPONSE_TENANTOVERRIDE.fields_by_name['version'].message_type = eve_dot_semanticversion__pb2._SPECIFICATION _LISTTENANTOVERRIDESRESPONSE_TENANTOVERRIDE.fields_by_name['update_time'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP +_LISTTENANTOVERRIDESRESPONSE_TENANTOVERRIDE.fields_by_name['admin_context'].message_type = eve_dot_quasar_dot_admin_dot_admin__pb2._CONTEXT _LISTTENANTOVERRIDESRESPONSE_TENANTOVERRIDE.containing_type = _LISTTENANTOVERRIDESRESPONSE _LISTTENANTOVERRIDESRESPONSE.fields_by_name['overrides'].message_type = _LISTTENANTOVERRIDESRESPONSE_TENANTOVERRIDE _LISTTENANTOVERRIDESRESPONSE.fields_by_name['next_page'].message_type = eve_dot_eve__pb2._NEXTPAGE diff --git a/eveSpaceObject/__init__.py b/eveSpaceObject/__init__.py @@ -73,6 +73,7 @@ droneGroupFromTypeGroup = {const.groupMiningDrone: gfxDroneGroupMining, const.groupWarpScramblingDrone: gfxDroneGroupCombat, const.groupCapDrainDrone: gfxDroneGroupCombat, const.groupLogisticDrone: gfxDroneGroupCombat, + const.groupHybridDrone: gfxDroneGroupCombat, const.groupSupportFighter: gfxDroneGroupCombat, const.groupLCODrone: gfxDroneGroupNpc, const.groupRogueDrone: gfxDroneGroupNpc, diff --git a/eveSpaceObject/spaceobjaudio.py b/eveSpaceObject/spaceobjaudio.py @@ -48,6 +48,7 @@ def GetBoosterSizeStr(groupID): const.groupStasisWebifyingDrone: 'd', const.groupUnanchoringDrone: 'd', const.groupWarpScramblingDrone: 'd', + const.groupHybridDrone: 'd', const.groupSupportFighter: 'fs', const.groupLightFighter: 'fs', const.groupHeavyFighter: 'fs', diff --git a/evelink/client/handlers/show_info/link.py b/evelink/client/handlers/show_info/link.py @@ -30,8 +30,8 @@ def category_link(category_id = None, link_text = None, hint = None, header_text return Link(url=format_category_id_url(category_id, header_text=header_text), text=link_text, alt=hint) -def type_list_link(type_list_id = None, link_text = None, hint = None, header_text = None): - return Link(url=format_type_list_url(type_list_id, header_text=header_text), text=link_text, alt=hint) +def type_list_link(type_list_id = None, link_text = None, hint = None, header_text = None, window_caption = None): + return Link(url=format_type_list_url(type_list_id, header_text=header_text, window_caption=window_caption), text=link_text, alt=hint) def ship_link(type_id, item_id = None, owner_id = None, item_name = None, hint = None): diff --git a/evewar/const.py b/evewar/const.py @@ -6,7 +6,7 @@ warRelationshipYourAlliance = 2 warRelationshipAtWar = 3 warRelationshipAtWarCanFight = 4 warRelationshipAlliesAtWar = 5 -COST_OF_WAR = 100000000 +COST_OF_WAR = 500000000 BILLING_PERIOD = WEEK WAR_NEGOTIATION_TYPE_ALLY_OFFER = 0 WAR_NEGOTIATION_TYPE_SURRENDER_OFFER = 2 diff --git a/freelanceprojects/client/mock/mock_project_draft.py b/freelanceprojects/client/mock/mock_project_draft.py @@ -6,6 +6,7 @@ from datetimeutils import datetime_to_filetime from freelanceprojects.client.contributionmethods.mock.data import configurations as mock_configurations from freelanceprojects.client.data.creation_costs import CreationCost, CreationPrices from freelanceprojects.client.data.project_draft import ProjectDraft +from math import ceil MOCK_BASE_FEE_PER_DAY = 75000 MOCK_BROADCASTING_FEE_PER_DAY_PER_LOCATION = 100000 @@ -21,9 +22,24 @@ MOCK_PROJECT_DRAFT_CAPTURE_FW_COMPLEX = ProjectDraft(name='Capture some FW compl MOCK_PROJECT_DRAFT_DEFEND_FW_COMPLEX = ProjectDraft(name='Defend our FW complexes', description='Defend them all for the glory of our corporation', career_path=career_path_enforcer, target_progress=2, contribution_method_configuration=mock_configurations.MOCK_DEFEND_FW_COMPLEX, end_time=datetime_to_filetime(datetime.now() + timedelta(days=7)), broadcast_locations=set(), payout_per_unit=100, expected_cost=_get_mock_creation_cost(rewards=200, days=7, number_of_locations=0), max_committed_participants=5, access_list=None) MOCK_PROJECT_DRAFT_KILL_NPC = ProjectDraft(name='Exterminate NPCs', description='They are stealing our fedos', career_path=career_path_enforcer, target_progress=20, contribution_method_configuration=mock_configurations.MOCK_KILL_NPC, end_time=datetime_to_filetime(datetime.now() + timedelta(days=7)), broadcast_locations=set(), payout_per_unit=10, expected_cost=_get_mock_creation_cost(rewards=200, days=7, number_of_locations=0), max_committed_participants=5, access_list=None) MOCK_PROJECT_DRAFT_DAMAGE_SHIP = ProjectDraft(name='Damage our enemies', description="Their ships look better than ours so let's fix that", career_path=career_path_soldier_of_fortune, target_progress=10000, contribution_method_configuration=mock_configurations.MOCK_DAMAGE_SHIP, end_time=datetime_to_filetime(datetime.now() + timedelta(days=7)), broadcast_locations=set(), payout_per_unit=1, expected_cost=_get_mock_creation_cost(rewards=10000, days=7, number_of_locations=0), max_committed_participants=20, access_list=None) -MOCK_PROJECT_DRAFT_DAMAGE_SHIP_1_HOUR_DURATION = ProjectDraft(name='Damage our enemies', description="Their ships look better than ours so let's fix that", career_path=career_path_soldier_of_fortune, target_progress=10000, contribution_method_configuration=mock_configurations.MOCK_DAMAGE_SHIP, end_time=datetime_to_filetime(datetime.now() + timedelta(hours=1)), broadcast_locations=set(), payout_per_unit=1, expected_cost=_get_mock_creation_cost(rewards=10000, days=1, number_of_locations=0), max_committed_participants=20, access_list=None) -MOCK_PROJECT_DRAFT_DAMAGE_SHIP_16_MIN_DURATION = ProjectDraft(name='Damage our enemies', description="Their ships look better than ours so let's fix that", career_path=career_path_soldier_of_fortune, target_progress=10000, contribution_method_configuration=mock_configurations.MOCK_DAMAGE_SHIP, end_time=datetime_to_filetime(datetime.now() + timedelta(minutes=16)), broadcast_locations=set(), payout_per_unit=1, expected_cost=_get_mock_creation_cost(rewards=10000, days=1, number_of_locations=0), max_committed_participants=20, access_list=None) -MOCK_PROJECT_DRAFT_DAMAGE_SHIP_4_MIN_DURATION = ProjectDraft(name='Damage our enemies', description="Their ships look better than ours so let's fix that", career_path=career_path_soldier_of_fortune, target_progress=10000, contribution_method_configuration=mock_configurations.MOCK_DAMAGE_SHIP, end_time=datetime_to_filetime(datetime.now() + timedelta(minutes=4)), broadcast_locations=set(), payout_per_unit=1, expected_cost=_get_mock_creation_cost(rewards=10000, days=1, number_of_locations=0), max_committed_participants=20, access_list=None) + +def _make_damage_ship_draft(duration): + billed_days = max(1, int(ceil(duration.total_seconds() / 86400.0))) + return ProjectDraft(name='Damage our enemies', description="Their ships look better than ours so let's fix that", career_path=career_path_soldier_of_fortune, target_progress=10000, contribution_method_configuration=mock_configurations.MOCK_DAMAGE_SHIP, end_time=datetime_to_filetime(datetime.now() + duration), broadcast_locations=set(), payout_per_unit=1, expected_cost=_get_mock_creation_cost(rewards=10000, days=billed_days, number_of_locations=0), max_committed_participants=20, access_list=None) + + +def MOCK_PROJECT_DRAFT_DAMAGE_SHIP_1_HOUR_DURATION(): + return _make_damage_ship_draft(timedelta(hours=1)) + + +def MOCK_PROJECT_DRAFT_DAMAGE_SHIP_16_MIN_DURATION(): + return _make_damage_ship_draft(timedelta(minutes=16)) + + +def MOCK_PROJECT_DRAFT_DAMAGE_SHIP_4_MIN_DURATION(): + return _make_damage_ship_draft(timedelta(minutes=4)) + + MOCK_PROJECT_DRAFT_SHIP_INSURANCE = ProjectDraft(name='Die and we refund your ship', description='This is not a pyramid scheme', career_path=career_path_soldier_of_fortune, target_progress=100000000, contribution_method_configuration=mock_configurations.MOCK_SHIP_INSURANCE, end_time=datetime_to_filetime(datetime.now() + timedelta(days=7)), broadcast_locations=set(), payout_per_unit=1, expected_cost=_get_mock_creation_cost(rewards=100000000, days=7, number_of_locations=0), max_committed_participants=20, max_contributions_per_participant=40000000, max_progress_per_contribution=10000000, contribution_multiplier=200, access_list=None) MOCK_PROJECT_DRAFT_0_AGE_RESTRICTIONS = deepcopy(MOCK_PROJECT_DRAFT_SHIP_INSURANCE) MOCK_PROJECT_DRAFT_0_AGE_RESTRICTIONS.min_character_age = 0 diff --git a/inventorycommon/const.py b/inventorycommon/const.py @@ -633,6 +633,7 @@ groupHeavyAssaultCruiser = 358 groupHomefrontOperationsHauler = 4577 groupHullRepairUnit = 63 groupHybridAmmo = 85 +groupHybridDrone = 5239 groupHybridWeapon = 74 groupHybridTechComponents = 964 groupIce = 465 diff --git a/jumpbridge/__init__.py b/jumpbridge/__init__.py @@ -0,0 +1,2 @@ +#Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\jumpbridge\__init__.py +pass diff --git a/jumpbridge/client/__init__.py b/jumpbridge/client/__init__.py @@ -0,0 +1,2 @@ +#Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\jumpbridge\client\__init__.py +pass diff --git a/jumpbridge/client/jumpBridge.py b/jumpbridge/client/jumpBridge.py @@ -0,0 +1,128 @@ +#Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\jumpbridge\client\jumpBridge.py +import evetypes +from appConst import maxStargateJumpingDistance +from carbonui.control.contextMenu.menuData import MenuData +from eveexceptions import UserError +from evelink.client.handlers.show_info.link import type_list_link +from jumpbridge.client.validation_rules import validate_ship_type +from jumpbridge.common.slim_item_serialization import parse_slim_value +from logging import getLogger +from spacecomponents import Component +from spacecomponents.client import MSG_ON_ADDED_TO_SPACE, MSG_ON_SLIM_ITEM_UPDATED, MSG_ON_REMOVED_FROM_SPACE +from spacecomponents.client.ui.jumpbridge.jumpBridgeCont import JumpBridgeCont +from spacecomponents.common import componentConst +from spacecomponents.common.componentConst import JUMP_BRIDGE +if False: + from typing import Optional +logger = getLogger('jump_bridge') + +class JumpBridge(Component): + + def __init__(self, itemID, typeID, attributes, componentRegistry): + Component.__init__(self, itemID, typeID, attributes, componentRegistry) + self._bracket_ui = None + self._excludedShipsList = evetypes.GetTypeIDsByListID(attributes.restrictionTypeList) + self._zoneMultipliers = [attributes.zone1Modifier, + attributes.zone2Modifier, + attributes.zone3Modifier, + attributes.zone4Modifier, + attributes.zone5Modifier] + self._lastETag = 0 + self._lastActivationState = None + self.SubscribeToMessage(MSG_ON_ADDED_TO_SPACE, self._OnAddedToSpace) + self.SubscribeToMessage(MSG_ON_REMOVED_FROM_SPACE, self._OnRemovedFromSpace) + self.SubscribeToMessage(MSG_ON_SLIM_ITEM_UPDATED, self._OnSlimItemUpdate) + + @property + def zoneMultipliers(self): + return self._zoneMultipliers + + def _OnAddedToSpace(self, slimItem): + logger.debug('JumpBridge._OnAddedToSpace [%s]', self.itemID) + self._ballpark = sm.GetService('michelle').GetBallpark() + self._OnSlimItemUpdate(slimItem) + if self._bracket_ui is None: + from spacecomponents.client.ui.jumpbridge.bracket import JumpBridgeBracket + self._bracket_ui = JumpBridgeBracket(item_id=slimItem.itemID, type_id=slimItem.typeID, content_class=JumpBridgeCont) + + def _OnRemovedFromSpace(self): + if self._bracket_ui: + self._bracket_ui.close() + self._bracket_ui = None + + def _OnSlimItemUpdate(self, slimItem): + if slimItem.component_jumpBridge is not None: + new_etag = parse_slim_value(slimItem.component_jumpBridge) + if new_etag != self._lastETag: + self._OnETagChanged() + self._lastETag = new_etag + if slimItem.activationState is not None: + newActivationState = slimItem.activationState + if newActivationState != self._lastActivationState: + self._OnActivationStateChanged() + self._lastActivationState = newActivationState + + def _OnETagChanged(self): + sm.ScatterEvent('OnJumpBridgeChargeChanged') + + def _OnActivationStateChanged(self): + sm.ScatterEvent('OnJumpBridgeActivationChanged') + + def IsAccessibleByShip(self, shipTypeID): + logger.debug('JumpBridge.IsAccessibleByShip [%s] %s', self.itemID, shipTypeID) + if not self._ValidateShipType(shipTypeID): + return False + return True + + def ValidateJumpAttempt(self, shipItemID, shipTypeID): + logger.debug('JumpBridge.ValidateJumpAttempt [%s] %s, %s', self.itemID, shipItemID, shipTypeID) + if not self._ValidateShipType(shipTypeID): + raise UserError('JumpBridgeRestrictedShip', {'shipName': evetypes.GetName(shipTypeID)}) + if self._ballpark.DistanceBetween(shipItemID, self.itemID) > maxStargateJumpingDistance: + raise UserError('NotCloseEnoughToJump', {'maxdist': maxStargateJumpingDistance}) + + def _ValidateShipType(self, shipTypeID): + return validate_ship_type(shipTypeID, self._excludedShipsList) + + def GetGMMenu(self): + menu_data = MenuData() + return menu_data + + @staticmethod + def GetAttributeInfo(typeID, attributes, instance, localization): + from eve.client.script.ui.control.entries.header import Header + from eve.client.script.ui.control.entries.label_text import LabelTextSides + from spacecomponents.client.display import EntryData + listTitle = evetypes.GetTypeListDisplayName(attributes.restrictionTypeList) + attributeEntries = [EntryData(Header, localization.GetByLabel('UI/Inflight/SpaceComponents/JumpBridge/InfoAttributesHeader')), + EntryData(LabelTextSides, localization.GetByLabel('UI/Inflight/SpaceComponents/JumpBridge/ShipRestrictions'), type_list_link(attributes.restrictionTypeList, listTitle, header_text=listTitle, window_caption=listTitle)), + EntryData(LabelTextSides, localization.GetByLabel('UI/Inflight/SpaceComponents/JumpBridge/Zone1Modifier'), attributes.zone1Modifier), + EntryData(LabelTextSides, localization.GetByLabel('UI/Inflight/SpaceComponents/JumpBridge/Zone2Modifier'), attributes.zone2Modifier), + EntryData(LabelTextSides, localization.GetByLabel('UI/Inflight/SpaceComponents/JumpBridge/Zone3Modifier'), attributes.zone3Modifier), + EntryData(LabelTextSides, localization.GetByLabel('UI/Inflight/SpaceComponents/JumpBridge/Zone4Modifier'), attributes.zone4Modifier), + EntryData(LabelTextSides, localization.GetByLabel('UI/Inflight/SpaceComponents/JumpBridge/Zone5Modifier'), attributes.zone5Modifier)] + return attributeEntries + + def ReloadUI(self): + if self._bracket_ui: + self._bracket_ui.close() + self._bracket_ui = None + slimItem = sm.GetService('michelle').GetItem(self.itemID) + from spacecomponents.client.ui.jumpbridge.bracket import JumpBridgeBracket + self._bracket_ui = JumpBridgeBracket(item_id=slimItem.itemID, type_id=slimItem.typeID, content_class=JumpBridgeCont) + + +def GetJumpBridgeComponent(ballpark, structureID): + logger.debug('GetJumpBridgeComponent [%s]', structureID) + try: + jumpBridgeComponent = ballpark.componentRegistry.GetComponentForItem(structureID, componentConst.JUMP_BRIDGE) + except KeyError: + return False + + return jumpBridgeComponent + + +def GetJumpBridgeInfo(michelleService, structureID): + logger.debug('GetJumpBridgeInfo [%s]', structureID) + remoteBallpark = michelleService.GetRemotePark() + return remoteBallpark.CallComponentFromClient(structureID, JUMP_BRIDGE, 'GetJumpBridgeInfo') diff --git a/jumpbridge/client/validation_rules.py b/jumpbridge/client/validation_rules.py @@ -0,0 +1,9 @@ +#Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\jumpbridge\client\validation_rules.py + + +def validate_ship_type(ship_type_id, exclusion_typelist): + if ship_type_id is None: + return False + if ship_type_id in exclusion_typelist: + return False + return True diff --git a/jumpbridge/common/__init__.py b/jumpbridge/common/__init__.py @@ -0,0 +1,2 @@ +#Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\jumpbridge\common\__init__.py +pass diff --git a/jumpbridge/common/jump_bridge_authorized_info.py b/jumpbridge/common/jump_bridge_authorized_info.py @@ -0,0 +1,21 @@ +#Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\jumpbridge\common\jump_bridge_authorized_info.py +import gametime + +class JumpBridgeAuthorizedInfo(object): + + def __init__(self, valid_ship_type, structure_capacitor): + self._valid_ship_type = valid_ship_type + self._structure_capacitor = structure_capacitor + self._sim_timestamp = gametime.GetSimTime() + + @property + def valid_ship_type(self): + return self._valid_ship_type + + @property + def structure_capacitor(self): + return self._structure_capacitor + + @property + def sim_timestamp(self): + return self._sim_timestamp diff --git a/jumpbridge/common/slim_item_serialization.py b/jumpbridge/common/slim_item_serialization.py @@ -0,0 +1,11 @@ +#Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\jumpbridge\common\slim_item_serialization.py + + +def create_slim_value(etag): + slimValue = etag + return slimValue + + +def parse_slim_value(slimValue): + etag = slimValue + return etag diff --git a/jumpbridge/common/zone_modifier_util.py b/jumpbridge/common/zone_modifier_util.py @@ -0,0 +1,41 @@ +#Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\jumpbridge\common\zone_modifier_util.py +import eveuniverse +import logging +logger = logging.getLogger('jump_bridge') +ZONE_DISTANCE_INFINITY_SENTINEL = -1 +ZONE_ONE = 5 +ZONE_TWO = 10 +ZONE_THREE = 15 +ZONE_FOUR = 20 +ZONE_FIVE = ZONE_DISTANCE_INFINITY_SENTINEL +ZONE_DISTANCES = [ZONE_ONE, + ZONE_TWO, + ZONE_THREE, + ZONE_FOUR, + ZONE_FIVE] + +def GetCapacitorZoneModifierAndIdx(capitalSolarSystemID, destinationSolarsystemID, zoneMultipliers): + if capitalSolarSystemID is not None: + lightYears = eveuniverse.solar_systems.GetLightYearDistance(destinationSolarsystemID, capitalSolarSystemID) + zoneIndex = _GetZoneIndexFromLYDistance(lightYears) + else: + zoneIndex = len(ZONE_DISTANCES) - 1 + lightYears = None + multiplier = _GetMultiplierFromAttributes(zoneIndex, zoneMultipliers) + logger.info('JumpBridge._GetCapacitorZoneModifier %s, %s, %s', lightYears, zoneIndex, multiplier) + return (multiplier, zoneIndex) + + +def _GetZoneIndexFromLYDistance(lightYears): + for index, distance in enumerate(ZONE_DISTANCES): + if distance == ZONE_DISTANCE_INFINITY_SENTINEL: + return index + if lightYears > distance: + continue + return index + + +def _GetMultiplierFromAttributes(zoneIndex, zoneMultipliers): + if zoneIndex is None or zoneIndex < 0 or zoneIndex >= len(zoneMultipliers): + raise AttributeError('zoneIndex out of range') + return zoneMultipliers[zoneIndex] diff --git a/menucheckers/celestialCheckers.py b/menucheckers/celestialCheckers.py @@ -17,7 +17,7 @@ from menucheckers.decorators import decorated_checker, explain_failure_with, nee from eve.common.script.sys import idCheckers from eve.common.script.sys.idCheckers import IsDeprecatedStation, IsNPC, IsStation, IsCharacter, IsSolarSystem, IsTriglavianSystem from brennivin.itertoolsext import Bundle -from spacecomponents.common.helper import HasItemTrader, HasScoopComponent, IsActiveComponent, HasCargoBayComponent, HasMicroJumpDriverComponent, HasLinkWithShipComponent, HasUnderConstructionComponent, HasTowGameObjectiveComponent, HasPhaseStabilizerComponent +from spacecomponents.common.helper import HasItemTrader, HasScoopComponent, IsActiveComponent, HasCargoBayComponent, HasMicroJumpDriverComponent, HasLinkWithShipComponent, HasUnderConstructionComponent, HasTowGameObjectiveComponent, HasPhaseStabilizerComponent, HasJumpBridgeComponent from spacecomponents.common.components.fitting import IsShipWithinFittingRange, HasFittingComponent from spacecomponents.common.components.bookmark import IsTypeBookmarkable from eve.client.script.parklife.states import gbEnemySpotted, selectedForNavigation @@ -317,6 +317,11 @@ class CelestialChecker(_BaseItemChecker): return False if not self.IsStructureOnline(): return False + shipItem = self.session.getActiveShipGodmaItem() + from jumpbridge.client import jumpBridge + jumpBridgeComponent = jumpBridge.GetJumpBridgeComponent(self.GetBallpark(), self.item.itemID) + if not jumpBridgeComponent or not jumpBridgeComponent.IsAccessibleByShip(shipItem): + return False return True @needs_ballpark_item @@ -1766,6 +1771,8 @@ class CelestialChecker(_BaseItemChecker): def IsConnectedJumpBridgeStructure(self): if not IsUpwellStargate(self.item.typeID): return False + if not HasJumpBridgeComponent(self.item.typeID): + return False if not getattr(self.item, 'targetSolarsystemID', None): return False return True diff --git a/multiprocessing/pool.pyc b/multiprocessing/pool.pyc Binary files differ. diff --git a/probescanning/const.py b/probescanning/const.py @@ -180,7 +180,8 @@ probeScanGroups[probeScanGroupDrones] = {inventorycommon.const.groupCapDrainDron inventorycommon.const.groupLogisticDrone, inventorycommon.const.groupMiningDrone, inventorycommon.const.groupStasisWebifyingDrone, - inventorycommon.const.groupSalvageDrone} + inventorycommon.const.groupSalvageDrone, + inventorycommon.const.groupHybridDrone} probeScanGroups[probeScanGroupFighters] = {inventorycommon.const.groupLightFighter, inventorycommon.const.groupSupportFighter, inventorycommon.const.groupHeavyFighter, diff --git a/shipfitting/fittingWarningConst.py b/shipfitting/fittingWarningConst.py @@ -95,6 +95,7 @@ GROUPS_AFFECTING_MODULE_GROUPS = {inventoryconst.groupGyrostabilizer: (inventory inventoryconst.groupMagneticFieldStabilizer: (inventoryconst.groupHybridWeapon,), inventoryconst.groupHeatSink: (inventoryconst.groupEnergyWeapon,), inventoryconst.groupDroneDamageAmplifier: (inventoryconst.groupCombatDrone, + inventoryconst.groupHybridDrone, inventoryconst.groupHeavyFighter, inventoryconst.groupLightFighter, inventoryconst.groupStructureLightFighter, diff --git a/spacecomponents/client/factory.py b/spacecomponents/client/factory.py @@ -16,6 +16,7 @@ from spacecomponents.client.components.fwCapturePoint import FWCapturePoint from spacecomponents.client.components.fwScoreboard import FWScoreboard from spacecomponents.client.components.hackingSecurityState import HackingSecurityState from spacecomponents.client.components.hostileBaiter import HostileBaiter +from jumpbridge.client.jumpBridge import JumpBridge from spacecomponents.client.components.linkWithShip import LinkWithShip from spacecomponents.client.components.mercenaryDen import MercenaryDen from spacecomponents.client.components.mineable import Mineable @@ -121,7 +122,8 @@ COMPONENTS = {componentConst.DEPLOY_CLASS: deploy.Deploy, componentConst.BREACH_POINT_ASTEROID: BreachPointAsteroid, componentConst.REORIENTOR: Reorientor, componentConst.COMPANION_MODEL: CompanionModel, - componentConst.STARTER_SHIPCASTER: StarterShipcaster} + componentConst.STARTER_SHIPCASTER: StarterShipcaster, + componentConst.JUMP_BRIDGE: JumpBridge} def GetComponentClass(componentName): return COMPONENTS[componentName] diff --git a/spacecomponents/client/ui/jumpbridge/__init__.py b/spacecomponents/client/ui/jumpbridge/__init__.py @@ -0,0 +1,2 @@ +#Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\spacecomponents\client\ui\jumpbridge\__init__.py +pass diff --git a/spacecomponents/client/ui/jumpbridge/bracket.py b/spacecomponents/client/ui/jumpbridge/bracket.py @@ -0,0 +1,78 @@ +#Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\spacecomponents\client\ui\jumpbridge\bracket.py +import threadutils +from carbon.common.script.sys.serviceManager import ServiceManager +from dynamicresources.client.ess.bracket.camera import InFlightCameraReference +from dynamicresources.client.ess.bracket.state_machine import State +from spacecomponents.client.ui.baseBracket import BaseBracket +from spacecomponents.client.ui.jumpbridge.states import Online +from spacecomponents.client.ui.rootTransformController import RootTransformController + +class JumpBridgeBracket(BaseBracket): + __notifyevents__ = ('OnWarpActive', 'OnClientEvent_WarpFinished', 'OnSessionChanged') + + def __init__(self, item_id, type_id, content_class, panel_name = 'JumpBridgeBracket', offset_y = 5500.0, collapse_at_camera_distance = 150000.0, tether_name = 'jumpbridge_tether', tether_width = 50): + super(JumpBridgeBracket, self).__init__(item_id, type_id) + self._content_class = content_class + self._panel_name = panel_name + self._offset_y = offset_y + self._collapse_at_camera_distance = collapse_at_camera_distance + self._tether_name = tether_name + self._tether_width = tether_width + self._init() + + @property + def content_class(self): + return self._content_class + + @property + def panel_name(self): + return self._panel_name + + @property + def offset_y(self): + return self._offset_y + + @property + def collapse_at_camera_distance(self): + return self._collapse_at_camera_distance + + @property + def tether_name(self): + return self._tether_name + + @property + def tether_width(self): + return self._tether_width + + @threadutils.threaded + def _init(self): + ball = self._wait_for_ball() + scene = self._scene_manager.GetRegisteredScene('default') + self._root = RootTransformController(ball=ball, scene=scene) + self._camera = InFlightCameraReference(self._scene_manager) + self._on_state_changed() + ServiceManager.Instance().RegisterNotify(self) + + def _on_state_changed(self, *_args): + if self._closed: + return + if self._michelle.InWarp(): + self._state_machine.move_to(Hidden()) + elif session.structureid: + self._state_machine.move_to(Hidden()) + else: + self._state_machine.move_to(Online(self)) + + def OnWarpActive(self, _warp_to_item_id, _warp_to_type_id): + self._on_state_changed() + + def OnClientEvent_WarpFinished(self, _warp_to_item_id, _warp_to_type_id): + self._on_state_changed() + + def OnSessionChanged(self, isRemote, sess, change): + if 'shipid' in change: + self._on_state_changed() + + +class Hidden(State): + pass diff --git a/spacecomponents/client/ui/jumpbridge/bracketPanel.py b/spacecomponents/client/ui/jumpbridge/bracketPanel.py @@ -0,0 +1,97 @@ +#Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\spacecomponents\client\ui\jumpbridge\bracketPanel.py +import math +from carbonui import uiconst +from carbonui.primitives.containerAutoSize import ContainerAutoSize +from carbonui.primitives.transform import Transform +from carbonui.uianimations import animations +from dynamicresources.client.ess.bracket.panel import BracketPanel, get_absolute_bounds, Priority +from dynamicresources.client.ess.bracket.state_machine import StateMachine +from dynamicresources.client.ess.bracket.tether import BracketTether +from signals import Signal +from spacecomponents.client.ui.rootTransformController import PanelTransformController + +class JumpBridgePanel(BracketPanel): + + def __init__(self, parent, camera, root_transform, content_class, panel_name, offset_y, collapse_at_camera_distance, tether_name, tether_width, on_focus = None, itemID = None, typeID = None): + self._camera = camera + self._root_transform = root_transform + self._content_class = content_class + self._state_machine = StateMachine() + self._item_id = itemID + self._type_id = typeID + self.playerRequestedCollapseToken = None + self.on_collapse_changed = Signal('on_collapse_changed') + self._panel_transform = PanelTransformController(root=root_transform, camera=camera, offset_y=offset_y) + super(JumpBridgePanel, self).__init__(name=panel_name, transform=self._panel_transform.transform, layer=parent, camera=camera, collapse_at_camera_distance=collapse_at_camera_distance, clipping_dead_zone=50, on_focus=on_focus, collapsed=True) + self._base = ContainerAutoSize(name='%s_base' % panel_name, alignMode=uiconst.CENTERBOTTOM) + self._main_content = ContainerAutoSize(name='_main_content', parent=self._base, align=uiconst.CENTERBOTTOM, alignMode=uiconst.CENTERBOTTOM) + self._content = ContainerAutoSize(name='_content', parent=self._main_content, align=uiconst.CENTERBOTTOM, alignMode=uiconst.TOPLEFT, state=uiconst.UI_DISABLED if self.is_collapsed else uiconst.UI_PICKCHILDREN, left=0, opacity=0.0 if self.is_collapsed else 1.0) + self._content_tracker_token = self.tracker.add(self._base, anchor=(0.5, 0.5), offset=(0, -150)) + tether_cont = Transform(name=tether_name, rotation=math.radians(270.0), width=100, height=100) + tether_cont.rotationCenter = (1.0, 0.5) + tether_inner_cont = Transform(name='tether_inner_cont', parent=tether_cont, rotation=math.radians(180.0), width=tether_cont.width, height=tether_cont.height) + self._tether = BracketTether(parent=tether_inner_cont, align=uiconst.TOPLEFT, collapsed=True, width=tether_width, on_click=self._on_tether_click, on_close_point_click=self._on_close_point_click) + self.tracker.add(tether_cont, anchor=(1.0, 0.5), offset=(35, 0)) + self._on_state_update() + + @property + def item_id(self): + return self._item_id + + @property + def type_id(self): + return self._type_id + + @property + def camera(self): + return self._camera + + @property + def root_transform(self): + return self._root_transform + + @property + def content_class(self): + return self._content_class + + @property + def content_bounds(self): + return get_absolute_bounds(self._main_content) + + @property + def content(self): + return self._content + + def collapse(self, lock = False): + self._main_content.DisableAutoSize() + self._content.state = uiconst.UI_DISABLED + self._tether.collapse(lock=lock) + animations.MorphScalar(self._content, 'top', startVal=self._content.top, endVal=-20, duration=0.2) + animations.FadeOut(self._content, duration=0.2, callback=self._main_content.EnableAutoSize) + self.on_collapse_changed(True) + + def expand(self): + self._tether.expand() + self._content.state = uiconst.UI_PICKCHILDREN + animations.MorphScalar(self._content, 'top', startVal=self._content.top, endVal=0, duration=0.2, timeOffset=0.2, callback=self._main_content.EnableAutoSize) + animations.FadeIn(self._content, duration=0.2, timeOffset=0.2) + self.on_collapse_changed(False) + + def close(self): + self._state_machine.close() + self._base.Close() + self._tether.parent.Close() + self._panel_transform.close() + super(JumpBridgePanel, self).close() + + def _on_state_update(self): + from spacecomponents.client.ui.jumpbridge.states import Idle + self._state_machine.move_to(Idle(self)) + + def _on_tether_click(self): + if self.playerRequestedCollapseToken: + self.playerRequestedCollapseToken.clear() + self.force_expand() + + def _on_close_point_click(self): + self.playerRequestedCollapseToken = self.request_collapse(Priority.control_point) diff --git a/spacecomponents/client/ui/jumpbridge/jumpBridgeCont.py b/spacecomponents/client/ui/jumpbridge/jumpBridgeCont.py @@ -0,0 +1,234 @@ +#Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\spacecomponents\client\ui\jumpbridge\jumpBridgeCont.py +import math +import eveicon +import uthread2 +from carbon.common.script.util.timerstuff import AutoTimer +from carbonui import TextColor, Align, TextAlign, PickState +from carbonui.control.button import Button +from carbonui.primitives.container import Container +from carbonui.primitives.containerAutoSize import ContainerAutoSize +from carbonui.primitives.fill import Fill +from carbonui.primitives.frame import Frame +from carbonui.primitives.layoutGrid import LayoutGrid +from carbonui.primitives.sprite import Sprite +from carbonui.text.styles import TextBody, TextHeadline +from carbonui.uiconst import UI_DISABLED +from eve.client.script.ui import eveColor, eveThemeColor +from eve.client.script.ui.control.gaugeCircular import GaugeCircular +from eve.client.script.ui.eveColor import TUNGSTEN_GREY +from eveexceptions import ExceptionEater +from localization import GetByLabel +from spacecomponents.client.ui.jumpbridge.jumpBridgeContController import JumpBridgeContController, JumpBridgeValuesNoAccess + +class JumpBridgeCont(Container): + default_name = 'jumpBridgeCont' + CONTENT_HEIGHT = 170 + __notifyevents__ = ['OnCapitalSystemChanged', + 'OnSessionChanged', + 'OnJumpBridgeChargeChanged', + 'OnJumpBridgeActivationChanged'] + + def ApplyAttributes(self, attributes): + super(JumpBridgeCont, self).ApplyAttributes(attributes) + self.item_id = attributes.itemID + self.type_id = attributes.typeID + self.panel = attributes.panel + self.jump_bridge_cont_controller = JumpBridgeContController(self.item_id, self.type_id) + self.construct_ui() + sm.RegisterNotify(self) + self._connect_signals() + + def _connect_signals(self): + with ExceptionEater('JumpBridgeCont: Failing to connect signals'): + self.panel.on_collapse_changed.connect(self._on_collapse_changed) + + def _disconnect_signals(self): + with ExceptionEater('JumpBridgeCont: Failing to disconnect signals'): + self.panel.on_collapse_changed.disconnect(self._on_collapse_changed) + + def construct_ui(self): + self._construct_button() + self._construct_center_sprite_cont() + self._construct_top_cont() + self._update_item_id_and_ui() + + def _construct_button(self): + cont = ContainerAutoSize(parent=self, align=Align.TOBOTTOM) + button_grid = LayoutGrid(parent=cont, columns=3, align=Align.CENTER) + button_grid.AddCell(Fill(align=Align.TOPLEFT)) + button_grid.AddCell(Fill(align=Align.TOPLEFT), minWidth=168) + button_grid.AddCell(Fill(align=Align.TOPLEFT)) + button_grid.FillRow() + self._left_btn_sprite = Sprite(parent=button_grid, pos=(0, 4, 147, 24), align=Align.CENTERRIGHT, texturePath='res:/UI/Texture/classes/ShipCaster/shipcasterLeftSide.png', color=TUNGSTEN_GREY, state=UI_DISABLED) + self._button = Button(parent=button_grid, align=Align.CENTER, label=GetByLabel('UI/Inflight/InitiateJump'), func=self.jump) + self._right_btn_sprite = Sprite(parent=button_grid, pos=(0, 4, 147, 24), align=Align.CENTERLEFT, texturePath='res:/UI/Texture/classes/ShipCaster/shipcasterRightSide.png', color=TUNGSTEN_GREY, state=UI_DISABLED) + + def _construct_center_sprite_cont(self): + self.center_sprite_cont = Container(name='center_sprite_cont', parent=self, height=40, align=Align.TOBOTTOM) + self.center_icon_cont = Container(parent=self.center_sprite_cont, align=Align.TOBOTTOM, height=40) + Sprite(parent=self.center_icon_cont, pos=(0, 0, 204, 66), align=Align.CENTERTOP, texturePath='res:/UI/Texture/classes/ShipCaster/shipcasterCenter.png', color=TUNGSTEN_GREY, state=UI_DISABLED) + Sprite(parent=self.center_icon_cont, pos=(0, 0, 26, 26), align=Align.CENTERTOP, texturePath='res:/UI/Texture/classes/ShipCaster/shipcasterCenterIcon.png', state=UI_DISABLED) + sweep_angle = 2 * math.pi * 0.21 + start_angle = -math.pi / 2 - sweep_angle / 2 + self.gauge = GaugeWithRed(parent=self.center_sprite_cont, showMarker=False, radius=118, lineWidth=4.0, startAngle=start_angle, angle=sweep_angle, align=Align.CENTERTOP, pickState=PickState.OFF) + + def _construct_top_cont(self): + top_cont = Container(name='top_cont', parent=self, align=Align.TOBOTTOM, height=70, top=32) + self.cost_label_cont = ContainerAutoSize(parent=top_cont, align=Align.TOBOTTOM) + cost_grid = LayoutGrid(parent=self.cost_label_cont, align=Align.CENTER, margin=8, cellSpacing=(8, 0)) + self.warning_sprite = Sprite(parent=cost_grid, align=Align.CENTER, pos=(0, 0, 16, 16), texturePath=eveicon.difficulty, opacity=TextColor.SECONDARY.opacity) + self.warning_sprite.Hide() + self.cost_label = TextBody(parent=cost_grid, align=Align.CENTERLEFT, color=TextColor.SECONDARY) + Frame(bgParent=cost_grid, opacity=0.1) + Fill(bgParent=cost_grid, color=eveColor.BLACK, opacity=0.2) + spacer = Container(parent=top_cont, align=Align.TOBOTTOM, height=8) + self.zone_label = TextBody(name='zone_label', parent=top_cont, align=Align.TOBOTTOM, textAlign=TextAlign.CENTER, color=eveThemeColor.THEME_FOCUS) + self.system_name_label = TextHeadline(parent=top_cont, align=Align.TOBOTTOM, text='', color=TextColor.HIGHLIGHT, textAlign=TextAlign.CENTER) + c = ContainerAutoSize(parent=top_cont, align=Align.TOBOTTOM, top=4) + grid = LayoutGrid(parent=c, align=Align.CENTERTOP, columns=3, cellSpacing=(8, 0)) + self.capacitory_label = TextBody(parent=grid) + self.capacitory_div = Fill(parent=grid, pos=(0, 0, 1, 4), align=Align.CENTER, opacity=0.5) + self.capacitor_perc_label = TextBody(parent=grid) + + def jump(self, *args): + sm.GetService('menu').JumpThroughStructureJumpBridge(self.item_id) + + def _update_item_id_and_ui(self): + self.update_ui(force=True) + self.updateTimer = AutoTimer(2000, self.update_ui) + + def _should_update_ui(self, force): + if force: + return True + if not self.panel: + return False + if self.panel.is_collapsed: + return False + return True + + def update_ui(self, force = False): + if self.destroyed: + self.updateTimer = None + return + if not self._should_update_ui(force): + return + with ExceptionEater('JumpBridgeCont:Failed to update ui'): + self._update_target_name() + jump_bridge_values = self.jump_bridge_cont_controller.get_jump_bridge_values() + if not jump_bridge_values: + return + self._update_button(jump_bridge_values) + self._update_top_cont(jump_bridge_values) + + def _update_button(self, jump_bridge_values): + from menucheckers import CelestialChecker + from menucheckers import SessionChecker + self._button.Disable() + self._button.hint = '' + self._left_btn_sprite.opacity = 0.5 + self._right_btn_sprite.opacity = 0.5 + if isinstance(jump_bridge_values, JumpBridgeValuesNoAccess): + self._button.hint = GetByLabel('UI/Inflight/SpaceComponents/JumpBridge/NoAccess') + return + slim_item = self.jump_bridge_cont_controller.get_slim_item() + if not slim_item: + return + celestialChecker = CelestialChecker(slim_item, cfg, SessionChecker(session, sm)) + if celestialChecker.OfferActivateJumpBridge(): + self._left_btn_sprite.opacity = 1.0 + self._right_btn_sprite.opacity = 1.0 + self._button.Enable() + self._button.hint = None + + def _update_top_cont(self, jump_bridge_values): + if self.destroyed: + return + if isinstance(jump_bridge_values, JumpBridgeValuesNoAccess): + self._update_top_cont_without_access() + else: + self._update_top_cont_with_access(jump_bridge_values) + + def _update_target_name(self): + system_name = self.jump_bridge_cont_controller.get_target_system_name() + self.system_name_label.text = system_name + + def _update_top_cont_with_access(self, jump_bridge_values): + self.capacitory_label.text = jump_bridge_values.capacitory_text + self.capacitor_perc_label.text = jump_bridge_values.capacitor_perc_text + self.capacitor_perc_label.Show() + self.capacitory_div.Show() + self.zone_label.text = jump_bridge_values.zone_text + self.zone_label.Show() + self.cost_label.text = jump_bridge_values.cost_text + cost_prop = jump_bridge_values.cost_proportion + if jump_bridge_values.has_sufficient_charge: + capacity_prop = jump_bridge_values.capacity_proportion + white_prop = capacity_prop - cost_prop + self.gauge.SetValue(white_prop) + self.gauge.UpdateRedGauge(white_prop, capacity_prop) + self.warning_sprite.Hide() + else: + self.gauge.SetValue(0) + self.gauge.UpdateRedGauge(0, cost_prop) + self.warning_sprite.Show() + self.gauge.Show() + self.center_icon_cont.Hide() + + def _update_top_cont_without_access(self): + self.capacitory_label.text = GetByLabel('UI/Inflight/SpaceComponents/JumpBridge/Redacted') + self.capacitor_perc_label.Hide() + self.capacitory_div.Hide() + self.zone_label.Hide() + self.cost_label.text = GetByLabel('UI/Inflight/SpaceComponents/JumpBridge/NoAccess') + self.warning_sprite.Show() + self.gauge.Hide() + self.center_icon_cont.Show() + + def OnCapitalSystemChanged(self, change): + self.jump_bridge_cont_controller.clear_capital_memoize() + self.jump_bridge_cont_controller.reset_jump_bridge_values() + + def OnSessionChanged(self, isremote, sess, change): + if 'allianceid' in change: + self.jump_bridge_cont_controller.clear_capital_memoize() + self.jump_bridge_cont_controller.reset_jump_bridge_values() + if 'shipid' in change: + self.jump_bridge_cont_controller.reset_jump_bridge_values() + self.update_ui() + + def _on_collapse_changed(self, collapsing = False): + if not collapsing: + uthread2.StartTasklet(self.update_ui, True) + + def OnJumpBridgeChargeChanged(self): + self.jump_bridge_cont_controller.reset_jump_bridge_values() + + def OnJumpBridgeActivationChanged(self): + self.jump_bridge_cont_controller.reset_jump_bridge_values() + + def Close(self): + self._disconnect_signals() + super(JumpBridgeCont, self).Close() + + +class GaugeWithRed(GaugeCircular): + + def ApplyAttributes(self, attributes): + self.redGauge = None + super(GaugeWithRed, self).ApplyAttributes(attributes) + + def Reconstruct(self): + self._ConstructGauge() + self._ConstructRedGauge() + self._ConstructBGGauge() + + def _ConstructRedGauge(self): + if self.redGauge: + self.redGauge.Close() + self.redGauge = self.ConstructLine(eveColor.HOT_RED, eveColor.HOT_RED) + self.redGauge.end = 0 + self.redGauge.name = 'redGaugeLine' + + def UpdateRedGauge(self, start, end): + self.redGauge.start = start + self.redGauge.end = end diff --git a/spacecomponents/client/ui/jumpbridge/jumpBridgeContController.py b/spacecomponents/client/ui/jumpbridge/jumpBridgeContController.py @@ -0,0 +1,212 @@ +#Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\spacecomponents\client\ui\jumpbridge\jumpBridgeContController.py +import math +import gametime +import logging +from caching import Memoize +from carbon.common.script.util.format import FmtAmt +from carbonui import TextColor +from const import SEC +from dogma.const import attributeCapacitorCapacity, attributeBaseJumpBridgeCapacitorCost, dgmTauConstant, attributeRechargeRate +from eve.client.script.ui import eveColor +from eveexceptions import ExceptionEater +from eveformat import client as eveformat +from jumpbridge.common.zone_modifier_util import GetCapacitorZoneModifierAndIdx +from localization import GetByLabel +logger = logging.getLogger(__name__) + +class JumpBridgeContController(object): + + def __init__(self, itemID, typeID): + self._item_id = itemID + self._type_id = typeID + self._jump_bridge_values = None + self.michelle = sm.GetService('michelle') + self.sov_svc = sm.GetService('sov') + self.dogma_lm = sm.GetService('clientDogmaIM').GetDogmaLocation() + self._recharge_time = self.dogma_lm.dogmaStaticMgr.GetTypeAttribute2(self._type_id, attributeRechargeRate) + self._total_capacity = self.dogma_lm.dogmaStaticMgr.GetTypeAttribute2(self._type_id, attributeCapacitorCapacity) + + def get_slim_item(self): + bp = self.michelle.GetBallpark() + if not bp: + return None + return bp.GetSlimItem(self._item_id) + + def get_target_system_name(self): + slim_item = self.get_slim_item() + if not slim_item: + return '' + target_system_id = slim_item.targetSolarsystemID + if not target_system_id: + return GetByLabel('UI/Inflight/SpaceComponents/JumpBridge/JumpBridgeUnlinked') + header_text = u'{system_name} {security_status}'.format(system_name=cfg.evelocations.Get(target_system_id).name, security_status=eveformat.solar_system_security_status(target_system_id)) + return header_text + + def _get_your_cost_and_zone(self): + slim_item = self.get_slim_item() + if not slim_item: + return (None, None) + capital_solar_system_id = get_my_capital_system() + if capital_solar_system_id is None: + return (None, None) + base_capacitor_use = self.dogma_lm.GetAttributeValue(session.shipid, attributeBaseJumpBridgeCapacitorCost) + component = self._get_jump_bridge_component() + if not component: + return (None, None) + zone_multiplier, zone_idx = GetCapacitorZoneModifierAndIdx(capital_solar_system_id, slim_item.targetSolarsystemID, component.zoneMultipliers) + total_capacitor_use = base_capacitor_use * zone_multiplier + return (total_capacitor_use, zone_idx) + + def reset_jump_bridge_values(self): + self._jump_bridge_values = None + + def get_jump_bridge_values(self): + if self._jump_bridge_values and not self._jump_bridge_values.is_expired: + return self._jump_bridge_values + self._jump_bridge_values = self._get_new_jump_bridge_values() + return self._jump_bridge_values + + def _get_new_jump_bridge_values(self): + jump_bridge_values = None + with ExceptionEater('JumpBridgeContController:Failed to update ui'): + if self.has_correct_alliance_membership(): + jump_bridge_values = self._get_values_for_update() + else: + jump_bridge_values = JumpBridgeValuesNoAccess() + return jump_bridge_values + + def _get_values_for_update(self): + try: + info = self.get_jump_bridge_info() + if info is None: + return JumpBridgeValuesNoAccess() + except AttributeError: + return JumpBridgeValuesNoAccess() + + total_capacitor_use_by_ship, zone_idx = self._get_your_cost_and_zone() + values = JumpBridgeValuesAccess(info.structure_capacitor, info.sim_timestamp, self._recharge_time, self._total_capacity, total_capacitor_use_by_ship, zone_idx) + return values + + def _get_jump_bridge_component(self): + bp = self.michelle.GetBallpark() + if not bp: + return None + from jumpbridge.client.jumpBridge import GetJumpBridgeComponent + return GetJumpBridgeComponent(bp, self._item_id) + + def get_jump_bridge_info(self): + from jumpbridge.client.jumpBridge import GetJumpBridgeInfo + return GetJumpBridgeInfo(self.michelle, self._item_id) + + def has_correct_alliance_membership(self): + if not session.allianceid: + return False + sov_info = self.sov_svc.GetSystemSovereigntyInfo(session.solarsystemid2) + if not sov_info: + return False + return sov_info.allianceID == session.allianceid + + def clear_capital_memoize(self): + get_my_capital_system.clear_memoized() + + +@Memoize(60) +def get_my_capital_system(): + return sm.GetService('sov').GetMyCapitalSystem() + + +class BaseJumpBridgeValues(object): + + def __init__(self): + self._timestamp = gametime.GetWallclockTime() + + @property + def is_expired(self): + time_since = gametime.GetTimeSinceWallclockTime(self._timestamp) + return time_since > 60 * SEC + + +class JumpBridgeValuesNoAccess(BaseJumpBridgeValues): + pass + + +class JumpBridgeValuesAccess(BaseJumpBridgeValues): + + def __init__(self, capacitor_value, sim_timestamp, recharge_time, total_capacity, capacitor_use_by_ship, zone_idx): + super(JumpBridgeValuesAccess, self).__init__() + self._capacitor_value = capacitor_value + self._sim_timestamp = sim_timestamp + self._recharge_time = recharge_time + self._total_capacity = total_capacity + self._capacitor_use_by_ship = capacitor_use_by_ship + self._zone_idx = zone_idx + + @property + def zone_text(self): + if self._zone_idx is None: + return '' + return GetByLabel('UI/Inflight/SpaceComponents/JumpBridge/ZoneNumber', zoneNumber=self._zone_idx + 1) + + @property + def current_capacitor(self): + return self.current_charge_value + + @property + def current_charge_value(self): + if self._total_capacity <= 0: + return 0 + old_time = self._sim_timestamp + tau_value = self._recharge_time / 5.0 + new_time = gametime.GetSimTime() + sq = math.sqrt(max(self._capacitor_value / self._total_capacity, 0)) + time_passed = min(old_time - new_time, 0) / float(dgmTauConstant) + exp = math.exp(time_passed / tau_value) + ret = (1.0 + (sq - 1.0) * exp) ** 2 * self._total_capacity + return ret + + @property + def cost_text(self): + if self._capacitor_use_by_ship is None: + return '' + cost = self._convert_gj_to_tj_text(self._capacitor_use_by_ship, 1) + if self.has_sufficient_charge: + percentage = round(self.cost_proportion * 100, 1) + text = GetByLabel('UI/Inflight/SpaceComponents/JumpBridge/YourCostWithPercentage', colorValue=TextColor.HIGHLIGHT, cost=cost, percentage=percentage) + else: + text = GetByLabel('UI/Inflight/SpaceComponents/JumpBridge/YourCostInsufficientCharge', colorValue=eveColor.HOT_RED_HEX, cost=cost) + return text + + @property + def capacitory_text(self): + text = GetByLabel('UI/Inflight/SpaceComponents/JumpBridge/CapacitorStatus', capacitorLeft=self._convert_gj_to_tj_text(self.current_capacitor), totalCapacitor=self._convert_gj_to_tj_text(self._total_capacity)) + return text + + @property + def capacitor_perc_text(self): + percentage = round(self.capacity_proportion * 100, 1) + return GetByLabel('UI/Common/Formatting/PercentageDecimal', percentage=percentage) + + @property + def capacity_proportion(self): + if self._total_capacity: + return float(self.current_capacitor) / self._total_capacity + return 0 + + @property + def cost_proportion(self): + if self._capacitor_use_by_ship is None: + return 0 + if self._total_capacity: + return float(self._capacitor_use_by_ship) / self._total_capacity + return 0 + + def _convert_gj_to_tj_text(self, value, decimals = 0): + in_tj = value / 1000.0 + rounded = round(in_tj, decimals) + if decimals == 0: + return FmtAmt(rounded) + return FmtAmt(rounded, showFraction=decimals) + + @property + def has_sufficient_charge(self): + return self._capacitor_use_by_ship <= self.current_capacitor diff --git a/spacecomponents/client/ui/jumpbridge/states.py b/spacecomponents/client/ui/jumpbridge/states.py @@ -0,0 +1,74 @@ +#Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\spacecomponents\client\ui\jumpbridge\states.py +import carbonui.const as uiconst +from carbonui.primitives.container import Container +from carbonui.uianimations import animations +from dynamicresources.client.ess.bracket.state_machine import State, StateMachine, Transition +from spacecomponents.client.ui.jumpbridge.bracketPanel import JumpBridgePanel +CONTENT_WIDTH = 300 +DEFAULT_CONTENT_HEIGHT = 170 + +class Online(State): + + def __init__(self, bracket): + self._bracket = bracket + self._state_machine = StateMachine() + + def enter(self): + self._state_machine.move_to(InRange(self._bracket)) + + def close(self): + self._state_machine.close() + + +class InRange(State): + __notifyevents__ = [] + + def __init__(self, bracket): + self._bracket = bracket + self._panel = None + + def enter(self): + self._panel = JumpBridgePanel(parent=self._bracket.layer, camera=self._bracket.camera, root_transform=self._bracket.root, content_class=self._bracket.content_class, panel_name=self._bracket.panel_name, offset_y=self._bracket.offset_y, collapse_at_camera_distance=self._bracket.collapse_at_camera_distance, tether_name=self._bracket.tether_name, tether_width=self._bracket.tether_width, itemID=self._bracket.item_id, typeID=self._bracket.type_id) + + def close(self): + self._panel.close() + + +class Idle(State): + + def __init__(self, panel): + self._panel = panel + self._content = None + + def enter(self): + content_class = self._panel.content_class + height = getattr(content_class, 'CONTENT_HEIGHT', DEFAULT_CONTENT_HEIGHT) + self._content = Container(name='idleCont', parent=self._panel.content, pos=(0, + 0, + CONTENT_WIDTH, + height), align=uiconst.TOPLEFT) + content_class(parent=self._content, align=uiconst.TOBOTTOM, height=height, itemID=self._panel.item_id, typeID=self._panel.type_id, panel=self._panel) + animations.FadeTo(self._content, duration=0.3) + + def exit(self): + transition = Exit(self._content) + self._content = None + return transition + + def close(self): + if self._content: + self._content.Close() + + +class Exit(Transition): + + def __init__(self, content): + super(Exit, self).__init__() + self._content = content + + def animation(self): + animations.FadeOut(self._content, duration=0.2) + self.sleep(0.2) + + def on_close(self): + self._content.Close() diff --git a/spacecomponents/common/componentConst.py b/spacecomponents/common/componentConst.py @@ -96,6 +96,7 @@ BREACH_POINT_ASTEROID = 'breachPointAsteroid' REORIENTOR = 'reorientor' COMPANION_MODEL = 'companionModel' STARTER_SHIPCASTER = 'starterShipcaster' +JUMP_BRIDGE = 'structureJumpBridge' ALL_COMPONENTS = (DEPLOY_CLASS, ACTIVATE_CLASS, DOGMATIC_CLASS, @@ -186,6 +187,7 @@ ALL_COMPONENTS = (DEPLOY_CLASS, BREACH_POINT_ASTEROID, REORIENTOR, COMPANION_MODEL, - STARTER_SHIPCASTER) + STARTER_SHIPCASTER, + JUMP_BRIDGE) MIN_DISTANCE_FROM_CONTROLTOWER_MAX_VALUE = 30000000 BOOMBOX_MUSIC_TRIGGER_SLIM_ITEM_FIELD = 'component_boombox_music_trigger' diff --git a/spacecomponents/common/helper.py b/spacecomponents/common/helper.py @@ -358,15 +358,23 @@ def HasPhaseStabilizerComponent(typeID): return type_has_space_component(typeID, componentConst.PHASE_STABILIZER) +def GetPhaseStabilizerAttributes(typeID): + return GetComponentTypeAttributes(typeID, componentConst.PHASE_STABILIZER) + + +def HasJumpBridgeComponent(typeID): + return type_has_space_component(typeID, componentConst.JUMP_BRIDGE) + + +def GetJumpBridgeAttributes(typeID): + return GetComponentTypeAttributes(typeID, componentConst.JUMP_BRIDGE) + + def GetItemTraderComponent(typeID): if HasItemTrader(typeID): return GetComponentTypeAttributes(typeID, componentConst.ITEM_TRADER) -def GetPhaseStabilizerAttributes(typeID): - return GetComponentTypeAttributes(typeID, componentConst.PHASE_STABILIZER) - - def GetClosestComponentWithinRange(ballID, ballpark, component_class, max_distance): closestDistance = max_distance closestComponentInstance = None diff --git a/structures/const.py b/structures/const.py @@ -149,7 +149,7 @@ REINFORCE_DURATION_ARMOR_MEDIUM_BY_SECURITY = {securityClassZeroSec: int(302400. securityClassHighSec: int(388800.0), securityClassSafeSec: int(388800.0)} REINFORCE_DURATION_ARMOR_WAR_HQ = 86400 -REINFORCE_DURATION_ARMOR_INSURGENCY_FOB = 86400 +REINFORCE_DURATION_ARMOR_INSURGENCY_FOB = 10800 REINFORCE_DURATION_HULL_DEFAULT = int(129600.0) REINFORCE_DURATION_HULL_WORMHOLE = int(129600.0) REINFORCE_DURATION_HULL_TRIGLAVIAN = int(129600.0) @@ -162,6 +162,7 @@ FLEX_REINFORCE_DURATION_HULL = 3600 REINFORCE_EXIT_JITTER_DEFAULT_SECONDS = 10800 REINFORCE_EXIT_JITTER_MEDIUM_SECONDS = int(5400.0) REINFORCE_EXIT_JITTER_FLEX_SECONDS = 1800 +REINFORCE_EXIT_JITTER_INSURGENCY_FOB_SECONDS = 3600 DEFAULT_REPAIR_TIMER = 900 STATE_REPAIR_TIME = {STATE_ANCHOR_VULNERABLE: 900, STATE_ONLINING_VULNERABLE: 900, diff --git a/structures/deployment.py b/structures/deployment.py @@ -38,7 +38,7 @@ CATEGORY_DISTANCES = {inventorycommon.const.categoryEntity: 5000, GROUP_MIN_DISTANCE_TO_STARGATE = {inventorycommon.const.groupStructureJumpBridge: 100000000} GROUPS_REQUIRING_CONQUERABLE_SYSTEM = {inventorycommon.const.groupStructureJumpBridge, inventorycommon.const.groupStructureCynoJammer, inventorycommon.const.groupStructureCynoBeacon} MAX_GROUP_PER_SOLARSYSTEM = {inventorycommon.const.groupStructureJumpBridge: 1, - inventorycommon.const.groupStructureCynoJammer: 3, + inventorycommon.const.groupStructureCynoJammer: 1, inventorycommon.const.groupStructureCynoBeacon: 1} MAX_ADM_FOR_HOSTILE_DEPLOYMENT_BY_TYPE = {inventorycommon.const.typeCitadelAstrahus: 4, inventorycommon.const.typeEngineeringComplexRaitaru: 4, diff --git a/structures/settings.py b/structures/settings.py @@ -112,7 +112,7 @@ ALL_SETTING_OBJECTS = [StructureSettingObject(SETTING_MARKET_TAX, 'UI/StructureS StructureSettingObject(SETTING_MANUFACTURING_SUPERCAPITAL_TAX, 'UI/StructureSettings/ManufacturingSuperCapitalTax', 'UI/StructureSettings/ManufacturingSuperCapitalTaxDesc', 'StructureManufacturingSuperCapitalDenied', SETTINGS_TYPE_PERCENTAGE, hasGroups=True, valueRange=(0, MAX_INDUSTRY_TAX_PERCENTAGE), decimals=INDUSTRY_DECIMALS), StructureSettingObject(SETTING_RESEARCH_TAX, 'UI/StructureSettings/ResearchTax', 'UI/StructureSettings/ResearchTaxDesc', 'StructureResearchDenied', SETTINGS_TYPE_PERCENTAGE, hasGroups=True, valueRange=(0, MAX_INDUSTRY_TAX_PERCENTAGE), decimals=INDUSTRY_DECIMALS), StructureSettingObject(SETTING_INVENTION_TAX, 'UI/StructureSettings/InventionTax', 'UI/StructureSettings/InventionTaxDesc', 'StructureInventionDenied', SETTINGS_TYPE_PERCENTAGE, hasGroups=True, valueRange=(0, MAX_INDUSTRY_TAX_PERCENTAGE), decimals=INDUSTRY_DECIMALS), - StructureSettingObject(SETTING_JUMP_BRIDGE_ACTIVATION, 'UI/StructureSettings/CanActivateJumpBridge', 'UI/StructureSettings/CanActivateJumpBridgeDesc', 'ActivateJumpBridgeDenied', SETTINGS_TYPE_ISK, hasGroups=True, valueRange=(0, MAX_ISK_TAX_PER_LO)), + StructureSettingObject(SETTING_JUMP_BRIDGE_ACTIVATION, 'UI/StructureSettings/CanActivateJumpBridge', 'UI/StructureSettings/CanActivateJumpBridgeDesc', 'ActivateJumpBridgeDenied', SETTINGS_TYPE_NONE, hasGroups=True), StructureSettingObject(SETTING_CYNO_BEACON, 'UI/StructureSettings/CanConnectToCynoBeacon', 'UI/StructureSettings/CanConnectToCynoBeaconDesc', 'ConnectToCynoBeaconDenied', SETTINGS_TYPE_NONE, hasGroups=True), StructureSettingObject(SETTING_AUTOMOONMINING, 'UI/StructureSettings/CanAccessAutoMoonDrill', 'UI/StructureSettings/CanAccessAutoMoonDrillDesc', 'AccessToAutoMoonMinerDenied', SETTINGS_TYPE_NONE, hasGroups=True)] CATEGORIES_HULL = [ value for name, value in CATEGORIES_BY_NAME.iteritems() if name.startswith('CATEGORY_HULL_') ] diff --git a/structures/structure.py b/structures/structure.py @@ -98,6 +98,8 @@ class Structure(object): jitterRange = structures.REINFORCE_EXIT_JITTER_FLEX_SECONDS elif self.IsMediumStructure(): jitterRange = structures.REINFORCE_EXIT_JITTER_MEDIUM_SECONDS + elif self.IsInsurgencyFOB(): + jitterRange = structures.REINFORCE_EXIT_JITTER_INSURGENCY_FOB_SECONDS else: jitterRange = structures.REINFORCE_EXIT_JITTER_DEFAULT_SECONDS return exitTime + reinforce.GenerateJitterTimeDelta(jitterRange) diff --git a/whitelist.py b/whitelist.py @@ -3,7 +3,7 @@ import exceptions import blue from eveprefs import boot whitelist = '\n blue.DBRowDescriptor\n blue.DBRow\n\n eveexceptions.SQLError\n eveexceptions.UserError\n eveexceptions.CancelSessionChange\n eveexceptions.UnmarshalError\n eveexceptions.ConnectionError\n eveexceptions.ServiceNotFound\n \n stackless_response_router.exceptions.TimeoutException\n\n carbon.common.script.sys.crowset.CRowset\n carbon.common.script.sys.crowset.CIndexedRowset\n carbon.common.script.sys.crowset.CFilterRowset\n\n exceptions.AttributeError\n exceptions.IndexError\n exceptions.ValueError\n exceptions.KeyError\n exceptions.WindowsError\n exceptions.ReferenceError\n exceptions.RuntimeError\n exceptions.IOError\n\n exceptions.GPSException\n exceptions.GPSTransportClosed\n exceptions.GPSBadAddress\n exceptions.GPSAddressOccupied\n\n carbon.common.script.net.GPSExceptions.GPSException\n carbon.common.script.net.GPSExceptions.GPSTransportClosed\n carbon.common.script.net.GPSExceptions.GPSBadAddress\n carbon.common.script.net.GPSExceptions.GPSAddressOccupied\n\n carbon.common.script.net.machoNetExceptions.MachoException\n carbon.common.script.net.machoNetExceptions.MachoWrappedException\n carbon.common.script.net.machoNetExceptions.ProxyRedirect\n carbon.common.script.net.machoNetExceptions.UberMachoException\n carbon.common.script.net.machoNetExceptions.UnMachoDestination\n carbon.common.script.net.machoNetExceptions.UnMachoChannel\n carbon.common.script.net.machoNetExceptions.WrongMachoNode\n\n xmlrpclib.Fault\n\n carbon.common.script.net.machoNetPacket.CallReq\n carbon.common.script.net.machoNetPacket.CallRsp\n carbon.common.script.net.machoNetPacket.ErrorResponse\n carbon.common.script.net.machoNetPacket.IdentificationReq\n carbon.common.script.net.machoNetPacket.IdentificationRsp\n carbon.common.script.net.machoNetAddress.MachoAddress\n carbon.common.script.net.machoNetPacket.Notification\n carbon.common.script.net.machoNetPacket.PingReq\n carbon.common.script.net.machoNetPacket.PingRsp\n carbon.common.script.net.machoNetPacket.SessionChangeNotification\n carbon.common.script.net.machoNetPacket.SessionInitialStateNotification\n carbon.common.script.net.machoNetPacket.TransportClosed\n\n carbon.common.script.net.objectCaching.CacheOK\n carbon.common.script.net.objectCaching.CachedMethodCallResult\n carbon.common.script.net.objectCaching.CachedObject\n\n carbon.common.script.net.cachedObject.CachedObject\n utillib.KeyVal\n carbon.common.script.net.moniker.Moniker\n carbon.common.script.net.moniker.Moniker\n carbon.common.script.util.format.PasswordString\n carbon.common.script.sys.row.Row\n carbon.common.script.net.moniker.UpdateMoniker\n\n __builtin__.str\n __builtin__.unicode\n __builtin__.set\n\n collections.OrderedDict\n collections.defaultdict\n collections.deque\n\n localizationUtil.LocalizationSafeString\n\n eve.common.script.paperDoll.paperDollDefinitions.SculptingRow\n eve.common.script.paperDoll.paperDollDefinitions.ModifierRow\n eve.common.script.paperDoll.paperDollDefinitions.ColorSelectionRow\n eve.common.script.paperDoll.paperDollDefinitions.AppearanceRow\n\n machonethelpers.argchecker.ValidateArgTypeException\n \n\n fsd.schemas.loaders.objectLoader.ObjectLoader\n fsd.schemas.path.FsdDataPathObject\n fsd.schemas.binaryLoader.LoaderState\n fsd.schemas.loaders.dictLoader.DictLoader\n \n raffles.common.raffle.Raffle\n raffles.common.ticket.Ticket\n raffles.common.raffle_data.RaffleCreationData\n raffles.RafflesError\n raffles.RaffleNotFoundError\n raffles.TicketUnavailableError\n raffles.NotEnoughISKError\n raffles.FailureToDeliverItemError\n raffles.FetchError\n raffles.InventoryError\n raffles.CreateError\n raffles.PurchaseError\n \n kiring.common.errors.KiringRedeemingCodeException\n kiring.common.errors.KiringRedeemingCodeNotValidException\n kiring.common.errors.KiringRedeemingCodeUsedException\n kiring.common.errors.KiringRedeemingCodeTypeUsedException\n\n contracts.contractStruct.ContractStruct\n\n uuid.UUID\n' -whitelist += '\n foo.SlimItem\n\n eve.common.script.util.slimItem.SlimItem\n\n eve.common.script.sys.eveCfg.Standings\n\n eve.common.script.sys.rowset.RowDict\n eve.common.script.sys.rowset.RowList\n\n eve.common.script.sys.rowset.Rowset\n eve.common.script.sys.rowset.FilterRowset\n eve.common.script.sys.rowset.IndexRowset\n eve.common.script.sys.rowset.IndexedRows\n eve.common.script.sys.eveCfg.StackSize\n eve.common.script.sys.eveCfg.Singleton\n eve.common.script.util.pagedCollection.PagedResultSet\n\n dogma.exceptions.EmbarkOnlineError\n\n evewar.util.War\n eve.common.script.universe.locationWrapper.SolarSystemWrapper\n\n industry.job.Location\n industry.const.Error\n industry.const.Reference\n\n crimewatch.corp_aggression.settings.AggressionSettings\n\n shipskins.LicensedSkin\n\n eve.common.script.dogma.effect.BrainEffect\n dogma.attributes.Attribute\n dogma.attributes.SkillLevelAttribute\n dogma.attributes.ChargedAttribute\n dogma.attributes.HeatAttribute\n dogma.attributes.StackingNurfedAttribute\n dogma.attributes.LiteralAttribute\n dogma.attributes.BrainLiteralAttribute\n \n datetime.datetime\n datetime.date\n\n projectdiscovery.common.exceptions.NoActiveClassificationTaskError\n projectdiscovery.common.exceptions.UnexpectedMmosResultError\n projectdiscovery.common.exceptions.TooFewPolygonsMmosResultError\n projectdiscovery.common.exceptions.TooFewVerticesMmosResultError\n projectdiscovery.common.exceptions.NoConnectionToAPIError\n projectdiscovery.common.exceptions.MissingKeyError\n\n marketutil.BestByOrder\n marketutil.OrderAllData\n\n seasons.common.challenge.Challenge\n seasons.common.exceptions.ChallengeForCharacterNotFoundError\n seasons.common.exceptions.NotEnoughChallengeTypesAvailableError\n seasons.common.exceptions.ChallengeTypeNotFoundError\n \n explorationscanner.common.cosmicAnomalyInfo.CosmicAnomalyInfo\n explorationscanner.common.signatureInfo.SignatureInfo\n explorationscanner.common.structureInfo.StructureInfo\n explorationscanner.common.staticSiteInfo.StaticSiteInfo\n \n evedungeons.common.dungeonInfo.DungeonInfo\n\n agency.common.contentdata.CustomContentData\n \n fastcheckout.common.errors.FastCheckoutDisabled\n\n characterskills.common.character_skill_entry.CharacterSkillEntry\n \n npcs.npccorporations.CorporationTicker\n\n characterenergy.characterEnergyState.CharacterEnergyState\n characterenergy.characterEnergyState.InsufficientEnergyError\n solarsysteminterference.solarsystemInterferenceState.SolarsystemInterferenceState\n solarsysteminterference.solarsystemInterferenceState.ExcessInterferenceError\n \n structures.structureHangarViewState.StructureHangarViewState\n \n factionwarfare.occupationState.OccupationState\n factionwarfare.victoryPointState.VictoryPointState\n factionwarfare.advantageState.AdvantageState\n \n shipcosmetics.structs._modules._logo.ShipCosmeticLogo\n shipcosmetics.structs._fitting._group.ShipCosmeticFittingGroup\n shipcosmetics.structs._fitting._fitting.ShipCosmeticFitting\n shipcosmetics.structs._license._logo.ShipLogoLicense\n \n shipcaster.landingPadData.LandingPadData\n \n deathzone.targetTrackingState.TargetTrackingState\n\n pirateinsurgency.campaignClientSnapshot.CampaignClientSnapshot\n \n lpOffers.exceptions.TransfersDisabledError\n \n sovereignty.data_types.SovHubInfo\n sovereignty.data_types.SovClaimInfo\n\n dotWeapons.common.dotAppInfo.DotApplicationInfo\n\n evedungeons.common.instance_identifier.DungeonInstanceIdentifier\n' +whitelist += '\n foo.SlimItem\n\n eve.common.script.util.slimItem.SlimItem\n\n eve.common.script.sys.eveCfg.Standings\n\n eve.common.script.sys.rowset.RowDict\n eve.common.script.sys.rowset.RowList\n\n eve.common.script.sys.rowset.Rowset\n eve.common.script.sys.rowset.FilterRowset\n eve.common.script.sys.rowset.IndexRowset\n eve.common.script.sys.rowset.IndexedRows\n eve.common.script.sys.eveCfg.StackSize\n eve.common.script.sys.eveCfg.Singleton\n eve.common.script.util.pagedCollection.PagedResultSet\n\n dogma.exceptions.EmbarkOnlineError\n\n evewar.util.War\n eve.common.script.universe.locationWrapper.SolarSystemWrapper\n\n industry.job.Location\n industry.const.Error\n industry.const.Reference\n\n crimewatch.corp_aggression.settings.AggressionSettings\n\n shipskins.LicensedSkin\n\n eve.common.script.dogma.effect.BrainEffect\n dogma.attributes.Attribute\n dogma.attributes.SkillLevelAttribute\n dogma.attributes.ChargedAttribute\n dogma.attributes.HeatAttribute\n dogma.attributes.StackingNurfedAttribute\n dogma.attributes.LiteralAttribute\n dogma.attributes.BrainLiteralAttribute\n \n datetime.datetime\n datetime.date\n\n projectdiscovery.common.exceptions.NoActiveClassificationTaskError\n projectdiscovery.common.exceptions.UnexpectedMmosResultError\n projectdiscovery.common.exceptions.TooFewPolygonsMmosResultError\n projectdiscovery.common.exceptions.TooFewVerticesMmosResultError\n projectdiscovery.common.exceptions.NoConnectionToAPIError\n projectdiscovery.common.exceptions.MissingKeyError\n\n marketutil.BestByOrder\n marketutil.OrderAllData\n\n seasons.common.challenge.Challenge\n seasons.common.exceptions.ChallengeForCharacterNotFoundError\n seasons.common.exceptions.NotEnoughChallengeTypesAvailableError\n seasons.common.exceptions.ChallengeTypeNotFoundError\n \n explorationscanner.common.cosmicAnomalyInfo.CosmicAnomalyInfo\n explorationscanner.common.signatureInfo.SignatureInfo\n explorationscanner.common.structureInfo.StructureInfo\n explorationscanner.common.staticSiteInfo.StaticSiteInfo\n \n evedungeons.common.dungeonInfo.DungeonInfo\n\n agency.common.contentdata.CustomContentData\n \n fastcheckout.common.errors.FastCheckoutDisabled\n\n characterskills.common.character_skill_entry.CharacterSkillEntry\n \n npcs.npccorporations.CorporationTicker\n\n characterenergy.characterEnergyState.CharacterEnergyState\n characterenergy.characterEnergyState.InsufficientEnergyError\n solarsysteminterference.solarsystemInterferenceState.SolarsystemInterferenceState\n solarsysteminterference.solarsystemInterferenceState.ExcessInterferenceError\n \n structures.structureHangarViewState.StructureHangarViewState\n \n factionwarfare.occupationState.OccupationState\n factionwarfare.victoryPointState.VictoryPointState\n factionwarfare.advantageState.AdvantageState\n \n shipcosmetics.structs._modules._logo.ShipCosmeticLogo\n shipcosmetics.structs._fitting._group.ShipCosmeticFittingGroup\n shipcosmetics.structs._fitting._fitting.ShipCosmeticFitting\n shipcosmetics.structs._license._logo.ShipLogoLicense\n \n shipcaster.landingPadData.LandingPadData\n \n deathzone.targetTrackingState.TargetTrackingState\n\n pirateinsurgency.campaignClientSnapshot.CampaignClientSnapshot\n \n lpOffers.exceptions.TransfersDisabledError\n \n sovereignty.data_types.SovHubInfo\n sovereignty.data_types.SovClaimInfo\n\n dotWeapons.common.dotAppInfo.DotApplicationInfo\n\n evedungeons.common.instance_identifier.DungeonInstanceIdentifier\n jumpbridge.common.jump_bridge_authorized_info.JumpBridgeAuthorizedInfo\n' if boot.role == 'server': whitelist += '\n agent.StandardMissionDetails\n agent.HeraldryMissionDetails\n agent.ResearchMissionDetails\n agent.StorylineMissionDetails\n agent.EpicArcMissionDetails\n agent.OfferDetails\n agent.LoyaltyPoints\n agent.Agent\n agent.Credits\n agent.Item\n agent.Entity\n agent.Objective\n agent.FetchObjective\n agent.EncounterObjective\n agent.DungeonObjective\n agent.TransportObjective\n agent.AgentObjective\n agent.Reward\n agent.TimeBonusReward\n agent.MissionReferral\n agent.Location\n agent.ItemDeclarationError\n agent.ItemResolutionFailure\n agent.TransferItemFailure\n\n eve.server.script.mgt.npc.agents.services.standardMissionDetails.StandardMissionDetails\n eve.server.script.mgt.npc.agents.services.standardMissionDetails.HeraldryMissionDetails\n eve.server.script.mgt.npc.agents.services.standardMissionDetails.ResearchMissionDetails\n eve.server.script.mgt.npc.agents.services.standardMissionDetails.StorylineMissionDetails\n eve.server.script.mgt.npc.agents.services.standardMissionDetails.EpicArcMissionDetails\n eve.server.script.mgt.npc.agents.services.standardMissionDetails.OfferDetails\n eve.server.script.mgt.npc.agents.items.LoyaltyPoints\n eve.server.script.mgt.npc.agents.items.Agent\n eve.server.script.mgt.npc.agents.items.Credits\n eve.server.script.mgt.npc.agents.items.Item\n eve.server.script.mgt.npc.agents.items.Entity\n eve.server.script.mgt.npc.agents.items.Objective\n eve.server.script.mgt.npc.agents.items.FetchObjective\n eve.server.script.mgt.npc.agents.items.EncounterObjective\n eve.server.script.mgt.npc.agents.items.DungeonObjective\n eve.server.script.mgt.npc.agents.items.TransportObjective\n eve.server.script.mgt.npc.agents.items.AgentObjective\n eve.server.script.mgt.npc.agents.items.Reward\n eve.server.script.mgt.npc.agents.items.TimeBonusReward\n eve.server.script.mgt.npc.agents.items.MissionReferral\n eve.server.script.mgt.npc.agents.items.Location\n eve.server.script.mgt.npc.agents.exceptions.ItemDeclarationError\n eve.server.script.mgt.npc.agents.exceptions.ItemResolutionFailure\n eve.server.script.mgt.npc.agents.exceptions.TransferItemFailure\n\n sys.A\n sys.AgentString\n sys.AgentUnicode\n\n eve.common.script.sys.strangeStrings.A\n eve.common.script.sys.strangeStrings.AgentString\n eve.common.script.sys.strangeStrings.AgentUnicode\n\n scriber.hermes.Notification\n scriber.hermes.ReadStatus\n\n externalQueue.actions.ExternalActionException\n npcs.server.rewards.rewards.GroupRewardData\n npcs.server.rewards.rewards.DisqualificationData\n\n operations.common.const.RewardToken\n operations.common.const.SkillRewardToken \n\n raffles.server.PendingRaffle\n \n skills.server.exceptions.SkillBundleInjectionFailed\n skills.server.exceptions.MultiSkillBundleInjectForbidden\n \n evefitting.errors.FittingDoesNotExistError\n evefitting.errors.FittingIsNotValid\n \n externalQueue.utils.FilterGenerator\n \n behaviors.blackboards.scopes.Scope\n \n voidspace.server.content_manager.PlayerLocationInfo\n ballpark.gridallocationmanager.SolarSystemFullException\n ballpark.gridallocationmanager.GridAlreadyAllocatedError\n \n storylines.server.airnpe.AirNpeStartData\n \n nodegraph.server.atoms.atom_service.AtomNotFoundError\n nodegraph.server.atoms.atom_service.AtomRemoteMethodNotSupportedError \n \n shipcaster.launcherData.LauncherData\n \n lpOffers.exceptions.InsufficientBalanceError\n lpOffers.exceptions.MissingCorpRoleError\n lpOffers.exceptions.WrongCorporationMembershipError\n\n pirateinsurgency.server.campaignServerSnapshot.CampaignServerSnapshot\n \n assetholding.server.inventory.exceptions.HoldItemsFailed\n assetholding.server.inventory.exceptions.SpawnItemsFailed\n\n sovereignty.hub.server.errors.ItemCannotBeAddedToSovHubError\n sovereignty.skyhook.server.errors.CannotActivateError\n sovereignty.skyhook.server.errors.CannotAccessReagentsError\n \n spacecomponents.server.components.mercenaryDen.MercenaryDenNotFound\n spacecomponents.server.components.mercenaryDen.ValidateStartRequestFailed\n \n sovereignty.radius_dungeon_distribution.server.radius_dungeon_distribution_solarsystem.RadiusDungeonDistributionInstance\n evedungeons.server.scan_data.ScanData\n ' if boot.role == 'client':