You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

92 lines
14 KiB
Plaintext

<!--220310,220224-->
<h1>hostility</h1>
january 27, 2022<br>
#design #mechanic<br>
<br>
<br>
<h2>what is hostility? </h2><br>
Hostility is a state that a character's AI state machine can enter. More specific states will inherit from the hostile state to prompt targeting, aggressive, and defensive behavior. It's a very similar concept to <a href="https://wiki.guildwars.com/wiki/Aggro">aggro</a> in Guild Wars because weaving through patrol patterns and balling mobs is one of my favorite things from any game. <br>
<br>
<h3>when does a character become hostile? </h3><br>
NPCs generally will not seek out the player for combat. They will either stand stationary or follow their patrol route, oblivious of the player until becoming hostile. <br>
<br>
Usually, if an NPC is hostile, that means a threat got too close. Currently, proximities in Blessfrey mirror <a href="https://en.wikipedia.org/wiki/Proxemics">Edward T. Hall's zoning</a> for interpersonal distances. Intimate distance is the range for physical interaction and melee attacks and social distance is the range for assessing hostility and ranged attacks. <br>
<center><a href="https://en.wikipedia.org/wiki/Proxemics#/media/File:Personal_Space.svg"><img src="/static/img/ent/Personal_Space.svg" alt="(image: A visualization of proxemics by WebHamster of Wikipedia. Around someone are 4 concentric circles with varying diameters: within 25 feet is their public space, 12 feet is their social space, 4 feet is their personal space, and 1.5 feet is their intimate space.)" width="500" height="267.72"></a></center>
(By <a href="//commons.wikimedia.org/wiki/User:WebHamster" title="User:WebHamster";>WebHamster</a> - <span class="int-own-work" lang="en">Own work</span>, <a href="https://creativecommons.org/licenses/by-sa/3.0" title="Creative Commons Attribution-Share Alike 3.0">CC BY-SA 3.0</a>, <a href="https://commons.wikimedia.org/w/index.php?curid=6147809">Link</a>) <br>
<br>
An NPC will become hostile under a few conditions: <br>
<ul>
<li>An enemy faction member enters its social distance. Every character has a RangeBubble (Area2D) representing its social space. When a character enters range, its AI will assess both set of factions and change states upon finding a conflict. If there is a significant level disparity in the opponent's favor, though, the character will remain idle. </li>
<li>Someone attacked it or dealt damage to it. If their opponent isn't in range, they will become hostile and begin searching or ambushing. (There is no friendly fire, so teams aren't going to implode.) </li>
<li>Someone was damaged or attacked by it. Once again, if their opponent isn't in range, they will begin the hunt. </li>
<li>When the majority of a team is hostile towards an opponent, any team of the same faction or type entering the social space of the hostile team will also become hostile towards it. </li>
<li>When one member of a team becomes hostile, the others remain idle until aggravated. This allows skilled players to pull individual opponents away at a time without alerting the others and divide and conquer. This also prevents one foolhardy teammate from programmatically pulling aggro onto its entire team. </li>
</ul>
<br>
<h3>what changes when a character is hostile? </h3><br>
A hostile NPC will enter a combative AI state, usually with the goal of pursuing its opponent until either is killed or out of range. During combat, its passive health regeneration will slow, while energy regeneration will remain constant. Maybe certain skills and items can't be used during combat. If it has hostility towards multiple targets, it will prioritize targets according to its targeting AI state, probably favoring the nearest and weakest opponents. <br>
<br>
Each NPC will express hostility differently. Broadly, hostile behavior falls into 3 groups: offensive, defensive, and targeting. Offensive states may involve melee or ranged attacks, weapon attacks or offensive skill usage, single-target attacks or AoE, frontlining or backlining, and so on. Defensive states may involve buffing or healing, fleeing or kiting, protecting themselves or their teammates, and so on. The targeting state will allow the character to have unique opinions on who is most deserving of its attention. <br>
<br>
When a character becomes hostile toward the player, there will be feedback, such as battle music playing, the opponent's name turning red, or a sound effect playing. (Now I have the <a href="">Aion aggro sound effect</a> in my head.) <br>
<br>
<h3>when is a character no longer hostile? </h3><br>
An NPC will lose hostility under a few conditions:
<ul>
<li>Enough distance has spread between the NPC and its opponent. Usually, an NPC will not pursue an opponent very far. The farther the NPC is led from its idle route, the less tolerance it has to pursue its opponent. However, if pulled slowly, a few steps at a time, it can be led almost anywhere. </li>
<li>Its opponent exits the NPC's territory. Some NPCs have lines they will not cross. </li>
<li>Its opponent or itself dies. </li>
<li>The opponent no longer belongs to a conflicting faction. </li>
</ul>
<br>
<h3>what happens after a character is no longer hostile? </h3><br>
The character will return to its idle position or the nearest waypoint of its patrol route. Its passive health regeneration returns to its usual rate. Possibly some skills and items will be combat-only and will become disabled. <br>
<br>
<h2>hostility in action </h2><br>
This next section is mostly for me. Let's run through some faction clash examples after illustrating the relationship of teammates and allies.<br>
<br>
<br>
<h3>team hierarchy </h3><br>
Teams have a leader. If there are additional teammates, they will be followers of the leader. Teams can be allied with other teams. Generally, the leader of the ally team will become a follower of the main team's leader, while its teammates will be followers of their local leader. If a teammate has a pet, raises a minion, casts a summon, or triggers an event that grants it an ally, that character will be the leader of its own group, allied with the responsible teammate. Alliances can be gained or broken. <br>
<br>
Teams will be more or less oblivious to their allies' position and lose them if they aren't keeping up. They will support allies in combat, but they characters usually prioritize teammates over allies. <br>
<br>
<center><img src="/static/img/ent/team_hierarchy.png" alt="(A diagram of team hierarchy. )" width="500" height="375"></center> <br>
<br>
<h3>scenarios </h3><br>
<center><img src="/static/img/ent/teams_collide.png" alt="(An illustration of the chain resulting from paladins allying with a necromancer who summons a vampire who converts a ghoul who is friends with a chaos dwarf who build a war golem.)" width="500" height="375"></center> <br>
<br>
A, B, and C are in team 1. D is allied with them. They are preparing to attack the idle team 2 (V, W, and X with ally Y). Both teams will be spotted by the patrolling team 3 (M, N, and O with ally P) in a minute. Team 2 and 3 are members of the same faction, while Team 1 is of an opposing faction. A, B, and D are within range of either other, while C is investigating something just out of range. V, W, and X are within range, while Y is stuck behind a rock just out of range. M, N, and O are patrolling, while P walks too slowly to be in immediate range of the others. A, V, and M are leaders of their teams. They lead, while their teammates flock with them. Allies are members of their own team(s). Ally team leaders will follow the team leader of the main team, while their teammates flock with them. Allies can have their own allies, resulting in large trails of allied groups. Allies will not engage against allies or support direct enemies of their allies. Allies may engage against allies removed or support direct enemies of allies twice removed, though. <br>
<br>
Technically, allies are in their own team by themselves. Allies will flock within their own team and follow the general position of the main team or the individual teammate they are allied with. The main team will flock within their own team and ignore the positions of their allies. Allies will only share hostility with the main team through the coincidental case of being the same faction or type. <br>
<br>
<ul>
<li>A attacked V. V and A are hostile towards each other. B and D gain hostility towards V from being in range of A. W and Y gain hostility towards A from V. Now A, B, and D are opposed to V, W, and Y and vice versa and begin fighting. C and X are bound to cluster closer or be approached by opponents and join in soon. </li>
<li>A lays a trap. V walks into the trap and takes damage. A and V are now hostile towards each other. A and V will prepare for battle and begin hunting for each other. Their RangeBubbles will extend farther during this time. If they search for too long or travel too many steps without finding an opponent, they will resume their idle positions. If A finds an opponent, any teammates or allies within their RangeBubble will gain hostility towards the opponent and move within range. Combat will ensue. If very few or no members were in range of A, its team will idle on without it. If most members were in range, the remaining members will flock to their team and inevitably gain hostility and enter combat. </li>
<li>A one-hit-kills V from a safe distance. A becomes hostile and searches for an opponent. Team 2 is oblivious. </li>
<li>Teams 1 and 2 are hostile towards each other. Team 1 changes to the same faction. Teams 1 and 2 lose hostility. They will now consider each other friendly and possibly support each other. If one team gains hostility towards another team, the other will share hostility if still in range. </li>
<li>Teams 1 and 2 are friendly with each other and following each other. Team 1's faction changes to an adversarial one. They are all so close, they all gain hostility towards the other team's members immediately. </li>
<li>All of team 1 is hostile towards all of team 2. Team 3 enters range of team 2. All of team 3 gains hostility towards team 1 the moment a member of team 2 enters range of a single member of team 3. </li>
<li>Team 1 and team 2 are hostile towards each other with team 3 approaching. Ally P intersects with ally Y, triggering hostility between them. Teams 1 and 2 remain oblivious towards Team 3 and vice-versa. If team 3 starts going somewhere else, P will be left behind. Members of team 3 will gain hostility on a case by case basis as they flock nearby and inevitably get too close. </li>
<li>Team 1 and team 2 are hostile towards each other with team 3 approaching. Teammate M intersects with ally Y, triggering hostility between all of team 3 and ally Y. Team 2 will eventually enter the fray coincidentally. </li>
</ul>
<br>
<h3>ally chains </h3><br>
<br>
<center><img src="/static/img/ent/ally_chain.png" alt="(An illustration of the chain resulting from paladins allying with a necromancer who summons a vampire who converts a ghoul who is friends with a chaos dwarf who build a war golem.)" width="500" height="375"></center> <br>
<br>
If a necromancer is allied with a team of paladins, they will only enter hostility through their own terms. For instance, the paladins may attack a bear, but the necromancer will ignore it until the bear is a direct threat to itself. If the paladins attack another necromancer, the enemy necromancers will likely ignore the paladin-allied necromancer and never pose a direct threat. The allied necromancer may express idle supportive behavior like buffing the paladins, but it will remain idle. The politics of the main team trump that of other roaming teams. The allied necromancer will not enter combat with the paladins merely because it is the same type as the necromancers. It will also not idly heal the team that is currently directly opposed to its paladin allies. If the enemy necromancers were fighting a team of merchants, and the paladins completely ignore both groups, the necromancer ally will enter the fray in support of the necromancers and against the merchants. This may draw the paladins in, who will support the merchants and fight the necromancers. The allied necromancer will immediately lose hostility towards anyone directly opposed to the main team's leader. <br>
<br>
If the necromancer raises 2 liches, each lich is the leader of its own team, and each team is allied with the necromancer. Let's say the liches summon vampiric minions, one of which converts someone to an allied ghoul whose alliance remains constant with its chaos dwarf buddy who in turn is allied with its war golem. The paladin will respect the necromancer and liches but become hostile towards the vampires and all other evil monsters and vice-versa. In the case all these groups were factionless, the paladin would be neutral towards the vampires and everything else down the chain. Neutral characters are generally low priority in combat, but AoE attacks can easily whip up hostility. <br>
<br>
If the necromancer dies, the lich and paladins will no longer restrain themselves from becoming hostility towards each other. <br>
<br>
<br>
<h2>what I learned </h2><br>
Before, I was trying to force the combat state into flat booleans, but clearly there is more nuance to the issue. A character can be hostile but not in active combat. A character can be in combat but not hostile. Also, hostility is more of a product of a character's surroundings, actions, and actions inflicted on it. Structurally, it needs to resemble (extremely obviously) an AI state rather than any kind of variable. <br>
<br>
The characters' state machines now behave more like the above scenarios, and I'd love to make a cutscene-like demo for Blessfrey's second demo that sets differently factioned groups on clashing patrols to make sure it all works. Look forward to it! <br>
<br>
Last updated January 31, 2022
<br>