DevLog: Reimagining Polar Bears - Drakonkinst/DrakonsDatapacks GitHub Wiki

DevLog: Reimagining Polar Bears

By Drakonkinst

Hello there!

Here, I've written far, far too much about what has become one of the most fun datapacks I've worked on to date: Improved Polar Bears, which fully overhauls Polar Bears, a largely forgotten mob that was introduced in the 1.10 Frostburn Update back in 2016.

This DevLog is a technical deep dive, design doc, detailed wiki, and postmortem rolled into one. You may not understand everything, but you might pick up new details about the Polar Bear's new mechanics that I don't mention in the datapack's overview! This document will assume that you're somewhat familiar with Improved Polar Bear's features and does not explain everything in order, so read the original doc first!

Design Goals

As a part of the Improved Mobs datapack series, this datapack aims to bring additional behavior and features to Polar Bears to create more interesting gameplay experiences. For Polar Bears, we set out to accomplish the following:

  • Make Polar Bears more interesting and closer to their real-world counterparts without incentivizing players to kill them.
  • Make Polar Bears appropriately fearsome as an apex predator and incentivize players to keep their distance instead of simply slaughtering them.
  • Give Polar Bears autonomous behaviors to create a sense of immersion outside of player interaction.

Stat Boosts

Statline changes are simple but the most straightforward step to reworking Polar Bears. When considering the stats of Polar Bears, we mainly considered two other mobs as precedent: Hoglins and Ravagers. While Polar Bears do not hunt in as large of a pack as Hoglins, indicating they should be slightly stronger individually, they should not be as powerful as the Ravager, which is a much larger creature that spawns as a mini-boss during Raids.

This led to the following chances, with the (original vanilla values) in parentheses.

  • Health (30): Hoglins have 40 health and Ravagers have 100, so we decided on 80 health to mix between the two and make Polar Bears more threatening.
  • Damage (4/6/9): Hoglins deal 5/8/12 damage and Ravagers deal 7/12/18 damage based on game difficulty. We decided to bring this in line with Ravagers, to 7/12/18 damage (nearly doubled from vanilla values).
  • Knockback Resistance (0): Hoglins have 60% knockback resistance and Ravagers have 75% knockback resistance, which aid both in not being able to be pushed around (which in turn makes them more terrifying). Therefore, we decided to also bring this in line with Ravagers, to 75% knockback resistance.
  • Follow Range (16): The default follow range for all mobs except for Zombies is 16 blocks, where Zombies have 40 blocks. Since Polar Bears are masterful hunters but we don't want them to chase players too far, we decided to increase this to 20 blocks to give a little extra room to track.
  • Movement Speed (0.25): Polar Bears are a bit too slow, so we brought them up to 0.3 to bring them in line with Hoglins. Fortunately, this also affects swimming speed, making them slightly faster in the water!

Shield-Breaking

In addition, we took the opportunity to sneak in a new ability by modifying the Polar Bear's equipment: By making the Polar Bear hold a wooden axe in their mainhand (which does not appear on their model), all attacks from the Polar Bear also disable Shields as if it were an axe strike. Since Shields are often used as a form of ultimate protection in the current version's combat system, this was an appealing addition to enhance the power of the Polar Bear's blows and remove one of the primary strategies for dealing with them, making them more fearsome overall.

This axe is set to 0 damage so it does not add additional damage, is Unbreakable, and also never drops upon death, so it is essentially invisible to players. Since it is not named, it does not show up in death messages either!

AI Targeting

While it might seem that "making Polar Bears hostile" is a simple task, the new AI behaviors of Polar Bears are by far the most advanced component of this datapack.

Mechanisms

Since datapacks do not support direct AI modification, a number of tricks were used to manipulate the AI into accomplishing new behaviors. These tricks revolved around three main mechanisms.

First, since vanilla Polar Bears are a neutral mob, they come with two key NBT tags. These tags are unique to neutral mobs and not found in hostile mobs, which provides an opportunity to manipulate AI further than what would normally be possible.

  • AngryAt: Stores the UUID of the entity they are angry at. If the Polar Bear is not currently angry at anything, this tag does not exist.
  • AngerTime: The duration (in ticks) that the Polar Bear will remain angry while they cannot see the target. This timer pauses while the Polar Bear is actively tracking the target, and it drops aggro if 1) it can no longer see the target and 2) AngerTime is 0.
    • In vanilla, this is set to a random value between 400 and 800 (20-40s) whenever the mob becomes aggressive.

In addition, the new /execute on target command allows us to get the entity that the Polar Bear is currently targeting, also known as the target. This does not always line up with AngryAt: the Polar Bear must have line of sight and be actively following the mob to consider it a target. Furthermore, it can target creatures that it is not necessarily angry at according to its AngryAt NBT. Overall, this tag represents what the Polar Bear is actually doing, rather than what we want it to do (which is more or less represented by AngryAt).

