diff --git a/combat.py b/combat.py index 5d4d700..5a17e96 100644 --- a/combat.py +++ b/combat.py @@ -46,66 +46,66 @@ def _aura(kind, dur, on, **extra): ABILITIES = { # Sword and shield: hold the line. - "shield_bash": {"name": "Shield Bash", "icon": "๐ก๏ธ", "needs": "shield", "target": "enemy", "cd": 10, + "shield_bash": {"name": "Shield Bash", "needs": "shield", "target": "enemy", "cd": 10, "offgcd": True, "threat": 2, "effects": [_dmg(1.2), {"t": "stun", "dur": 2}], "auto": {"r": "stop", "else": True}, "tip": "Hit, stun 2s, stop a cast. Bosses only lose the cast."}, - "challenge": {"name": "Challenge", "icon": "๐ค", "target": "enemy", "cd": 8, "offgcd": True, + "challenge": {"name": "Challenge", "target": "enemy", "cd": 8, "offgcd": True, "effects": [{"t": "taunt", "dur": 3}], "auto": {"r": "taunt"}, "tip": "An enemy turns on you for 3s."}, - "sweeping_cut": {"name": "Sweeping Cut", "icon": "๐", "target": "aoe", "cd": 10, "threat": 2, + "sweeping_cut": {"name": "Sweeping Cut", "target": "aoe", "cd": 10, "threat": 2, "effects": [{"t": "aoe", "c": 0.8}], "auto": {"r": "aoe", "n": 2}, "tip": "Hits every enemy. Double threat."}, - "shield_wall": {"name": "Shield Wall", "icon": "๐งฑ", "needs": "shield", "target": "self", "cd": 30, "offgcd": True, + "shield_wall": {"name": "Shield Wall", "needs": "shield", "target": "self", "cd": 30, "offgcd": True, "effects": [_aura("taken", 6, "self", mult=0.5)], "auto": {"r": "tanking", "pct": 0.6}, "tip": "Half damage taken for 6s."}, # Warhammer: slow, heavy, and hard to stand up to. - "crushing_blow": {"name": "Crushing Blow", "icon": "๐จ", "target": "enemy", "cd": 16, "cast": 1.5, + "crushing_blow": {"name": "Crushing Blow", "target": "enemy", "cd": 16, "cast": 1.5, "effects": [_dmg(1.5)], "auto": {"r": "always"}, "tip": "Wind up 1.5s, hit for 1.5ร."}, - "concuss": {"name": "Concuss", "icon": "๐ซ", "target": "enemy", "cd": 15, "offgcd": True, + "concuss": {"name": "Concuss", "target": "enemy", "cd": 15, "offgcd": True, "effects": [{"t": "stun", "dur": 3}], "auto": {"r": "stop", "else": True}, "tip": "Stun 3s, stop a cast. Bosses only lose the cast."}, - "earthshaker": {"name": "Earthshaker", "icon": "๐", "target": "aoe", "cd": 12, + "earthshaker": {"name": "Earthshaker", "target": "aoe", "cd": 12, "effects": [{"t": "aoe", "c": 0.5}, {"t": "delay", "by": 1.5}], "auto": {"r": "aoe", "n": 2}, "tip": "Hits every enemy and puts their next swing back 1.5s."}, - "unstoppable": {"name": "Unstoppable", "icon": "๐ก", "target": "self", "cd": 45, "offgcd": True, + "unstoppable": {"name": "Unstoppable", "target": "self", "cd": 45, "offgcd": True, "effects": [_aura("done", 12, "self", mult=1.2)], "auto": {"r": "big"}, "tip": "+20% damage for 12s."}, # Staff: magic, and keeping everyone standing. - "bolt": {"name": "Bolt", "icon": "โจ", "target": "enemy", "cd": 10, "cast": 1.5, + "bolt": {"name": "Bolt", "target": "enemy", "cd": 10, "cast": 1.5, "effects": [_dmg(1.1)], "auto": {"r": "always"}, "tip": "Cast 1.5s, magic hit for 1.1ร."}, - "mend": {"name": "Mend", "icon": "๐", "target": "ally", "cd": 10, "cast": 2, + "mend": {"name": "Mend", "target": "ally", "cd": 10, "cast": 2, "effects": [{"t": "heal", "c": 2.0}], "auto": {"r": "heal", "pct": 0.5}, "tip": "Cast 2s, heal someone for 2ร your hit."}, - "ward": {"name": "Ward", "icon": "๐ฎ", "target": "ally", "cd": 20, + "ward": {"name": "Ward", "target": "ally", "cd": 20, "effects": [{"t": "shield", "c": 2.0, "dur": 20}], "auto": {"r": "ward", "pct": 0.8}, "tip": "Soaks 2ร your hit for someone, for up to 20s."}, - "thornbind": {"name": "Thornbind", "icon": "๐ฟ", "target": "enemy", "cd": 20, + "thornbind": {"name": "Thornbind", "target": "enemy", "cd": 20, "effects": [{"t": "cc", "dur": 15}], "auto": {"r": "cc"}, "tip": "Holds an enemy 15s. Damage breaks it. Not bosses."}, # Bow: fast, first, and from a distance. - "aimed_shot": {"name": "Aimed Shot", "icon": "๐ฏ", "target": "enemy", "cd": 10, "cast": 2, + "aimed_shot": {"name": "Aimed Shot", "target": "enemy", "cd": 10, "cast": 2, "effects": [_dmg(2.0)], "auto": {"r": "always"}, "tip": "Aim 2s, hit for 2ร."}, - "pinning_shot": {"name": "Pinning Shot", "icon": "๐", "target": "enemy", "cd": 12, "offgcd": True, + "pinning_shot": {"name": "Pinning Shot", "target": "enemy", "cd": 12, "offgcd": True, "effects": [_dmg(0.5), {"t": "interrupt"}], "auto": {"r": "stop"}, "tip": "Hit and stop a cast."}, - "barbed_arrow": {"name": "Barbed Arrow", "icon": "๐ฉธ", "target": "enemy", "cd": 12, + "barbed_arrow": {"name": "Barbed Arrow", "target": "enemy", "cd": 12, "effects": [_dmg(0.4), {"t": "dot", "c": 0.25, "every": 2, "dur": 12}], "auto": {"r": "dot"}, "tip": "Hit, then bleeds 6ร 0.25 over 12s."}, - "volley": {"name": "Volley", "icon": "๐น", "target": "aoe", "cd": 10, "cost": 5, + "volley": {"name": "Volley", "target": "aoe", "cd": 10, "cost": 5, "effects": [{"t": "aoe", "c": 0.9}], "auto": {"r": "aoe", "n": 2}, "tip": "Hits every enemy. 5 arrows."}, # Trades: one each, whatever the weapon. - "find_the_seam": {"name": "Find the Seam", "icon": "โ๏ธ", "target": "enemy", "cd": 30, "offgcd": True, + "find_the_seam": {"name": "Find the Seam", "target": "enemy", "cd": 30, "offgcd": True, "effects": [_aura("seam", 8, "target")], "auto": {"r": "debuff", "pct": 0.6}, "tip": "8s: its resistance doesn't count and its weakness counts double, for everyone."}, - "barricade": {"name": "Barricade", "icon": "๐ง", "target": "party", "cd": 40, "offgcd": True, + "barricade": {"name": "Barricade", "target": "party", "cd": 40, "offgcd": True, "effects": [_aura("taken", 8, "party", mult=0.75)], "auto": {"r": "danger", "pct": 0.6}, "tip": "Everyone takes 25% less damage for 8s."}, - "hearty_meal": {"name": "Hearty Meal", "icon": "๐ฒ", "target": "party", "cd": 30, + "hearty_meal": {"name": "Hearty Meal", "target": "party", "cd": 30, "effects": [{"t": "hot", "c": 0.3, "every": 2, "dur": 10}], "auto": {"r": "party_hot", "pct": 0.75}, "tip": "Everyone heals 5ร 0.3 of your hit over 10s."}, - "mark_prey": {"name": "Mark Prey", "icon": "๐พ", "target": "enemy", "cd": 30, "offgcd": True, + "mark_prey": {"name": "Mark Prey", "target": "enemy", "cd": 30, "offgcd": True, "effects": [_aura("vuln", 15, "target", mult=1.15)], "auto": {"r": "debuff", "pct": 0.6}, "tip": "It takes 15% more damage from everyone for 15s."}, } @@ -147,17 +147,17 @@ def role(style: str, shield: bool) -> str: # the enemy's average hit, damage type: None for its own). Telegraphed casts always land. ENEMY_ABILITIES = { - "heavy_slam": {"name": "Heavy Slam", "icon": "๐ฅ", "cast": 2.0, "every": 14, "first": 5, "interrupt": False, + "heavy_slam": {"name": "Heavy Slam", "cast": 2.0, "every": 14, "first": 5, "interrupt": False, "target": "target", "effect": ("hit", 1.6, "blunt")}, - "lunge": {"name": "Lunge", "icon": "๐ก๏ธ", "cast": 0, "every": 10, "first": 4, "interrupt": False, + "lunge": {"name": "Lunge", "cast": 0, "every": 10, "first": 4, "interrupt": False, "target": "soft", "effect": ("hit", 1.2, None)}, - "hex_bolt": {"name": "Hex Bolt", "icon": "๐ฅ", "cast": 2.5, "every": 12, "first": 3, "interrupt": True, + "hex_bolt": {"name": "Hex Bolt", "cast": 2.5, "every": 12, "first": 3, "interrupt": True, "target": "target", "effect": ("hit", 1.8, "magic")}, - "sweep": {"name": "Sweep", "icon": "๐", "cast": 1.5, "every": 16, "first": 8, "interrupt": False, + "sweep": {"name": "Sweep", "cast": 1.5, "every": 16, "first": 8, "interrupt": False, "target": "all", "effect": ("aoe", 0.8, "slash")}, - "fire_breath": {"name": "Fire Breath", "icon": "๐", "cast": 3.0, "every": 18, "first": 6, "interrupt": False, + "fire_breath": {"name": "Fire Breath", "cast": 3.0, "every": 18, "first": 6, "interrupt": False, "target": "all", "effect": ("aoe", 1.4, "magic")}, - "tail_swipe": {"name": "Tail Swipe", "icon": "๐ข", "cast": 0, "every": 12, "first": 7, "interrupt": False, + "tail_swipe": {"name": "Tail Swipe", "cast": 0, "every": 12, "first": 7, "interrupt": False, "target": "target", "effect": ("hit", 1.2, "blunt")}, } ARCHETYPE_ABILITIES = {"brute": ["heavy_slam"], "skirmisher": ["lunge"], "caster": ["hex_bolt"], diff --git a/game.py b/game.py index ea78704..439ad69 100644 --- a/game.py +++ b/game.py @@ -4640,6 +4640,22 @@ ACTION_GLYPHS = { "hunt_elk": ("deer", "#a07a50"), "hunt_sabrecat": ("saber-toothed-cat-head", "#e0a050"), "hunt_mammoth": ("mammoth", "#8a6a50"), } +# Abilities: yours by weapon and trade, then the enemies' (shown as they cast). +ABILITY_GLYPHS = { + "shield_bash": ("shield-bash", "#d4dae2"), "challenge": ("shouting", "#e0a050"), + "sweeping_cut": ("sword-spin", "#d4dae2"), "shield_wall": ("stone-wall", "#a8a29e"), + "crushing_blow": ("hammer-break", "#d1a46a"), "concuss": ("knockout", "#f0d060"), + "earthshaker": ("quake-stomp", "#c08850"), "unstoppable": ("enrage", "#e06a6a"), + "bolt": ("bolt-spell-cast", "#a77be8"), "mend": ("healing", "#5fae5a"), + "ward": ("energy-shield", "#8fb8f0"), "thornbind": ("thorny-vine", "#6f9a4a"), + "aimed_shot": ("target-arrows", "#e0a050"), "pinning_shot": ("arrowed", "#8fd0e0"), + "barbed_arrow": ("barbed-arrow", "#e05a5a"), "volley": ("arrow-cluster", "#5fae8a"), + "find_the_seam": ("armor-downgrade", "#d07a3c"), "barricade": ("barricade", "#d1a46a"), + "hearty_meal": ("cooking-pot", "#e0b04a"), "mark_prey": ("targeted", "#e06a6a"), + "heavy_slam": ("punch-blast", "#e06a6a"), "lunge": ("pierced-body", "#e06a6a"), + "hex_bolt": ("fireball", "#a77be8"), "sweep": ("spinning-blades", "#e06a6a"), + "fire_breath": ("dragon-breath", "#ff8a3a"), "tail_swipe": ("spiked-tail", "#c08850"), +} PRAYER_GLYPHS = {"thick_skin": ("shield", "#a8a29e"), "burst_of_strength": ("biceps", "#e06a6a"), "rapid_heal": ("heart-plus", "#e06a8a"), "steel_skin": ("armor-upgrade", "#d4dae2"), "superhuman_strength": ("biceps", "#ff8a3a"), "second_wind": ("wind-hole", "#8fd0e0"), @@ -4731,6 +4747,8 @@ def _assign_glyphs() -> None: spec["glyph"], spec["tint"] = BUILDING_GLYPHS[key] for prayer in PRAYERS: prayer["glyph"], prayer["tint"] = PRAYER_GLYPHS[prayer["id"]] + for key, ability in [*combat.ABILITIES.items(), *combat.ENEMY_ABILITIES.items()]: + ability["glyph"], ability["tint"] = ABILITY_GLYPHS[key] for action in ACTIONS: if action["id"] in ACTION_GLYPHS: action["glyph"], action["tint"] = ACTION_GLYPHS[action["id"]] @@ -4751,7 +4769,8 @@ def _assign_glyphs() -> None: def all_glyphs() -> set[str]: """Every glyph the game draws, for building the sprite.""" names = set(UI_GLYPHS) - for collection in (ITEMS.values(), SKILLS, CLASSES.values(), BUILDINGS.values(), PRAYERS, ACTIONS): + for collection in (ITEMS.values(), SKILLS, CLASSES.values(), BUILDINGS.values(), PRAYERS, ACTIONS, + combat.ABILITIES.values(), combat.ENEMY_ABILITIES.values()): names.update(entry["glyph"] for entry in collection) return names @@ -4781,6 +4800,7 @@ PATCH_NOTES = [ "Retreating is gone."), ("new", "Bosses and dragons are group fights (2+). Start one alone and you wait there for someone to join. " "They grow with the group: +75% HP for each fighter."), + ("fix", "Abilities, enemy casts and fight statuses have proper icons instead of emoji."), ("balance", "Enemies have 20% more HP for the same XP, since everyone has abilities now."), ("balance", "Boss hits: area bosses 1.35 โ 1.2ร and dragons 1.5 โ 1.9ร their level's max hit, then ร1.3 " "against a pair."), diff --git a/static/app.js b/static/app.js index d21e6cd..c48f1f1 100644 --- a/static/app.js +++ b/static/app.js @@ -38,7 +38,8 @@ const COIN = glyph("two-coins", "#e0b04a"), ANY_FOOD = glyph("knife-fork", "#d9c function iconise(content) { const entries = [...Object.values(content.items), ...content.skills, ...Object.values(content.classes), - ...Object.values(content.buildings), ...content.prayers, ...content.actions]; + ...Object.values(content.buildings), ...content.prayers, ...content.actions, + ...Object.values(content.abilities), ...Object.values(content.enemy_abilities)]; for (const entry of entries) if (entry.glyph) entry.icon = glyph(entry.glyph, entry.tint); return content; } @@ -938,7 +939,7 @@ function abilityBar(me) { const potion = me.health_potion; return `
`; + title="${esc(potion ? `${item(potion).name}: +${item(potion).drink} HP, once a fight under ${Math.round(C.potion_below * 100)}% ยท ${fmt(me.bank[potion])} left` : "No health potion")}">${item(potion || "health_potion_1").icon}${potion ? `${fmt(me.bank[potion])}` : ""}`; } // Prayers you can switch on and off between swings, and the points left to pay for them. @@ -966,18 +967,18 @@ function fightLine(e, f) { return `