Summoning: familiar combat foundation, interactions, dialogue, foraging and boosts#1052
Draft
HarleyGilpin wants to merge 34 commits into
Draft
Summoning: familiar combat foundation, interactions, dialogue, foraging and boosts#1052HarleyGilpin wants to merge 34 commits into
HarleyGilpin wants to merge 34 commits into
Conversation
Port talk dialogue and special-op interactions for ~62 summoning familiars from a reference implementation, matching the existing per-familiar Script pattern (SpiritWolf/AbyssalLurker/AbyssalParasite). - Per-familiar Interact dialogue scripts (random + context-aware: inventory/equipment/stat/BoB-slot/run-energy/staged-state checks), grouped via wildcard ids for minotaurs, cockatrices, titan tiers, and gorajo/clay dungeoneering familiars. - Special ops: unicorn Cure (gated; inert until poison exists), pyrelord logs->firemaking, lava titan Lava Maze teleport, dreadfowl/compost mound Boost Farming. - Generic expression_familiar_* chathead animation family + unicorn cure anim/gfx; dialogue="familiar" + interacts=false on all scriptable familiars.
The generic expression_familiar_* family applied the shared cat head talk animations to every familiar's chathead model, which animates incorrectly for non-feline familiars. Drop the dialogue="familiar" override and the generic family so each familiar renders its own chathead model with no forced (wrong) animation. Correct per-familiar talk anims can be added later as expression_<familiar>_* families (via ::expr_scan), like the existing wolf/bird/leech sets.
Familiars are creatures; add large_head = true to every familiar npc def so their dialogue renders the bigger chathead (as cows, camels and other creature npcs already do).
Foragers (starting with Magpie) periodically gather loot from a forage_<familiar> drop table into the familiar's inventory while summoned, and the player retrieves it via the familiar's Withdraw/Take option (reusing the beast-of-burden inventory + interface). Players can't deposit their own items into a forager. - Forager script: 30s forage timer rolling the drop table into the familiar inventory, plus Withdraw/Take open handlers. Foragers are detected data-drivenly by the existence of a forage_<id> drop table (no new npc-def param, which must map to a real cache param). - forage_magpie drop table (gems/rings) in summoning.drops.toml. - Magpie marked as a beast-of-burden (cap 30) to reuse the storage + withdraw UI; store() rejects deposits into foragers. - Start/stop the forage timer on summon/dismiss. Other forager familiars are now just data: add a forage_<name> table.
Port the forage drop tables for beaver, spirit spider, granite crab, granite lobster, ibis, macaw (grimy herbs), compost mound, evil turnip, fruit bat, giant ent, stranger plant, void ravager and the cockatrice family, and mark each as a beast of burden (cap 30) so they reuse the forage inventory + Withdraw/Take interaction. Tables model the reference's "1/outOf chance, then drop one" via a 1/<roll> outer roll deferring to an `_items` sub-table for multi-item foragers (also corrects magpie, which previously dropped every tick). Item ids resolved to void string ids. Dungeoneering hoardstalker foragers (tier t1-t10) are deferred.
The farming boost was wrongly offered as a "Boost Farming" entry in a
Talk-to/Boost choice on Interact. Make Interact talk-only again and
trigger the boost from the familiar's special-move ("Special") option
instead, via the cast_dreadfowl_strike / cast_generate_compost buttons
on the summoning orb and familiar details tab.
The boost is on the familiar's "Special" right-click option, not the
special-move interface button. Use npcOperate("Special", ...) guarded
to the player's own familiar.
Clicking the dreadfowl's "Special" option now plays the asking-to-fight dialogue, the dreadfowl's special animation (7810) + gfx (1523, from darkanrs' Dreadfowl Strike sync), then boosts Farming by one.
Player plays gfx 1307 and the dreadfowl plays gfx 1317 alongside its special-strike animation (5387) when boosting Farming via the Special option.
The dreadfowl/compost-mound Special Farming boost now refuses to apply when Farming is already boosted (e.g. by a garden pie), and is stripped when the familiar is dismissed or dies (both route through dismissFamiliar) - only if it's still the active, unchanged boost.
Introduce a data-driven registry of the passive skill-level boosts a summoned familiar grants (beaver +2 Woodcutting, granite lobster +4 Fishing, obsidian golem +7 Mining, etc.) and a Player.familiarBoost function. The boost is read live from the active follower and added to the effective level in skill success checks - so it's invisible (not in the skill tab), never lets the player act above their real level, and disappears the moment the familiar is dismissed or killed. Wired into woodcutting, fishing, mining, firemaking and thieving. Hunter boosts (arctic bear, wolpertinger, kyatt, larupia) are in the registry but inert until the Hunter skill is implemented.
Summoned familiars now periodically shout a random overhead line every ~30s (driven by the existing familiar timer), matching RS. Lines are a data-driven map keyed by familiar id, sourced from the RuneScape Wiki transcript "Overhead dialogue" sections - 83 familiars covered. Phoenix and the gorajo (bloodrager/stormbringer/etc.) tiers have no overhead on the wiki and stay silent.
Replace the hardcoded Kotlin FAMILIAR_OVERHEAD map with a data-driven familiar_overhead table (list<string> "lines" column, keyed by familiar id), matching how the rest of the project stores config (e.g. the pet talk tables). The familiar timer reads it via Rows/Tables, so lines can be edited as data without touching code.
Familiars now play their own "fade into existence" animation (alongside the existing summon graphic) when summoned and when called. The per-familiar spawn anims are ported from darkanrs' Pouch spawnAnim values, mapped by npc id, as named <familiar>_spawn animation defs.
Split the grouped IronSteelTitan stub (a single grunt) into separate IronTitan and SteelTitan scripts with their full random talk dialogue, ported from the RuneScape Wiki transcripts (iron titan: 4 conversations; steel titan: 5).
darkanrs' albino rat spawn anim (16080) is outside void's animation cache. The albino rat reuses the generic rat skeleton (Base 1152) for its render anims; that skeleton's summoning-era animation is 8545 - matching how arctic bear (8522, bear skeleton) and the bats (8279, bat skeleton) take their spawn anim from their skeleton's list. 8545 is in cache range, so all 144 familiars now have a spawn animation.
albino rat spawn anim (16080) is outside 634 cache animation boundry. The albino rat reuses the generic rat skeleton (Base 1152) for its render anims; that skeleton's summoning-era animation is 8545 - matching how arctic bear (8522, bear skeleton) and the bats (8279, bat skeleton) take their spawn anim from their skeleton's list. 8545 is in cache range, so all 144 familiars now have a spawn animation.
…dialogues' into feat/summoning/interactions-and-dialogues
A player and its familiar count as one side, so they may both attack the same target in single-way combat: - Target.attackable exempts the owner<->familiar pair from the single-combat gate. - FamiliarCombat lets the familiar be sent at an NPC outside multi-combat when it's the owner's own target (offensive/defensive assist). Combat familiars now also grant their owner combat xp for the damage they deal - the owner's chosen melee style skill (or the familiar's range/magic type) plus Constitution - mirroring CombatExperience.
Familiars wouldn't approach a target they were sent at - they stood frozen and only attacked if it was already in range. Two causes: - Movement only ran pathfinding for players; NPCs used cheap single-step line movement that can't route around obstacles. Owned familiars now pathfind like players so they actually walk to the target. - CombatMovement applied the spawn/aggro leash to familiars, so a target beyond their ~9-tile aggro range (e.g. one commanded up to 16 tiles away) dropped them straight to EmptyMode. Owned familiars are now exempt from the leash - they chase what their owner directs and fall back to following when the fight ends.
Locks in the Target.attackable exemption: in a single-way zone (one attacker per target) the owner and its familiar count as one side, so the familiar may still join the owner's fight.
Reverts the single-way assist allowance: combat familiars can only attack in multi-combat zones. In single-way combat the player can still use the familiar (storage, foraging, special moves) but it won't assist in the fight. Removes the owner/familiar single-combat exemption from Target.attackable and the single-way assist path in FamiliarCombat.
Player and familiar are separate attackers under the single-way "one attacker per target" rule: - commandFamiliarAttack: drop the multi-combat-only gate so a familiar can be ordered to attack in single-way, but pre-check Target.attackable so it can't pile onto an NPC already under attack (e.g. one the owner is fighting), rejecting with a message instead. - assistFamiliar: auto-join only in multi-combat; in single-way the owner's target is theirs alone, so the familiar must be ordered at a separate NPC. Tests cover: ordered solo attack in single-way, no sharing from the player's side, no auto-assist in single-way, auto-assist in multi.
Covers the approach path (interact -> combat) for a target beyond the familiar's approach range, the scenario that wasn't exercised by the adjacent-target ordered-attack test.
When ordered/assisting, the familiar walked to its target via the interact-then-combat path. The interact mode gives up the instant a player or npc fully blocks the route (cantReach -> EmptyMode) and never re-paths once the obstruction clears, leaving the familiar frozen. Drive the familiar with CombatMovement directly instead: it re-paths every tick and (for npcs) never bails on cantReach, so the familiar routes around or waits out blockers and resumes as soon as they move.
NPCCharacterTargetStrategy.destination() returns Tile.EMPTY for npcs with an EMPTY walk mode. Familiars have that walk mode (they don't wander), so destination() always returned EMPTY and recalculate() short-circuited (EMPTY == cleared destination) - the familiar never re-pathed, following only its initial path. A stationary target worked; a target that moved/retreated left the familiar stuck at the old tile. Exempt owned familiars (owner_index set) from the stationary-npc short-circuit so they recompute a path to the target's current tile each tick and chase it.
Familiars persist in CombatMovement and never call cantReach, so an unreachable target (fled somewhere with no path) left them stuck chasing forever. Track ticks of no progress while still far from the target; if the familiar makes none for a short grace period it gives up and reverts to EmptyMode, which NPCTask turns back into following its owner. Moving, or being all but in range (just waiting on a free attack tile in a crowd), resets the grace period so genuine fights aren't abandoned.
When a familiar dealt the killing blow it was the npc's killer, but the death handler only drops loot (and grants slayer / logs the kill) when the killer is a Player, so familiar kills dropped nothing. Resolve a familiar killer to its owner so the loot drops for the player.
A plain npc killer has owner_index -1, and Players.indexed(-1) throws ArrayIndexOutOfBoundsException - so every npc-on-npc kill crashed the tick. Only resolve an owner when owner_index is set.
Combat data and wiring the familiar combat behaviour builds on: - summoning.combat.toml / summoning_combat.anims.toml / .gfx.toml: per- familiar combat definitions (stats, attack styles, anims, projectiles). - summoning.npcs.toml: combat stats and combat_def links per familiar. - gameframe.ifaces.toml: summoning orb / follower-details "Attack" option. - Summoning.kt: apply the wilderness pvp combat form on summon and call. - NPCTask.kt: an idle familiar resumes following its owner instead of wandering. - Combat.kt: retaliation anchors its leash via leashAnchor() (owner tile for familiars). - Attack.kt: resolve an npc's swing definition through combat_def.
In multi-combat the familiar engaged the owner's target on combatStart and (correctly) never switched mid-fight, but once its own target died nothing re-engaged it if the owner had since moved to another enemy - it just stood idle. Assist on the owner's combatAttack too: each hit an idle familiar joins the owner's current (last-attacked) target, while the idle guard still leaves an actively fighting familiar alone.
With world.players.collision on, a player stamps BLOCK_PLAYERS on its tile and an npc's blockMove (BLOCK_PLAYERS|BLOCK_NPCS) is the canTravel extraFlag, so a familiar couldn't step onto any player tile - standing between it and its target blocked it. Drop BLOCK_PLAYERS from blockMove for owned followers (familiars/pets) so they phase through players including their owner, while keeping BLOCK_NPCS; solid npcs already stamp FLOOR so the pathfinder still routes the familiar around them.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fleshes out summoning familiars: talk dialogue, special moves, foraging, skill boosts and overhead chat.
Talk dialogue & chatheads
Special-move (Special) interactions
Foraging
Passive skill boosts
Overhead dialogue