Fire Projectile (Power Type)

Fires one or more projectiles upon pressing the specified Key with customizable projectile-firing ability with configurable visuals, behavior, and actions…

Fires one or more projectiles upon pressing the specified Key with customizable projectile-firing ability with configurable visuals, behavior, and actions on hit/miss.

Type ID: apoli:fire_projectile

Fields

FieldTypeDefaultDescription
entity_typeIdentifierThe ID of the entity type that will be fired.
texture_locationIdentifier or keywordoptionalIf specified, the texture used for the projectile and the entity_type will be ignored. The projectile is then Apoli’s own entity, which can also wear a Bedrock model. The keywords held_item and offhand_item throw the shooter’s item instead — see Throwing what you are holding.
cooldownInteger or Expression1Interval of ticks this power needs to recharge before the power can be triggered again.
hud_renderHud RenderoptionalDetermines how the cooldown of this power is visualized on the HUD.
countInteger1The amount of projectiles to fire each use.
intervalInteger0Determines the interval for firing multiple projectiles consecutively (in ticks). If set to 0, it will fire all the projectiles at the same tick.
start_delayInteger0Determines how long the start of the firing process is delayed (in ticks).
speedFloat1.5The speed applied to the fired projectile.
offset_x, offset_y, offset_zFloat0Where the projectile spawns, relative to the shooter’s eyes. Read through space, so local puts offset_z: 1.5 a block and a half in front of wherever they are looking — the muzzle of a cannon rather than a point due south of it.
spaceSpaceworldHow the spawn offset is read. local is relative to the shooter’s facing, world to the world axes.
max_distanceFloat or Expression0Removes the projectile once it has travelled this far, in blocks. 0 leaves it to fly until it hits something or expires. Apoli’s own shots keep drifting on inertia, so speed alone does not bound their range.
divergenceFloat1.0How much each projectile fired is affected by random spread.
soundIdentifieroptionalIf set, the sound with this ID will be played when the power is used.
tagNBToptionalNBT data of the entity.
allow_conditional_cancellingBooleanfalseDetermines if extra projectiles will no longer be fired as soon as the entity no longer meets this power’s condition.
block_action_cancels_miss_actionBooleanfalseDetermines if the block_action_on_hit action will cancel the bientity_action_on_miss action.
entity_action_before_firingEntity ActionoptionalIf specified, the entity action to execute on the entity firing the projectile just prior to the projectile being created.
bientity_action_after_firingBi-entity ActionoptionalIf specified, the bi-entity action to execute with the projectile owner the actor, and the projectile as the target as soon as the projectile is created.
block_action_on_hitBlock ActionoptionalIf specified, the block action to execute on the block the projectile lands on upon having it land on it.
bientity_action_on_missBi-entity ActionoptionalIf specified, the bi-entity action to execute with the projectile owner as the actor, and the projectile as the target upon missing.
bientity_action_on_hitBi-entity ActionoptionalIf specified, the bi-entity action to execute with the projectile as the actor, and the hit entity as the target upon hitting an entity.
owner_target_bientity_action_on_hitBi-entity ActionoptionalIf specified, the bi-entity action to execute with the projectile owner as the actor, and the hit entity as the target upon hitting an entity.
tick_bientity_actionBi-entity ActionoptionalIf specified, the bi-entity action with the projectile owner as the actor, and the projectile as the target that is run each tick of the projectile’s lifespan.
block_conditionBlock ConditionoptionalIf specified, the block condition that the block targeted by the block_action_on_hit field must meet in order for that to run.
bientity_conditionBi-entity ConditionoptionalIf specified, the bi-entity condition with the projectile as the actor and the target as the target for the projectile to actually hit the target instead of pass through.
owner_bientity_conditionBi-entity ConditionoptionalIf specified, the bi-entity condition with the projectile owner as the actor and the target as the target for the projectile to actually hit the target instead of pass through.
keyKeyoptionalWhich active key this power should respond to. If none is specified, this power will use the primary active power key.
projectile_actionEntity Action TypeoptionalIf specified, this entity action will be executed on the projectile or entity that will be launched.
shooter_actionEntity Action TypeoptionalIf specified, this entity action will be executed on the entity that has the power.
reflectiveBooleanfalseWhen true, the projectile bounces off blocks instead of stopping on them. See Bouncing off walls.
max_bouncesInteger4How many times a reflective projectile may bounce before the next block hit stops it. -1 bounces forever, which needs max_distance or a tick_bientity_action to end the shot.
bounce_speedFloat1.0The fraction of its speed the projectile keeps after each bounce. 1.0 loses nothing, 0.6 is a rubber ball, values above 1 accelerate it.
bientity_action_on_bounceBi-entity ActionoptionalIf specified, the bi-entity action to execute with the projectile owner as the actor and the projectile as the target every time it bounces.

