Disguise¶
A behavior where the map entity has a special disguiseobj
that will replace its normal entity.sprite
appearence until the behavior is switched away from which reveals the entity.sprite
(usually by going into the inrange
one). After coming back to this behavior (usually by going out of inrange
), the entity will move back to its startpos
and put its disguise on again.
Frequency meaning¶
None.
A general explanation of how disguising works¶
This behaviors hinges on a special object called the disguiseobj
which is childed to entity.sprite
on SetUp.
Due to this structure, it's positioned similarly to how entity.model
would, but this behavior is made to not involve a model entity and instead flip flops the enablement of the disguiseobj
and the entity.sprite
such that only one of the 2 is enabled at a given time.
However, EntityControl.Update will think this structure is like a model entity and it will try to sync the enablement of the entity.sprite
's child to the entity.sprite
.enabled. This contradicts the goal of this behavior so what the behavior will do when it is active is to keep enforcing the rule that only one of the 2 can remain enabled by essentially fighting against EntityControl's Update.
Since this behavior is what keeps the disguiseobj
from being disabled by EntityControl, whenever the player gets inrange
and this behavior is switched away, it will no longer fight against EntityControl causing the entity.sprite
to be enabled with the disguiseobj
disabled. This is how an NPCControl with this behavior can reveal itself.
If the player gets out of inrange
after this and we come back to this behavior, it now manages a cooldown (the disguisecooldown
) of 120 frames that will have the entity move to its startpos
when it gets to 20 frames left. From there, either the 20 frames expires or it reached the entity.startpos
within 2.0 units which will cause this behavior to flip flop again such that entity.sprite
is disabled and disguiseobj
enabled. This puts back the disguise and the cycle continues.
Due to this complex management of the disguiseobj
, this behavior's logic is very spread out throughout the game because it needs to fight against EntityControl.Update as there is very little logic there to support the disguise feature.
Start / SetUp¶
On SetUp:
- entity.
alwaysactive
is set to true disguiseobj
is initialised to the transform ofprefabs/Disguises/x
prefab where x is the entity.AnimID. It gets childed to the entity.sprite
which also gets disabled making only the disguise visible instead of the sprite. The local position is ensured to be Vector3.zero, but the angles and the scales depends on the AnimID (anything not mentioned is left default):Cactus
: scale of (70.0, 25.0, 70.0)Mushroom
: scale of (20.0, 15.0, 25.0)CursedSkull
: scale of 0.5 uniform, local position of (0.0, 0.0, -0.5) and angles of (-90.0, 0.0, 0.0)Plumpling
: scale of 0.2 uniform and angles of (-90.0, 0.0, 180.0)
After SetUp returned on Start:
disguiseobj
is enableddisguisecooldown
is set to -1 (meaning it simulates an already expired disguise cooldown)- entity.
sprite
is disabled - enity.
height
is set to 0.0
All of this hides the actual sprite of the entity with no visual offset and it leaves the disguise object visible.
DoBehavior (Main logic)¶
Nothing happens if disguisecooldown
is below 0 (meaning it expired more than a cycle ago).
The main logic depends on the disguisecooldown
which is an int countdown of the number of update cycles left before the disguiseobj
gets enabled and the entity.sprite
disabled. This occurs if by the end of this cycle, it reaches 0 or below and the opposite happens if it not. No matter what specific branch of the logic applies, these enablement changes always happen after the branch is done.
disguisecooldown
is 0 (it just expired last cycle)¶
- TempSpin will be called on the entity which sets its
spin
to (0.0, 20.0, 0.0) and then zerored out in 0.2 seconds disguisecooldown
is set to -1- StopForceMove is called on the entity
disguisecooldown
hasn't expired yet and either it's 20 or above or the NPCControl is 2.0 or less away from entity.startpos
¶
- StopForceMove is called on the entity
disguisecooldown
is decremented- If
disguisecooldown
is 40 or 80, entity.flip
is toggled (this is by default the 2/3 and 1/3 point of the cooldown)
disguisecooldown
hasn't expired yet and it's below 20 while the NPCControl is more than 2.0 away from entity.startpos
¶
- DetectDirection is called on the entity with the entity.
startpos
- Align the entity.
moverotater
to the entity.startpos
via a LookAt call - If a HasGroundAhead call returns true, MoveTowards is called on the entity to move the entity to its
startpos
ignoring the y component at normal speed with the state beingWalk
and the stopstate beingIdle
. Otherwise, StopForceMove is called on the entity setting the animstate to its existing one at the end - The entity.animstate is set to the entity.
walkstate
- The entity.
oldstate
is set to -1 (which forces a sprite update) - If entity.
hitwall
is true: - The NPCControl position is set to entity.
startpos
- entity.
rigid
velocity is zeroed out - DeathSmoke particles are played at the NPCControl position if the entity is
incamera
Update (Inactive)¶
If the disguisecooldown
is fully expired (it's -1):
disguiseobj
is enabled- The entity.
sprite
gets disabled if entity.campos
z is above 5.0 (meaning it's too far forward from the camera), it remains enabled otherwise overrideminheight
is set to true- The entity.
height
is set to 0.0
LateUpdate (Not a dummy
and the entity is incamera
)¶
If the freezecooldown
and dizzytime
expired while we aren't minipause
, the enity.height
is set to a lerp from the existing one to initialheight
or 0.0 with a factor of 1/10 of the game's frametime. What determines the destination height is if the disguisecooldown
is 0 or above where it's initialheight
, 0.0 otherwise.
Otherwise, if we are in a minipause
, then the disguiseobj
is enabled if disguisecooldown
is -1 (fully expired), disabled otherwise while the opposite is done on the entity.sprite
. The enablement values only changes when needed instead of every cycle by checking if the disguiseobj
is enabled or not in comparison to disguisecooldown
being -1 or not.
Update (Frozen Enemy
override)¶
disguisecooldown
is set to 120disguiseobj
is disabled- entity.
sprite
being enabled.
Update (dizzy Enemy
override)¶
The disguiseobj
is disabled.
Dizzy¶
The disguiseobj
is disabled with the entity.sprite
being enabled.
EntityControl.Update (active)¶
This behavior prevents the entity.sprite
from being enabled there. It also goes against this behavior at least as far as the disguiseobj
is concerned, but this behavior doesn't change this logic in particular, only overrides it.
EntityControl.UpdateSprite¶
This update method is disallowed to change the sprite
enablement on an Enemy with this behavior.
MainManager.RefreshEntities¶
This logic only matters if the method was called as a result of MapControl.Start, MapControl.RefreshInsides and BattleControl.ReturnToOverworld:
disguisecooldown
is set to -1 (fully expired)disguiseobj
is disabled- entity.
sprite
being enabled.
MapControl.PreloadSprites¶
This behavior prevents the preloading of the entity.sprite
texture into the map.entitysprite
.
RespawnEnemy (Only if it's the default behavior)¶
- The
disguiseobj
is destroyed if it was present - The entity.
speed
is set to 2.0 - The
disguisecooldown
is set to -1 - The default behavior is set to Wander
- The entity.
onground
is set to true in 0.5 seconds
This will get further handled by DoBehavior, see the section below for details
DoBehavior (behavior no longer exists)¶
A special case is handled where this behavior no longer exists, but the disguiseobj
still does. The only way for this case to happen is if a destroy of the disguiseobj
was requested by RespawnEnemy because not only it destroys it, but it also changes the default behavior to Wander. If this was the previous one and it wasn't the inrange
one, then it no longer exists after the respawn which makes it fall into this special case. The handling goes as follow:
- TempSpin is called on the entity which sets its
spin
to (0.0, 20.0, 0.0) and then zerored out in 0.2 seconds - The
disguisecooldown
is set to 120.0 - The entity.
overridehright
is set to false - The
disguiseobj
is disabled
Because the behavior was also changed, the main logic won't occur.