The third factor that allows us to manipulate AI is follow range, the distance at which Polar Bears can track and follow targets (currently 20 blocks due to the Stat Boosts section). Note that this is different from the range at which they aggro; since we control this manually, this only determines how far away the Polar Bear can keep following once aggro'd, after which pathfinding fails entirely.

Basic Version

The premise of making Polar Bears aggressive is simple: if there is an entity it can aggro against nearby and the Polar Bear is not currently angry, set AngryAt to match that entity's UUID and set AngryAt to a positive value. Due to Minecraft NBT bugs, setting this manually has a chance to fail: therefore, we apply it 4 times per second, which is fast enough to keep this behavior relatively consistent.

However, this quickly becomes hard to control: once AngryAt is set, the Polar Bear stays aggressive against that mob even if AngryAt is set to another target mob (or is removed entirely). In addition, attempting to reset AngryAt and AngerTime NBT while the Polar Bear is actively chasing a mob is entirely ineffectual, and the values simply get replaced the next tick.

Finally, there is the issue of priority: Polar Bears become single-mindedly fixated on the targeted mob, and will ignore other targets that are closer or ones that are potentially more threatening. For example, a Polar Bear fixated on catching a Salmon will entirely ignore an approaching player, even when that player starts attacking! These issues make the Polar Bear's AI clunky and call for a more complex approach.

Targeting Ranges and Categories

First, we categorized mobs that the Polar Bear could target into different categories. We want Polar Bears to be hostile but not evil: while they attack anything that comes close, they generally do not seek out targets outside of prey they actively hunt, namely Salmon and other fish. In addition, mobs that can fight back should be treated with higher priority than mobs who cannot, as we want the Polar Bear to be smart enough to respond to potential threats.

This leads to the following three categories that the Polar Bear can aggro against.

  • Threats: Mobs that the Polar Bear will attack that it expects to fight back, but will not try to seek out.
  • Prey: Mobs that the Polar Bear will attack, but will not try to seek out.
  • Favorite Prey: Mobs that the Polar Bear will attack and actively try to seek out.

When excluding mobs from these lists, flying mobs are generally ignored. In addition, certain mobs in Minecraft spell certain death or at least grievous injury for Polar Bears: while Polar Bears in the real world are completely fearless, Polar Bears in Minecraft have evolved to respect some mobs out of their own self-preservation, as trying to attack these mobs would be near-suicidal.

Threats

This list includes: Players, Golems, Pillagers, Spiders, Zombies, Skeletons, Piglins, Endermites, Silverfish, Slimes, Magma Cubes, Hoglins, Shulkers, Witches, and Zoglins.

Polar Bears can aggro against mobs from this list from 8 blocks away, which means they will only attack if they get close. Outside of a few exceptions listed below, this represents how Polar Bears will attack almost anything—this also opens up creative uses for Polar Bears, such as employing them to defend your backyard against other mobs.

An oddity on this list is the Iron Golem, which will frequently be victorious against Polar Bears as they have even higher health and damage. However, Iron Golems do not attack Polar Bears: therefore, it would be strange if Polar Bears could attack Villagers without consequence. Therefore, we decided to keep Iron Golems in this list so that Iron Golems can effectively defend their village.

This list does not include:

  • Creepers: Due to the prospect of mutually assured destruction, not even Iron Golems attack Creepers.
  • Guardians, Zombified Piglins: These mobs which usually group together and attack in hordes, making them incredibly dangerous for Polar Bears to attack.
  • Wolves: As a design courtesy to players, Polar Bears do not actively target pets unless directly attacked by them.
  • Phantoms, Ghasts, Blazes, Vex, Wither, Ender Dragon: Polar Bears do not try to go after flying mobs.
  • Wither, Ender Dragon, Warden: Polar Bears know better than to try to take on these mobs.

Prey

This list includes: Villagers, Llamas, Horses, Chicken, Cows, Foxes, Frogs, Mooshrooms, Ocelots, Pigs, Rabbits, Sheep, Turtles, Dolphins, Goats, Pandas, and Tadpoles. This comprises the majority of passive mobs in the game, which makes Polar Bears a threat to villages and livestock.

Polar Bears can aggro against mobs from this list from 12 blocks away, which is slightly further than for Threats to make tracking these mobs more consistent.

This list does not include:

  • Cats, Allay: As a design courtesy to players, Polar Bears do not actively target pets unless directly attacked by them.
  • Parrots, Bees, Allay: Polar Bears do not try to go after flying mobs.
  • Undead Horses: Skeleton and Zombie Horses are of no interest to Polar Bears, as they pose no threat but also provide no food.

Favorite Prey

This list includes Salmon, Cod, Tropical Fish, Squids, Glow Squids, which comprise some of the most common sea creatures. Only Salmon and Squids naturally spawn in the same biomes as the Polar Bear, but the other mobs are similar enough that Polar Bears will treat them the same way.