Bouncing off walls

reflective turns a block hit into a rebound: the projectile’s velocity is mirrored through the face it struck, scaled by bounce_speed, and it carries on flying. Entity hits are unaffected — a reflective projectile still hits the first entity it reaches, subject to bientity_condition.

Each bounce still runs block_action_on_hit (honouring block_condition), so a bouncing shot can leave a mark on every wall it kisses. bientity_action_on_miss is held back until the projectile actually stops, so “it missed” means what it says.

Once max_bounces is used up the next block hit ends the shot normally. Give a forever-bouncing projectile (max_bounces: -1) a max_distance so it cannot outlive the player who fired it.

{
  "type": "apoli:fire_projectile",
  "texture_location": "example:textures/entity/bouncy_orb.png",
  "speed": 1.2,
  "reflective": true,
  "max_bounces": 6,
  "bounce_speed": 0.85,
  "max_distance": 64,
  "bientity_action_on_bounce": {
    "type": "apoli:play_sound",
    "sound": "minecraft:entity.slime.squish"
  }
}

bounce_speed above 1.0 compounds — at 1.3 a projectile is travelling nearly four times its launch speed after six bounces, fast enough to tunnel through a one-block wall between ticks. Pair it with a low max_bounces.

Examples

{
  	"type": "apoli:fire_projectile",
	"entity_type": "minecraft:arrow",
  	"cooldown": 2,
	"hud_render": {
		"should_render": false
	},
	"tag": "{pickup:0b}",
	"key": {
		"key": "key.attack",
		"continuous": true
	}
}

This example will let the player fire arrows very rapidly by holding the left mouse button. They can’t be picked up.

{
    "type": "apoli:fire_projectile",
    "entity_type": "minecraft:snowball",
    "cooldown": 100,
    "hud_render": {
        "should_render": false
    },
    "count": 4,
    "interval": 5,
    "tag": "{Item: {id: 'minecraft:slime_ball', Count: 1b}}",
    "key": {
        "key": "key.use",
        "continuous": false
    }
}

This example will let the player fire 4 snow balls disguised as slime balls consecutively, with an interval of 5 ticks upon pressing the right mouse button.

Throwing what you are holding

Set texture_location to held_item (or offhand_item) and the projectile carries the shooter’s stack, rendering its real item model — blocks come out as blocks, items as their sprite, exactly the way a thrown snowball or ender pearl renders:

{
  "type": "apoli:fire_projectile",
  "texture_location": "held_item",
  "speed": 1.5
}

The stack is read when the projectile spawns, so it keeps looking like that item even if the shooter swaps hands mid-flight. It is a copy for rendering only — nothing is taken from the shooter’s inventory, so pair it with an apoli:consume or apoli:change_slot if the throw should cost the item.

Giving the projectile a model

A projectile spawned by texture_location is Apoli’s own entity, and like a minion or a clone it renders whatever apoli:custom_model_render geometry it is holding. Grant the model power to the projectile from projectile_action and it wears the model instead of the flat texture:

{
  "type": "apoli:fire_projectile",
  "texture_location": "example:textures/projectile/blank.png",
  "speed": 1.8,
  "projectile_action": {
    "type": "apoli:grant_power",
    "power": "example:shuriken_model",
    "source": "example:shuriken"
  }
}
{
  "type": "apoli:custom_model_render",
  "mode": "geometry",
  "model": "example:geo/shuriken.geo.json",
  "texture": "example:textures/entity/shuriken.png",
  "animations": {
    "animation": "example:animations/shuriken.animation.json",
    "name": "animation.shuriken.spin",
    "loop": true
  }
}

The model faces the projectile’s direction of travel, and its animations play from the moment it is granted, so a spin or a flame flicker runs for the projectile’s whole flight.

The power is resolved at spawn and the projectile carries it in its own entity data, so it arrives with the spawn packet and every viewer sees the model on the very first frame. Granting or revoking a model power mid-flight still works — the live power is checked when the projectile is not carrying a stamped one.

Pair it with the spawn offset to line the projectile up with whatever fired it:

{
  "type": "apoli:fire_projectile",
  "texture_location": "example:textures/projectile/blank.png",
  "space": "local",
  "offset_y": -0.4,
  "offset_z": 1.6,
  "speed": 2.0,
  "projectile_action": { "type": "apoli:grant_power", "power": "example:cannonball_model", "source": "example:cannon" }
}

texture_location is what selects Apoli’s projectile entity in the first place, so it stays required even when a model covers it — point it at a blank texture. A vanilla entity_type projectile renders the way vanilla renders it and ignores model powers.