ShootProjectile¶
Attacks the player by shooting an OverworldProjectile which can, under the right conditions, start a battle with advantage. The specifics of the projectile logic is dependant on the animid and only a few have a logic defined for this behavior.
Frequency meaning¶
None.
An overview of OverworldProjectile¶
This component is only involved over the course of this behavior. It is meant to be created externally via a static method called NewProjectile defined in that component's MonoBehavior. It takes a lot of parameters to setup the projectile notably a parent
which will be this NPCControl.
At a basic level, an OverworldProjectile is a sprite with a default trigger BoxCollider that has the ability to call NPCControl.StartBattle with advantage on its OnTriggerStay when all of the following conditions are fufilled:
- The other collider is the player
- We aren't in a
pause
,minipause
,inevent
orinbattle
- The player isn't on
shield
- This NPCControl entity isn't
iskill
- This NPCControl
dizzytime
expired (this prevents encounters where the projectile hit the player, but the player stunned them before)
The projectile has a limited amount of screen time in frames, but if it touches the player (without encounter) or a Ground
/ NoDigGround
layer, it gets destroyed with optional special effects.
As for the movement of the OverworldProjectile, it moves along a beizer curve with start / end points alongside the y position of the mid point. However, it is possible to send 0.1 or less for that last parameter to have it lerp in a straight line instead according to its screen time.
As for the rendering of of the projectile, it's a sprite index of the Sprites/Misc/projectiles
sprites, but it's possible to send a negative number to specify an item id (the absolute value) to use as the sprite.
Notable traits of an OverworldProjectile GameObject:
- Its name is
proj
- It is childed to the map
- A GameObject is childed to it with a SpriteRenderer called
tempproj
- Its layer is 14 (
Sprite
) - Its tag is
Projectile
DoBehavior¶
If returntoheight
is true, the entity.height
is set to a lerp from the existing one to its initialheight
with a factor of 0.1.
If the entity is in a forcemove
, StopForceMove is called on the entity without smoothing and without changing the animstate.
Finally, a ShootProjectile coroutine is started and set to behaviorroutine
.
ShootProjectile¶
This is a private coroutine specific to this behavior. It receives the behavior type and the coroutine call is assigned to behaviorroutine
which allows the NPCControl to stop it if needed.
- Emoticon is called on the entity with id 2 (a red ! mark) for 60 frames
- If
projectiles
is null, it is initalised to a new List of OverworldProjectile - All null elements in
projectiles
are removed - FaceTowards is called on the entity to face the player
- From there, the projectile is fired depending on the entity.animid. See the section below for more details. If this is not an animid with a projectile logic, the following is done:
- entity.animstate is set to entity.
basestate
- If we aren't
inrange
, entity.overrideonlyflip
is set to false - A frame is yielded
- StopForceBehavior is called
- The coroutine is exited early with a yield break
- entity.animstate is set to entity.
- entity.animstate is set to entity.
basestate
- If we aren't
inrange
, entity.overrideonlyflip
is set to false - A frame is yielded
- StopForceBehavior is called
- If we still aren't
inrange
, Emoticon is called on the entity with id 1 (? mark) for 60 frames
Projectile logic¶
Here are the different logic available for each animid.
DeadLanderA
¶
If there's no projectiles
:
- entity.animstate is set to 103 (shooting)
- A second is yielded
- All frames are yielded as long as we are in a
pause
,minipause
,inevent
or we are in abattle
that isinevent
- If either
dizzytime
orfreezecooldown
haven't expired, this projectile logic ends early (but the coroutine continues) - FaceTowards is called on the entity to face the player
- entity.
animstate
is set to 104 (going back to idle from shooting) - A projectile gets added with this NPCControl as the parent:
- sprite index 10 (honey projectile)
- starting position at this NPCControl position - its right vector + (0.0, 1.25, 0.0)
- target position being the player position undershot by 1.5 towards the direction of the player
- No spin
- y angles of the entity.
sprite
angle, but no x or z - size of uniform 0.75
HoneyExplode
particles on the projectle destruction- y midpoint of the bezier curve of 2.0
- time of 50.0 frames
- shadow size multiplier of 0.25
- 0.5 seconds are yielded
No matter if there was projectiles or not, all frames are yielded as long as we are in a pause
, minipause
, inevent
or we are in a battle
that is inevent
followed by an additional yield which ends this projectile.
WaspBomber
¶
If there's no projectiles
:
- entity.
animstate
is set to 101 (throwing) - A projectile gets added with this NPCControl as the parent:
- sprite index -30 (
SpicyBomb
item sprite) - starting position at this NPCControl position - its right vector + (0.25, 1.25, -0.1)
- target position being the player position undershot by 1.5 towards the direction of the player
- Spin of 20.0 in z (no x or y)
- y angles of the entity.
sprite
angle, but no x or z - size of uniform 1.0
explosionsmall
particles on the projectle destruction (also, if the player is less than 15.0 away on destruction,Explosion
sound is played at 0.75 pitch followed by a ShakeScreen of 0.1 for 0.5 seconds without reset)- y midpoint of the bezier curve of 5.0
- time of 80.0 frames
- shadow size multiplier of 0.5
- sprite index -30 (
- a second is yielded
- entity.
animstate
is set to 0 (Idle
)
No matter if there was projectiles or not, all frames are yielded as long as we are in a pause
, minipause
, inevent
or we are in a battle
that is inevent
followed by an additional yield which ends this projectile.
ToeBiter
¶
If there was at least 1 projectiles
, all frames are yielded as long as we are in a pause
, minipause
, inevent
or we are in a battle
that is inevent
followed by an additional yield which ends this projectile logic.
If there's no projectiles
:
- entity.
animstate
is set to 100 (lowering upper limbs to the ground) - 0.5 seconds are yielded
- entity.
animstate
is set to 101 (putting upper limbs in the air) - If
dizzytime
orfreezecooldown
aren't expired, this projectile logic ends early, but the coroutine still continues - All frames are yielded as long as the player isn't free (ignoring flying) or they are
digging
- If
internaltransform[0]
doesn't exist, it is initialised to aPrefabs/Objects/CrackedRock
prefab without its MeshCollider and Fader with a position of this NPCControl + (0.0, -2.0, 0.0), and a scale of 0.5 uniform internaltransform[0]
is childed to the mapinternaltransform[0]
is added to thedestroyOnBattle
list which slates this object to be destroyed the moement NPCControl.StartBattle gets called- If
dizzytime
orfreezecooldown
aren't expired, this projectile logic ends early, but the coroutine still continues - From there, there is a loop that goes on for up to 11.0 frames, but counted by a local variable which only gets incremented towards the end of the loop by the game's frametime (meaning there may be more frames yielded during the loop, but it will stop after 11.0 frames are counted using the local variable):
internaltransform[0]
position is set to a lerp from the existing one to (entity.sprite
position + the normalised right vector of the entity + 0.3 in y) with a factor of the ratio of the amount of frames counted in this loop over 11.0. This basically moves the rock on a straight line to a position above the entity, but slightly towards them- If
dizzytime
orfreezecooldown
aren't expired, this projectile logic ends early, but before it is ends, all frames are yielded as long as we are in apause
,minipause
,inevent
or we are in abattle
that isinevent
followed by an additional yield - This is where the local frame counter is incremented by the game's frametime, but only if we aren't in a
pause
- A frame is yielded
- 0.25 seconds are yielded
- All frames are yielded as long as the player isn't free (ignoring flying)
- entity.
animstate
is set to 28 (TossItem) - All frames are yielded as long as the player isn't free (ignoring flying)
- If
dizzytime
orfreezecooldown
aren't expired, this projectile logic ends early, but the coroutine still continues - The
Toss3
sound is played at 0.9 volume - A projectile gets added with this NPCControl as the parent:
- sprite index 17 (A brown missile)
- starting position at this
internaltransform[0]
position - target position being the player position undershot by 1.5 towards the direction of the player
- No spin
- y angles of the entity.
sprite
angle and z angle of 90.0, no x - size of uniform 0.5
Rock
particles on the projectle destruction (will also lead to the rooting of the rock if it still exists followed by CrackRock being called on it. Additionally, if the player is 15.0 away,RockBreak
sound is played at 0.75 pitch followed by a ShakeScreen of 0.1 for 0.5 seconds without reset)- y midpoint of the bezier curve of 3.0
- time of 40.0 frames
- shadow size multiplier of 0.25
- The projectile gets childed to
internaltransform[0]
. This is done so because the game hides the fact the rock isn't the projectile, but rather a brown missile is and its sprite gets disabled on the OverworldProjectile's Start because of theRock
particle on death parameter sent internaltransform[0]
is set to null (OverworldProjectile takes control of it from now on)- 0.5 seconds are yielded
- All frames are yielded as long as we are in a
pause
,minipause
,inevent
or we are in abattle
that isinevent
followed by an additional yield which ends this projectile
SneilEnemy
¶
If there's no projectiles
:
- entity.
animstate
is set to 100 (preparing to shoot) - FlipSpriteAngleAt is called on the entity towards the player with offset (0.0, 90.0, 0.0)
- All frames are yielded as long as we are in a
pause
,minipause
,inevent
or we are in abattle
that isinevent
- If
dizzytime
orfreezecooldown
aren't expired, this projectile logic ends early, but the coroutine still continues - The
Lazer
sound is played on the entity - FlipSpriteAngleAt is called on the entity towards the player with offset (0.0, 90.0, 0.0)
- A projectile gets added with this NPCControl as the parent:
- sprite index 4 (A white lightning bolt)
- starting position at this NPCControl position - its right vector + 0.1 in y
- target position being the player position undershot by 1.5 towards the direction of the player + 2.0 in y
- No spin
- y angles of the entity.
sprite
angle and z angle of 90.0, no x - size of uniform 0.75
- No particles on destruction
- y midpoint of the bezier curve of 0.0
- time of 60.0 frames
- shadow size multiplier of 0.25
- 0.75 seconds are yielded
- all frames are yielded as long as we are in a
pause
,minipause
,inevent
or we are in abattle
that isinevent
followed by an additional yield which ends this projectile.
Otherwise, if there was a projectile:
- entity.
animstate
is set to entity.basestate
- entity.
overrideflip
is set to false - A frame is yielded
- StopForceBehavior is called
- The coroutine is ended early with a yield break
BeeBot
¶
If there's less than 2 projectiles
:
- entity.
animstate
is set to 100 (preparing to shoot) - FlipSpriteAngleAt is called on the entity towards the player with offset (0.0, 90.0, 0.0)
- 0.5 seconds are yielded
- All frames are yielded as long as we are in a
pause
,minipause
,inevent
or we are in abattle
that isinevent
- If
dizzytime
orfreezecooldown
aren't expired, this projectile logic ends early, but the coroutine still continues - FlipSpriteAngleAt is called on the entity towards the player with offset (0.0, 90.0, 0.0)
- A projectile gets added with this NPCControl as the parent:
- sprite index 10 (honey projectile)
- starting position at this NPCControl position - its right vector + 1.25 in y
- target position being the player position undershot by 1.5 towards the direction of the player
- No spin
- y angles of the entity.
sprite
angle, no x or z - size of uniform 0.75
HoneyExplode
particles on destruction- y midpoint of the bezier curve of 2.0
- time of 60.0 frames
- shadow size multiplier of 0.25
- 0.3 seconds are yielded
No matter if there was less than 2 projectiles or not, all frames are yielded as long as we are in a pause
, minipause
, inevent
or we are in a battle
that is inevent
followed by an additional yield which ends this projectile.
Turret
¶
The same than BeeBot
with a few changes:
- The first yield is 0.7 seconds instead of 0.5
- Right before the second FlipSpriteAngleAt, entity.
animstate
is set to 102 (shooting) - The last yield is 0.4 seconds instead of 0.3
WaspScout
¶
If there's no projectiles
:
- entity.
animstate
is set to 100 (preparing to throw) - FaceTowards is called on the entity to face the player
- 0.25 seconds are yielded
- entity.
animstate
is set to 102 (throwing) - All frames are yielded as long as we are in a
pause
,minipause
,inevent
or we are in abattle
that isinevent
- If
dizzytime
orfreezecooldown
aren't expired, this projectile logic ends early, but the coroutine still continues - The
Toss
sound is played on the entity - FlipSpriteAngleAt is called on the entity towards the player with offset (0.0, 90.0, 0.0)
- A projectile gets added with this NPCControl as the parent:
- sprite index 2 (a brown kunai)
- starting position at this NPCControl position - its right vector + 1.75 in y
- target position being the player position undershot by 1.5 towards the direction of the player
- No spin
- y angles of the entity.
sprite
angle and -60.0 in z, no x - size of uniform 0.75
- No particles on destruction
- y midpoint of the bezier curve of 0.0
- time of 45.0 frames
- shadow size multiplier of 0.25
- 0.75 seconds are yielded
No matter if there was projectiles or not, all frames are yielded as long as we are in a pause
, minipause
, inevent
or we are in a battle
that is inevent
followed by an additional yield which ends this projectile.
LeafbugArcher
¶
The same than WaspScout
, but with a few changes:
- Before facing towards the entity, the
Rope1
sound is played on the entity - The first yield is 0.5 seconds instead of 0.25
- The projectile sprite index is 12 (a purple blunt projectile) instead of 2 (a brown kunai)
- The offset to the projectile starting position is (1.0, 1.0, -0.1) instead of just 1.75 in y
- The z angle of the projectile is -90.0 instead of -60.0
Bandit
¶
If there's no projectiles
:
- entity.
animstate
is set to 100 (preparing to throw) - FaceTowards is called on the entity to face the player
- 0.5 seconds are yielded
- All frames are yielded as long as we are in a
pause
,minipause
,inevent
or we are in abattle
that isinevent
- If
dizzytime
orfreezecooldown
aren't expired, this projectile logic ends early, but the coroutine still continues - The
Spin3
sound is played on the entity - FlipSpriteAngleAt is called on the entity towards the player with offset (0.0, 90.0, 0.0)
- A projectile gets added with this NPCControl as the parent:
- sprite index 3 (a shuriken shaped object)
- starting position at this NPCControl position - its right vector + 1.0 in y
- target position being the player position undershot by 2.0 towards the direction of the player + 1.25 in y
- z spin of 20.0
- y angles of the entity.
sprite
angle and 90.0 in z, no x - size of uniform 0.75
- No particles on destruction
- y midpoint of the bezier curve of 1.25
- time of 60.0 frames
- shadow size multiplier of 0.25
- 0.75 seconds are yielded
No matter if there was projectiles or not, all frames are yielded as long as we are in a pause
, minipause
, inevent
or we are in a battle
that is inevent
followed by an additional yield which ends this projectile.
ChomperBrute
¶
The same than Bandit
, but with a few changes:
- Before the entity.
animstate
is set to 100 (which is opening their mouth), theClomp
sound is played on the entity - After the first yields when in many kinds of pause, entity.
animstate
is set to 102 (biting) followed by a yield of 0.2 seconds - Before the FlipSpriteAngleAt, the sound played on the entity is
PingShot
instead ofToss
- The projectile sprite index is -38 (
ChomperSeed
item) - The offset to apply to the projectile starting position is 0.2 in y instead of 0.1
WildChomper
¶
The exact same logic than ChomperBrute
(animstate 100 is preparing to shoot while animstate 102 is shooting).