Polar Bears can aggro against mobs from this list from 20 blocks away, which will often lead them to faraway chases and create migratory behaviors while hunting as they move between food sources.

This list does not include:

  • Turtles, Dolphins, Tadpoles: While sea creatures, Polar Bears do not prefer to hunt them as much as other creatures on this list and will not go out of their way to kill them.
  • Axolotls: Axolotls are frequently pets for players and do not attack Polar Bears on their own, so this falls under similar logic as Wolves and Cats.

Selecting a Target

If a Polar Bear is not currently angry at anything (based on AngryAt), it will attempt to search for a new target. Upon finding one, it will set AngryAt to the target's UUID. It will also set AngerTime to 40 for Prey/Favorite Prey, which is a much smaller value than normal so that Polar Bears will switch targets more quickly when hunting prey. For Threats, AngerTime is set to 400, which is the minimum value of the 400-800 range. This value was chosen because Polar Bears have a much wider variety of possible targets than most mobs, so it should switch on the quicker side; in addition, it did not seem worthwhile to code this to pick a random value.

Polar Bears will attempt to find a mob from Threats, then Prey, then Favorite Prey, in that order with the aforementioned ranges; if it finds a matching mob it will not consider the remaining categories. This may seem counterintuitive since Favorite Prey is last; however, "favorite" prey is better read as the "most common" prey; therefore, we decided it makes more sense to go in order of distance (and place Threats first, since this includes players).

This ensures that if a Polar Bear is not currently targeting anything, it will always select the appropriate (and usually the closest) target. However, this has a limitation: if the Polar Bear is already targeting a mob, it will not switch targets if something more important comes along. Specifically, consider the example of a player approaching while the Polar Bear hunts for Salmon. Ideally, the Polar Bear should switch targets to the player as soon as they come close, but the current system does not provide a mechanism for this.

Prioritization and Re-Targeting

The main objective of target prioritization is to allow Polar Bears to switch targets from prey to threat. It is not concerned with differentiating Prey and Favorite Prey mobs since it is not important to actively switch targets between, so these are considered the same group for prioritization.

As mentioned in the problems in the Basic Version of the AI, removing AngerAt and AngerTime NBT while the Polar Bear is actively targeting a mob does not stop it from pursuing that mob, nor does it switch the targets by changing AngryAt. In other words, modifications to AngerAt do not affect the target, which can be tracked using /execute on target.

This is where follow distance swoops in to save the day: Polar Bears cannot pursue mobs outside its follow distance. Therefore, modifying follow distance can control if the Polar Bear is currently aggressive or not: namely, if the follow distance is set to 0, then the Polar Bear cannot target anything at all.

Using this mechanism, we implemented an emergency stop mechanism that sets the Polar Bear's follow distance to 0, preventing it from targeting anything and adding the tag dc_polarBearStop to mark that it cannot currently target anything. We then implement the inverse start mechanism that restores the follow distance to 20 and removes this tag.

When do we apply these tags? In other words, how do we know when to switch targets? First, we keep track of which type of mob (prey or threat) the Polar Bear currently intends to target (based on whoever AngryAt is set to). This adds the tag dc_aggroPrey or dc_aggroThreat based on which type of mob it should currently be aggressive towards. Then, we can check which type of mob is currently being targeted using /execute on, which sets a scoreboard variable #AggroType to 1 or 2 depending on if a prey or threat is targeted (with 0 or null representing no current target).

