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.
alwaysactiveis set to true disguiseobjis initialised to the transform ofprefabs/Disguises/xprefab where x is the entity.AnimID. It gets childed to the entity.spritewhich 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:
disguiseobjis enableddisguisecooldownis set to -1 (meaning it simulates an already expired disguise cooldown)- entity.
spriteis disabled - enity.
heightis 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
spinto (0.0, 20.0, 0.0) and then zerored out in 0.2 seconds disguisecooldownis 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
disguisecooldownis decremented- If
disguisecooldownis 40 or 80, entity.flipis 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.
moverotaterto the entity.startposvia a LookAt call - If a HasGroundAhead call returns true, MoveTowards is called on the entity to move the entity to its
startposignoring the y component at normal speed with the state beingWalkand 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.
oldstateis set to -1 (which forces a sprite update) - If entity.
hitwallis true: - The NPCControl position is set to entity.
startpos - entity.
rigidvelocity 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):
disguiseobjis enabled- The entity.
spritegets disabled if entity.camposz is above 5.0 (meaning it's too far forward from the camera), it remains enabled otherwise overrideminheightis set to true- The entity.
heightis 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)¶
disguisecooldownis set to 120disguiseobjis disabled- entity.
spritebeing 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:
disguisecooldownis set to -1 (fully expired)disguiseobjis disabled- entity.
spritebeing 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
disguiseobjis destroyed if it was present - The entity.
speedis set to 2.0 - The
disguisecooldownis set to -1 - The default behavior is set to Wander
- The entity.
ongroundis 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
spinto (0.0, 20.0, 0.0) and then zerored out in 0.2 seconds - The
disguisecooldownis set to 120.0 - The entity.
overridehrightis set to false - The
disguiseobjis disabled
Because the behavior was also changed, the main logic won't occur.