Add buttons to cast skills in Habitica integration (#126350)

This commit is contained in:
Manu 2024-10-24 19:54:59 +02:00 committed by GitHub
parent bf63b0993d
commit 39c0826f3c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 307 additions and 3 deletions

View file

@ -10,13 +10,18 @@ from typing import Any
from aiohttp import ClientResponseError
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
from homeassistant.core import HomeAssistant
from homeassistant.components.button import (
DOMAIN as BUTTON_DOMAIN,
ButtonEntity,
ButtonEntityDescription,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import ServiceValidationError
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import HabiticaConfigEntry
from .const import DOMAIN
from .const import ASSETS_URL, DOMAIN, HEALER, MAGE, ROGUE, WARRIOR
from .coordinator import HabiticaData, HabiticaDataUpdateCoordinator
from .entity import HabiticaBase
@ -27,6 +32,8 @@ class HabiticaButtonEntityDescription(ButtonEntityDescription):
press_fn: Callable[[HabiticaDataUpdateCoordinator], Any]
available_fn: Callable[[HabiticaData], bool] | None = None
class_needed: str | None = None
entity_picture: str | None = None
class HabitipyButtonEntity(StrEnum):
@ -36,6 +43,18 @@ class HabitipyButtonEntity(StrEnum):
BUY_HEALTH_POTION = "buy_health_potion"
ALLOCATE_ALL_STAT_POINTS = "allocate_all_stat_points"
REVIVE = "revive"
MPHEAL = "mpheal"
EARTH = "earth"
FROST = "frost"
DEFENSIVE_STANCE = "defensive_stance"
VALOROUS_PRESENCE = "valorous_presence"
INTIMIDATE = "intimidate"
TOOLS_OF_TRADE = "tools_of_trade"
STEALTH = "stealth"
HEAL = "heal"
PROTECT_AURA = "protect_aura"
BRIGHTNESS = "brightness"
HEAL_ALL = "heal_all"
BUTTON_DESCRIPTIONS: tuple[HabiticaButtonEntityDescription, ...] = (
@ -74,6 +93,173 @@ BUTTON_DESCRIPTIONS: tuple[HabiticaButtonEntityDescription, ...] = (
)
CLASS_SKILLS: tuple[HabiticaButtonEntityDescription, ...] = (
HabiticaButtonEntityDescription(
key=HabitipyButtonEntity.MPHEAL,
translation_key=HabitipyButtonEntity.MPHEAL,
press_fn=lambda coordinator: coordinator.api.user.class_.cast["mpheal"].post(),
available_fn=(
lambda data: data.user["stats"]["lvl"] >= 12
and data.user["stats"]["mp"] >= 30
),
class_needed=MAGE,
entity_picture="shop_mpheal.png",
),
HabiticaButtonEntityDescription(
key=HabitipyButtonEntity.EARTH,
translation_key=HabitipyButtonEntity.EARTH,
press_fn=lambda coordinator: coordinator.api.user.class_.cast["earth"].post(),
available_fn=(
lambda data: data.user["stats"]["lvl"] >= 13
and data.user["stats"]["mp"] >= 35
),
class_needed=MAGE,
entity_picture="shop_earth.png",
),
HabiticaButtonEntityDescription(
key=HabitipyButtonEntity.FROST,
translation_key=HabitipyButtonEntity.FROST,
press_fn=(
lambda coordinator: coordinator.api.user.class_.cast["frost"].post(
targetId=coordinator.config_entry.unique_id
)
),
available_fn=(
lambda data: data.user["stats"]["lvl"] >= 14
and data.user["stats"]["mp"] >= 40
),
class_needed=MAGE,
entity_picture="shop_frost.png",
),
HabiticaButtonEntityDescription(
key=HabitipyButtonEntity.DEFENSIVE_STANCE,
translation_key=HabitipyButtonEntity.DEFENSIVE_STANCE,
press_fn=(
lambda coordinator: coordinator.api.user.class_.cast[
"defensiveStance"
].post(targetId=coordinator.config_entry.unique_id)
),
available_fn=(
lambda data: data.user["stats"]["lvl"] >= 12
and data.user["stats"]["mp"] >= 25
),
class_needed=WARRIOR,
entity_picture="shop_defensiveStance.png",
),
HabiticaButtonEntityDescription(
key=HabitipyButtonEntity.VALOROUS_PRESENCE,
translation_key=HabitipyButtonEntity.VALOROUS_PRESENCE,
press_fn=(
lambda coordinator: coordinator.api.user.class_.cast[
"valorousPresence"
].post(targetId=coordinator.config_entry.unique_id)
),
available_fn=(
lambda data: data.user["stats"]["lvl"] >= 13
and data.user["stats"]["mp"] >= 20
),
class_needed=WARRIOR,
entity_picture="shop_valorousPresence.png",
),
HabiticaButtonEntityDescription(
key=HabitipyButtonEntity.INTIMIDATE,
translation_key=HabitipyButtonEntity.INTIMIDATE,
press_fn=(
lambda coordinator: coordinator.api.user.class_.cast["intimidate"].post(
targetId=coordinator.config_entry.unique_id
)
),
available_fn=(
lambda data: data.user["stats"]["lvl"] >= 14
and data.user["stats"]["mp"] >= 15
),
class_needed=WARRIOR,
entity_picture="shop_intimidate.png",
),
HabiticaButtonEntityDescription(
key=HabitipyButtonEntity.TOOLS_OF_TRADE,
translation_key=HabitipyButtonEntity.TOOLS_OF_TRADE,
press_fn=(
lambda coordinator: coordinator.api.user.class_.cast["toolsOfTrade"].post()
),
available_fn=(
lambda data: data.user["stats"]["lvl"] >= 13
and data.user["stats"]["mp"] >= 25
),
class_needed=ROGUE,
entity_picture="shop_toolsOfTrade.png",
),
HabiticaButtonEntityDescription(
key=HabitipyButtonEntity.STEALTH,
translation_key=HabitipyButtonEntity.STEALTH,
press_fn=(
lambda coordinator: coordinator.api.user.class_.cast["stealth"].post(
targetId=coordinator.config_entry.unique_id
)
),
available_fn=(
lambda data: data.user["stats"]["lvl"] >= 14
and data.user["stats"]["mp"] >= 45
),
class_needed=ROGUE,
entity_picture="shop_stealth.png",
),
HabiticaButtonEntityDescription(
key=HabitipyButtonEntity.HEAL,
translation_key=HabitipyButtonEntity.HEAL,
press_fn=(
lambda coordinator: coordinator.api.user.class_.cast["heal"].post(
targetId=coordinator.config_entry.unique_id
)
),
available_fn=(
lambda data: data.user["stats"]["lvl"] >= 11
and data.user["stats"]["mp"] >= 15
),
class_needed=HEALER,
),
HabiticaButtonEntityDescription(
key=HabitipyButtonEntity.BRIGHTNESS,
translation_key=HabitipyButtonEntity.BRIGHTNESS,
press_fn=(
lambda coordinator: coordinator.api.user.class_.cast["brightness"].post(
targetId=coordinator.config_entry.unique_id
)
),
available_fn=(
lambda data: data.user["stats"]["lvl"] >= 12
and data.user["stats"]["mp"] >= 15
),
class_needed=HEALER,
entity_picture="shop_brightness.png",
),
HabiticaButtonEntityDescription(
key=HabitipyButtonEntity.PROTECT_AURA,
translation_key=HabitipyButtonEntity.PROTECT_AURA,
press_fn=(
lambda coordinator: coordinator.api.user.class_.cast["protectAura"].post()
),
available_fn=(
lambda data: data.user["stats"]["lvl"] >= 13
and data.user["stats"]["mp"] >= 30
),
class_needed=HEALER,
entity_picture="shop_protectAura.png",
),
HabiticaButtonEntityDescription(
key=HabitipyButtonEntity.HEAL_ALL,
translation_key=HabitipyButtonEntity.HEAL_ALL,
press_fn=lambda coordinator: coordinator.api.user.class_.cast["healAll"].post(),
available_fn=(
lambda data: data.user["stats"]["lvl"] >= 14
and data.user["stats"]["mp"] >= 25
),
class_needed=HEALER,
entity_picture="shop_healAll.png",
),
)
async def async_setup_entry(
hass: HomeAssistant,
entry: HabiticaConfigEntry,
@ -82,6 +268,40 @@ async def async_setup_entry(
"""Set up buttons from a config entry."""
coordinator = entry.runtime_data
skills_added: set[str] = set()
@callback
def add_entities() -> None:
"""Add or remove a skillset based on the player's class."""
nonlocal skills_added
buttons = []
entity_registry = er.async_get(hass)
for description in CLASS_SKILLS:
if (
coordinator.data.user["stats"]["lvl"] >= 10
and coordinator.data.user["flags"]["classSelected"]
and not coordinator.data.user["preferences"]["disableClasses"]
and description.class_needed == coordinator.data.user["stats"]["class"]
):
if description.key not in skills_added:
buttons.append(HabiticaButton(coordinator, description))
skills_added.add(description.key)
elif description.key in skills_added:
if entity_id := entity_registry.async_get_entity_id(
BUTTON_DOMAIN,
DOMAIN,
f"{coordinator.config_entry.unique_id}_{description.key}",
):
entity_registry.async_remove(entity_id)
skills_added.remove(description.key)
if buttons:
async_add_entities(buttons)
coordinator.async_add_listener(add_entities)
add_entities()
async_add_entities(
HabiticaButton(coordinator, description) for description in BUTTON_DESCRIPTIONS
@ -123,3 +343,10 @@ class HabiticaButton(HabiticaBase, ButtonEntity):
if self.entity_description.available_fn:
return self.entity_description.available_fn(self.coordinator.data)
return True
@property
def entity_picture(self) -> str | None:
"""Return the entity picture to use in the frontend, if any."""
if entity_picture := self.entity_description.entity_picture:
return f"{ASSETS_URL}{entity_picture}"
return None

View file

@ -27,4 +27,9 @@ ATTR_SKILL = "skill"
ATTR_TASK = "task"
SERVICE_CAST_SKILL = "cast_skill"
WARRIOR = "warrior"
ROGUE = "rogue"
HEALER = "healer"
MAGE = "wizard"
DEVELOPER_ID = "4c4ca53f-c059-4ffa-966e-9d29dd405daf"

View file

@ -20,6 +20,42 @@
},
"revive": {
"default": "mdi:grave-stone"
},
"mpheal": {
"default": "mdi:broadcast"
},
"earth": {
"default": "mdi:landslide"
},
"frost": {
"default": "mdi:snowflake"
},
"defensive_stance": {
"default": "mdi:shield-sword"
},
"valorous_presence": {
"default": "mdi:shield-sun"
},
"intimidate": {
"default": "mdi:emoticon-angry"
},
"tools_of_trade": {
"default": "mdi:domino-mask"
},
"stealth": {
"default": "mdi:ninja"
},
"heal": {
"default": "mdi:aurora"
},
"brightness": {
"default": "mdi:flare"
},
"protect_aura": {
"default": "mdi:shimmer"
},
"heal_all": {
"default": "mdi:hand-heart-outline"
}
},
"sensor": {

View file

@ -46,6 +46,42 @@
},
"revive": {
"name": "Revive from death"
},
"mpheal": {
"name": "Ethereal surge"
},
"earth": {
"name": "Earthquake"
},
"frost": {
"name": "Chilling frost"
},
"defensive_stance": {
"name": "Defensive stance"
},
"valorous_presence": {
"name": "Valorous presence"
},
"intimidate": {
"name": "Intimidating gaze"
},
"tools_of_trade": {
"name": "Tools of the trade"
},
"stealth": {
"name": "Stealth"
},
"heal": {
"name": "Healing light"
},
"brightness": {
"name": "Searing brightness"
},
"protect_aura": {
"name": "Protective aura"
},
"heal_all": {
"name": "Blessing"
}
},
"sensor": {