Note: We used two tags, dc_aggroPrey and dc_aggroThreat, in place of a scoreboard value such as 0, 1, 2 (like we did for #AggroType) to avoid using an extra scoreboard. We would need a separate scoreboard because we need to remember these values over time, whereas #AggroType is the value at the given instant. We assume the tags are mutually exclusive, which provides a form of one-hot encoding that avoids needing to create a brand new scoreboard.

In the case that the Polar Bear is not currently angry at anything, it will have the tags equivalent to 0, which is to say, neither dc_aggroPrey nor dc_aggroThreat. Therefore, a majority of checks should account for this null case: if we're interested in whether a Polar Bear is angry at prey, we should check if it doesn't have dc_aggroThreat instead of checking for the presence of dc_aggroPrey.

To modify AngryAt while already angry at another mob, we implement an interruption check where if the Polar Bear is not already targeting a threat, it checks for nearby threats. If one is found, it removes AngryAt, which prompts the AI to select a new target and locate the new threat. While this sets AngryAt properly, setting AngryAt to the new target is not enough to switch the attacking behavior.

Next, we run a validation check to see if the mob targeted by AngryAt, which we can determine based on the presence of the dc_aggroPrey and dc_aggroThreat tags, matches the mob that is currently targeted, determined by #AggroType. If the mob types do not match (having dc_aggroPrey while #AggroType is 2 or having dc_aggroThreat while #AggroType is 1), we detect a contradiction: the Polar Bear is not targeting the mob (or at least, the type of mob) we want them to target!

Note: This system only checks if the Polar Bear intends to target a prey but is targeting a threat, or vice versa. It does not check the mob's actual identity or if the UUID of the mob targeted is the same as the one in AngryAt, nor does it really need to. This contradiction is all we need to check for to ensure that the prey-to-threat target switch works in an intuitive way.

Now that we detect a contradiction, we can call our emergency stop to stop the Polar Bear from targeting anything. This takes a couple ticks to fully propagate, leaving the Polar Bear tempoarily confused as it waits for the target NBT to disappear. Note that this system does not remove AngryAt NBT upon the emergency stop, allowing it to keep its intent to target whatever mob interrupted it.

Once we detect that a Polar Bear that has been stopped (with the tag dc_polarBearStop) is no longer targeting anything (using /execute on), we can re-enable its targeting with the start mechanism that restores its follow range, allowing it to detect and become aggressive towards the new, correct target.

While this was a lot of work to get going, it works quite well—Polar Bears appropriately switch from hunting prey to threats whenever they detect one of the latter nearby. In addition, the emergency stop/start mechanism is usable for other mechanics, whenever we want to stop the Polar Bear from targeting anything.

Giving Up

There's one additional feature we can give to the AI: when hunting fish, they often swim into the deep sea, beyond the reach of the Polar Bear's Lunge (see the Lunge Ability section below). However, the Polar Bear doesn't know this: as long as the fish is within its 20-block follow range, even if it's 20 blocks below the Polar Bear, the Polar Bear will remain in pursuit and get stuck in a hopeless hunting expedition for indeterminate periods of time.

Therefore, we wanted the Polar Bear to give up its chase if its target was too far below it, indicating that it was likely too deep to dive. In addition, this "giving up" mechanic should only apply to prey: The Polar Bear should be more than happy to wait for drowning players to return to the surface.

To accomplish this behavior, we added two checks: first, when initially selecting a prey as a target, the y-values of the Polar Bear and target are compared. If the target is more than 8 blocks below the target, which represents the Polar Bear's maximum diving distance, the aggro is cancelled. Since the prey this most often applies to, the Favorite Prey, are already selected last and they are selected in order of proximity, the mob that was checked was already the worst case target. Therefore, we minimize the risk of failing to find a target if there is actually one available due to this check.

However, the prey could begin within the Polar Bear's range and then swim further downwards. Therefore, we implement another check running once per 5 seconds that checks if the targeted prey is more than 10 blocks beneath the target, adding some extra leniency in case the target moves upward again and allowing the Polar Bear to be slightly more persistent. In this case, cancelling aggro must be done with the emergency stop, since the target is already selected. The target will not be re-selected immediately due to the first check ruling it out, so this behavior is complete.

Lunge Ability

The Polar Bear's new Lunge ability was born out of a number of factors. First, we assumed early in the design that Polar Bear swimming speed was not affected by base movement speed (which, pleasantly, turned out to be false). Second, even with enhanced swimming speed, Polar Bears cannot go underwater, which heavily reduces their ability to go after fish and other prey. Therefore, introducing a dash ability allows Polar Bears to dive underwater to catch their prey, as well as charge rapidly towards victims on land, serving multiple thematics.

Motion

The main mechanism for the Lunge ability is Motion NBT, which applies velocity in a target direction. This is a far smoother mechanism for Motion than incremental teleportation, which both looks more jagged (since it doesn't interact with gravity and other forces) and also does not take collision into account, leading to potential suffocation issues.

The Lunge direction is calculated with the same NBT trick as Modular Boats, which took both the current coordinates of the entity and the coordinates "in the direction of where they want to go", subtracting the two to generate a Motion vector. Unlike Boats, which can only move horizontally, this Lunge was calculated over all three axes, allowing the Polar Bear to dash upwards and downwards.

Note: How does Motion really work?

Motion is a tricky mechanic to work with, primarily because they do not equate to the mob's movement, but do allow velocities to be applied to them. Other code can update the mob's Motion, though it is inconsistent as to whether this is the mob's movement or other factors like knockback or explosions—to make matters worse, player Motion (as well as the Motion of anything controlled by a player) is read differently than entity Motion, and cannot be modified. Note that Motion does not use blocks/time as exact units: in other words, a Motion vector of [1.0d, 0.0d, 0.0d] will not move the mob exactly 1 block in the x-direction. However, it does correlate: high values means the mob moves further.

Motion naturally takes gravity and friction (as they exist in Minecraft) into account, creating some unique properties.

  • Velocity on land due to Motion NBT is generally lower than velocity in water, giving Lunges far more range and speed underwater as they also retain their momentum longer than on land.
  • Due to gravity, velocity upwards is generally lower than velocity downwards.

This Motion vector is calculated with a base magnitude of 1, where higher magnitudes would make the Lunge go further. Since scoreboards only store integers, this value is also scaled up by 50 for decimal precision when calculating, then scaled back down (by 1 / 50 = 0.02) when applying the Motion.

Note: Why scale by 50?

A scaling factor of 50 is a good default for coordinates. While usually precision scales by a factor of 10, we discovered while developing Modular Boats that it is possible to run into integer overflow errors if too large of a scaling factor is chosen. Since Minecraft worlds are limited to 30 million blocks in any direction, scaling by 50 means the maximum stored value is 1.5 billion, which stays below the integer limit of 2,147,483,647 (2.1 billion). If we scaled by 100 instead, we would hit up to 3 billion, which would max out the scoreboard and lead to improper calculations.

Technically, a scaling factor of 71 would maximize precision while staying within integer limits (up to 2,130,000,000), but this runs into rounding errors when scaling back down (and also makes us very, very sad).

This behavior already produced promising movement, though we wanted to make sure that Polar Bears could still be strong swimmers while not being able to make grand leaps on land, which would be unrealistic. Therefore, we introduced the following tuning factors to amplify or dampen the Lunge based on the situation:

  • If the Polar Bear is in water, any Lunge significantly upward is increased by 30% in the upwards direction. This allows Polar Bears to (somewhat inconsistently) leap 2 blocks out of water to "climb" onto a tall ledge from the sea.
  • If the Polar Bear is in water, any Lunge significantly downward is increased by 40% in the downwards direction, which increases their dive depth when hunting prey.
  • If the Polar Bear is on land, any upwards or downwards movement is limited to 30% of the maximum value in that direction. This limits Polar Bears to shorter "hops" that can jump approximately 1.5 blocks at best.

Damage

We decided that Lunges should also damage mobs that the Polar Bear collides with, representing being caught by its claws or simply being body-slammed by the Polar Bear. Using the /damage command can also inflict knockback, which helps the attack feel more powerful.

When is damage dealt? Our final implementation damages entities on contact with the Polar Bear (to be specific, being within 2 blocks—which might seem generous, but makes the hit detection more intuitive). However, each entity can only be damaged once by a single Lunge, to prevent double-dip combos.

Polar Bears only deal this contact damage when Lunging, so how do we define this? Using a scoreboard dc_polarBearLunge, we define the first 20 ticks (1 second) after a Polar Bear Lunges to be the "Lunging" state, during which it can deal damage. We use this same scoreboard to define a cooldown of 150 ticks (7.5 seconds), creating a cycle where Polar Bears Lunge for a certain duration, then go on cooldown, then become available to Lunge again.

How much damage is dealt? We decided to keep this ability focused primarily on mobility rather than damage (see Other Iterations for more information), so its damage is (relatively) light compared to its normal attack at 7 damage. This does not scale on game difficulty (though perhaps it should).

Which mobs can be damaged? It became apparent that the mobs that should be damageable by the Lunge ability was more than simply the mobs that Polar Bears could target. For example, although Polar Bears do not aggro against Creepers (for self-preservation), it would be strange if a Polar Bear Lunged straight through a Creeper without damaging it (and suffering the consequences).

Since Polar Bears cannot target some mobs directly, we took this opportunity to be more liberal with what mobs could be damaged if caught in the crossfire of a Lunge. This is controlled by the dc_polar_bear:lunge_damageable tag, which contains the following:

  • All mobs that the Polar Bear can aggro against.
  • Boats and Minecarts (we also added a special sound effect when breaking Boats, to further communicate how it was destroyed).
  • All mobs except for Polar Bears, including ones it normally wouldn't attack such as Creepers and pets such as Wolves, Cats, Parrots, and Axolotls.

Timings

Polar Bears should not Lunge too frequently; since this is an expensive operation to begin with, the Lunge check only occurs once per 5 seconds. This has ramifications on the previous cooldown, as a cooldown of 7.5 seconds really equates to 10 seconds since it only checks every 5 seconds. There is an argument to accelerate the Lunge check to once per second, which would make the scoreboard cooldown more accurate, but we do not think this is necessary and did not significantly impact the player experience.

In addition, we introduced a 25% chance to skip the Lunge every 5 seconds, even if every other condition was met. This extends the expected duration between Lunges to approximately 12 seconds, introducing some natural variation that prevents the Lunge intervals from feeling too rhythmic and artificial.

Other Iterations

The initial design included a warning cue to telegraph the Lunge, such as a growl sound effect or storm cloud particles. In addition, it included additional damage and crippling Slowness on its "primary target," or whoever they were targeting prior to the Lunge, as if they were "pouncing on" the target. Coordinating the warning cue to be consistent with an upcoming Lunge while possibly switching targets, as well as making the Polar Bear stand still to indicate preparation, seemed more clunky and out of tune with vanilla mechanics—very few mobs have an extended telegraph, since Minecraft's combat is not nearly as strategic and deliberate as a game like Dark Souls.

Therefore, we made the decision to skip the warning cue keep the Lunge ability more chaotic, allowing Polar Bears to Lunge without warning. The audio cue of the Lunge still provides some level of communication about the attack, which can be useful to dodge if you are far enough away. Consequently, we also removed the idea of a "primary target" of the Lunge, removing the high penalty for failing to dodge the attack because there is no proper cue to indicate a powerful attack. This made the Lunge less impactful for damage, but more impactful for mobility, allowing the Polar Bears to fight in interesting and surprising ways.

Another part of the initial design specified that Polar Bears should not Lunge at certain angles, such as directly upwards or downwards. We decided not to implement this restriction due to:

  1. Block collisions can cause dashes in these directions even if that is not the target's direction, making this hard to enforce.
  2. Calculating the angle between a target and the Polar Bear is nontrivial.
  3. Preventing the Polar Bear from Lunging in certain situations becomes clunky and will only serve to "disable" their Lunge ability at certain times, making them less powerful and consistent.

Finally, the initial design also specified that Polar Bears should only Lunge at certain ranges, such as if their target was between 5 and 15 blocks (not too close nor too far). For a similar reason as #3, we decided to remove this restriction to make Lunges more consistent and powerful. This also allows Polar Bears to dash past their victim in some situations, which increases their dynamic movement.

Breaking the Ice

An issue called out early in design was that if diving underwater, Polar Bears might get stuck under ice and drown, which would be quite an unfortunate way to die. Similarly, Polar Bears do not know how to navigate around ice when tracking prey and will often stand above their underwater prey on the ice, looking downwards but not being able to react their target.

To protect Polar Bears from an untimely demise and allow them to reach targets more easily, we decided to allow Polar Bears to break ice that blocks their movement. Decisions to let mobs break blocks must be taken carefully, as Minecraft's design philosophy revolves around the idea that the player is the only one who can meaningfully modify the world. However, if the ice breaks into water, then it can re-freeze to become ice if in a cold biome, and the terrain is not permanently damaged. Therefore, we decided this was still in line with Minecraft's design philosophy.

Polar Bears break ice in two primary ways:

  • If Polar Bears are in water, they break a 3x2x3 area of ice around them every second. This is sufficient in most cases (see Lung Capacity) of breaking through ice that prevents them from returning to the surface.
  • When Polar Bears use their Lunge ability to dash downward, they also break ice beneath them. This usually "consumes" a Lunge tick, as the Polar Bears do not actually travel anywhere if blocked by ice; this provides a natural delay between breaking ice beneath them and diving after their target, which helps the Polar Bear's Lunges be less surprising.

Lung Capacity

Note that Polar Bears cannot break any other blocks, including Packed Ice and Blue Ice, which means they can still drown under icebergs or other blocks under the sea. To further assist Polar Bears not drowning, we extended their air capacity underwater from the standard 15 seconds to 3 minutes, which matches real-world records.

This does not help Polar Bears escape these situations, but gives them more time so they have a slightly better chance of surviving. Unfortunately, Polar Bear AI is naturally lethargic, and they seem to roam much less frequently than other mobs. However, they can still be shaken out if prey such as Salmon roam nearby, incentivizing the Polar Bear to Lunge at them and break free of whatever is keeping them underwater.

Eating

While Polar Bears can attack fish, they should also be able to pick up and eat them. Since Polar Bears cannot inherently pick up items, they run a check every second to automatically pick up nearby fish within 3 blocks.

To implement this, every item spawned near a Polar Bear is examined (using utility armor stands) to check if the item matches the #dc_polar_bear:likes_to_eat item tag. While this only includes Salmon in the current version, this provides the option for more foods to be added easily without hardcoding each of them in (besides, funnily enough, the additional complexity required to make sure the right eating particles appear based on the food).

Note: Although we decided to only let the Polar Bears eat Salmon, it would be more realistic if it ate other fish as well, such as Cod and Tropical Fish. However, for the sake of both simplicity and staying true to Minecraft, they only have 1 favorite food: the fish that also spawns in the same biome.

Polar Bears only pick up one item at a time: if there are multiple Salmon in a stack, they only pick up one to eat (because they're very courteous eaters). This solves a number of issues, such as avoiding needing to "queue" multiple fish to eat and allow a group of Polar Bears to share nearby food.

When picking up food, the start eating function is called, which sets a scoreboard dc_polarBearEat that represents how long the Polar Bear will eat for. While players eat at a rate of 1.61s per item, Polar Bears take more time for reasons discussed below: Polar Bears give off eating particles for 4 seconds (playing sounds and particles 4 times per second), then take another second to digest before finishing their meal. Once the 5 seconds are up, the Polar Bear can grab another fish. This adds natural pauses to eating, instead of a continuous crunchcrunchcrunch when eating multiple Salmon at once, and also feels a little more realistic.

Since, like most mobs, where the code considers the mob's head to be is not always accurate depending on its rotation (see MC-86467), we decided not to try to superimpose a fish model in its mouth (like how Foxes hold items in their mouths). This desync is still visible with particles, but is much less noticeable.

Stored Food Regeneration

We also wanted this eating to have a gameplay function, taking an opportunity to add more autonomy to Polar Bears. One of our primary pet peeves with mobs in Minecraft is that the majority of mobs cannot naturally heal. This would especially hurt the presence of Polar Bears, who get into a fight with a wide variety of mobs and might be extraordinarily weak when they actually come across a player.

Therefore, we decided to introduce stored food, represented by a new scoreboard dc_polarBearFood. This scoreboard increases every time a fish is eaten, and can be decremented to give 1 second of Regeneration whenever the Polar Bear is below maximum health.

In terms of balancing, we settled on the following values:

  • Each point of stored food grants Regeneration III for 1 second, which heals approximately 1.667 health per second.
  • Each fish grants 8 points of stored food, which equates to 13.333 possible healing over the course of 8 seconds (17% of the Polar Bear's health).
  • Polar Bears can store up to a maximum of 48 points of stored food, or the equivalent of 6 fish.

The Regeneration provided is fast, but not overly so: it becomes more of an issue when facing a Polar Bear over an extended encounter (like dying and coming back to collect your gear), but Polar Bears can be killed before they have the chance to fully regenerate to nullify some of this bonus. This gives Polar Bears added survivability and endurance, and signals to the player that Polar Bears that live on the waters are likely more well-fed than those they find on land, and are even more of a threat. The Regeneration also displays visible particles to communicate to the player that the Polar Bear is healing.

Eating to Distract

Another feature added to the AI was preventing the Polar Bear from targeting a new mob while it was eating. In addition to giving more natural pauses to enjoy its meal while hunting, this provides an option to distract the Polar Bear. If players can throw fish towards a Polar Bear without getting too close (which is dangerous, though not impossible), they can approach and pass by safely while the Polar Bear eats the fish. This nonviolent alternative to getting around Polar Bears provides an additional level of player interaction, while still keeping an element of danger in case something goes wrong.

This provided a design incentive for:

  1. Making Polar Bears eat for much longer than players (5 seconds instead of 1.6 seconds), giving a larger window to go near the Polar Bear.
  2. Allowing the Polar Bear to eat even when it is full in terms of stored food, making it more consistently distractable.

While players can attempt to throw a stack of fish at a Polar Bear to distract it for long periods of time, there is a brief window between picking up a new fish where the Polar Bear has a chance to become aggressive if the player is close enough. We prefer this interaction, as it encourages players not to stay near Polar Bears too long.

Other AI Modifications

Polar Bears only seek out food to eat if they are not attacking a threat, so they do not pause for a snack in the middle of combat (though they can while they are hunting defenseless prey). In addition, striking the Polar Bear causes it to stop eating immediately: it does not gain the benefits of stored food since the eating never finishes, but can immediately become aggressive against whoever interrupted their meal.

Breeding

Hoglins can breed despite being fully hostile mobs, so we decided it would be neat for Polar Bears to have a way of repopulating on their own (besides just spawning in). This would complete their behavior set into a fully autonomous ecosystem where Polar Bears can hunt for their own food, eat what they catch, and repopulate, all without direct player interaction.

Vanilla Polar Bears do not breed naturally, and even though they have NBT like InLove related to breeding, they seem to ignore these fields entirely. Therefore, it became necessary to implement the breeding system from scratch, which also provided opportunities to reshape it.

For example, despite wanting Polar Bears to be able to breed, we do not want to encourage players to go up to a Polar Bear to feed it. Although we could use right-click detection to allow players to right-click with Polar Bears to feed them, we did not think this was a good idea. Instead, we looked to Villagers, who are more autonomous than animals: to make them breed, you simply toss them food and well-fed Villagers (thanks to the village's Farmers if players do not interfere) will automatically breed based on the carrying capacity (number of Beds) of the village.

Along these lines, we used the existing Eating system to allow well-fed Polar Bears to detect and breed with other nearby well-fed Polar Bears. Since AI cannot easily be manipulated to go towards a position or entity (at least, without the intent of killing it), the Polar Bears do not actually know to seek each other out. To account for this, we allow them to breed from up to 5 blocks away, which increases the likelihood that breeding will occur as Polar Bears wander around.

Breeding was surprisingly straightforward from there: using a scoreboard dc_polarBearBreed, we set both parents to have a breeding cooldown for 5 minutes, which matches most vanilla animal cooldowns. Similarly, we summoned a baby Polar Bear that grows up over 20 minutes, which is again identical to vanilla durations. The cub will spawn at whatever entity ticks first, which tends to be the oldest entity—though for most intents and purposes, this is entirely random.

The final component to consider is rewarding the player with experience (XP) for breeding Polar Bears. This occurs for most mobs, though notably not Villagers. We decided to include it as a possible incentive for players to encourage wildlife to prosper; however, farming Polar Bears is likely a far more dangerous profession than most animals, which makes them less ideal for animal farms. Vanilla breeding grants 1-7 XP in most cases; to skip needing to randomize this, we just made Polar Bears grant 7 XP every time due to the relative difficulty of breeding Polar Bears safely compared to other mobs. In addition, this XP Orb only spawns if the player is within 32 blocks, which we use as our metric to determine if the player aided in the process.

Drops

Polar Bear Meat

Instead of dropping Fish, which we find an odd choice since it seems to represent the contents of their stomach, we made Polar Bears drop Raw Polar Bear Meat: a variant of Beef (as the closest meat source available in vanilla) that is safe to eat when cooked, but very poisonous if eaten raw. This matches real-world Polar Bear meat, which is eaten by some cultures but is known to be very dangerous to eat raw. They drop 2-4 Raw Polar Bear Meat when killed unless they are on fire, in which case they drop 2-4 Steak. We decided not to rename the latter since it is functionally equivalent to Steak from Cows. In addition, names do not persist when cooking the item in the furnace, so Polar Bears killed while on fire would drop different items than if killed without fire then cooked, which seems like an unnecessary discrepancy.

For the poisoning effect, we took inspiration from the Pufferfish and granted it the same negative effects. The custom food is detected through a custom NBT tag, which is applied only to the raw item.

The frequency of 2-4 drops was chosen based on Hoglins, which drop the same amount of Porkchops. This meat provides a better emergency food if, somehow, the player's only option for food is to slay a Polar Bear. However, we stayed away from "trophy" loot like fur or Polar Bear heads, as incentivizing players to kill Polar Bears for these items is unethical.

XP

Polar Bears drop 1-3 XP when killed in vanilla. Since Polar Bears are much tougher to kill now, we increased the XP reward to 13-15 XP instead. This is not meant to incentivize players to kill Polar Bears, as there are much easier ways of gaining the same amount of XP, but more to offer a better consolation prize if they ever manage to take one down.

Additional Notes

Polar Bear Cubs

Polar Bear Cubs are not given the new stats nor behaviors until they grow up, which means they retain vanilla stats and behavior. Notably, the vanilla behavior of Polar Bears becoming hostile if you approach Cubs near them can still be triggered: with the new follow distance of 20, this can occur more easily and can result in Polar Bears becoming aggressive at 20 blocks instead of 8. We decided that this "bug" is a "feature", and consider this to represent Polar Bears being extra protective of their Cubs.

Tracking Distance

Since we manually set AngryAt based on distance, mob detection does not respect sneaking or invisibility like most mobs where these factors reduce the mob's detection range. If you are within range, it will become aggressive regardless of whether you are sneaking, invisible, or even out of line of sight. Additional checks might be able to handle this, but we decided this works as a feature due to the Polar Bear's excellent sense of smell, which does not rely on what they can see.

Leashes

Polar Bear aggression can be suppressed when on a Lead, so we decided to allow Polar Bears to break out of Leads. Multiple approaches were considered for this, but the current version un-leashes the mob every second so Polar Bears cannot be leashed for any extended period of time, since it does not make sense for a leash to work on a Polar Bear.

Damage Exploit

We encountered a major roadblock in Polar Bear AI: Upon being hit, the Polar Bear would freeze and lose both their target and AngryAt NBT. This temporarily stops the Polar Bear's aggression entirely, making it easy to stunlock the Polar Bear with successive hits. Since it does not immediately regain aggression, the Polar Bear is defenseless and dies easily, which loses much of the tension surrounding Polar Bear encounters.

This is coded into their vanilla behaviors for some reason, and occurs even without this datapack. We suspect that it has something to do with vanilla Polar Bears switching targets if they are angry at one creature but are attacked by another, which makes the Polar Bear extremely unresponsive.

Multiple attempts to quickly regain aggression were attempted, but none were successful. Instead, we turned to the Lunge ability: each time the Polar Bear is hit, the Lunge cooldown is completely refreshed, allowing it to Lunge and re-position itself while also dealing damage, even if the AI itself stuck not attacking. Previous iterations reduced the cooldown by a portion of its maximum amount, but since Lunges only occur on a 5-second interval at maximum, this was not very effective. Completely refreshing the cooldown made this more impactful, though it could perhaps be tuned even more in the future (such as allowing an additional Lunge to occur outside of the 5-second interval).

Since Lunge cooldowns are not highly enforced to begin with, this does not feel out of place and players are not likely to be surprised by (or even notice) the increased frequency of Lunges. With this addition, it is slightly more difficult (though still very possible) to exploit this weakness in the AI. This is disappointing, but we do not think more could be done with the datapack features available.

Other Bugs

  • After Lunging, there is a chance for Polar Bears to swim full speed off into the distance, not stopping until they hit land. This odd behavior is likely due to pathfinding that does not like being in the water. There's not much we can do about this behavior, so we'll call it long distance migration.
  • Polar Bears can hit fish and other creatures between 1 layer of ice (without needing to break through it). This is part of its basic attack behavior, so there's not much we can do here.