StartBattle - Post haltbattleload
¶
This is the second of 3 phases of StartBattle.
This phase occurs after the haltbattleload
yield, but before battle.halfload
is set to true. Since the value is only visible after the first yield, the phase ends after yielding when halfload
becomes true.
Further initialisations¶
This part only contains miscellaneous initialisations logic:
- If the stageid is
FarGrasslands
, the existing RenderSettings.fogEndDistance is saved intofogdist
while it gets overriden to 75.0 (this adds a foggy effect more suitable visuablly for this BattleMap) - The money HUD is hidden by setting instance.showmoney to -1
- MainManager.RefreshHUDValues is called which forces the displayed hp, tp and berry count to their real ones
- If
tskybox
exists (meaning this is a retry as it was saved before the StartBattle call), RenderSettings.skybox is set to it - All NPCControl have StopForceBehavior called on them
- A frame is yielded
- The
LevelUp
music andGameover
sound are loaded, but not stored. This is purely to preload them to not get a stutter when they eventually play damcounters
is reset to a new listcharmdance
is set to 2 elements being sprite 98 and 99 ofSprites/Entities/moth0
. These are the 2 Charmy's sprites used when they performs a charmscopeequipped
is set to whether or not theHPScope
medal is equippeddimmer
is set to a new Sprite of 1 pure black pixel namedMainDimmer
scaled to 100.0 on layer 5 (UI) uniformely with position Vector3.zero and with a pivot at (0.5, 0.5, 0.5). This covers the whole screen during the load- If this isn't a retry (meaning it wasn't an existing battle):
- The camera limits are removed, but saved to their temporary fields before
oldcamoffset
is set to instance.camoffset
oldcamrotation
is set to instance.camangleoffset
oldcamtarget
is set to instance.camtarget
oldcamspeed
is set to instance.camspeed
- SetDefaultCamera is called
chompylock
is set to falselockmmatter
is set to falsegameover
is set to nullattackedally
is set to -1- instance.
camspeed
is set to 99.0 - MainManager.parent (the
MainCam
object) angles are set to instance.camangleoffset
caller
is set to calledfrom
Battle map creation¶
This part disables the overworld map and creates/enables the battle one:
- If the map is enabled:
- MainManager.RefreshEntities is called
- A frame is yielded
- All
playerdata
entities have the following happen to each of them:flyinganim
is set to false- SetAnimForce is called
- A frame is yielded
- The entity.gameObject is disabled
- The map is disabled
battlemap
is set to a new GameObject namedBattle
- The corresponding
Prefabs/BattleMaps/X
battle map prefab is instantiated where X is the BattleMaps enum name of the stageid and it is childed tobattlemap
- All colliders in the battle map are disabled
- A BoxCollider is added to
battlemap
with center (0.0, -0.5, 0.0) and size (100.0, 1.0, 50.0). This is essentially the physical ground for both parties battlemap
.layer is set to 8 (Ground
)- A frame is yielded
Music setup¶
This part selects the music to play if any and plays it:
- MainManager.
music[0]
pitch is set to normal - If MainManager.map.
nobattlemusic
is false or we are instance.inevent
, the music is changed via MainManager.ChangeMusic with a 1.0 fadespeed where the clip varies depending on some conditions:- If the sent music isn't null, that will be the clip used
- Otherwise, If the current area is
UpperSnakemouth
,Battle6
will be used - Otherwise, if flag 348 (Start of chapter 5) is true and the current area is among
BarrenLands
,FarGrasslands
,WildGrasslands
,RubberPrison
,MetalLake
orStreamMountain
,Battle6
will be used - Otherwise,
Battle0
will be used
Enemy party setup¶
This part goes through all the enemyids and initialises the corresponding enemydata
element. The array is initialised to a new one with a length of enemyids.length for this purpose. The main portion of the data comes from GetEnemyData with entity creation.
From there, the following happens on each enemydata
after setting it to the return of GetEnemyData:
- battleentity.
battleid
is set to the corresponding index of theenemydata
turnsnodamage
is set to -1- battleentity.
alwaysactive
is set to true - battle.
estimatedexp
is incremented by theenemydata
'sexp
- If the enemy's
animid
(the enemy id) is less than the amount of instance.enemyencounter
elements (which is normally 256) and battleentity.cotunknown
is false (it's not a Cave of Trials battle entity), the correspondingenemyencounter
element's seen counter is incremented - The battleentity position is determined:
- x: This depends on the amount of enemy party member and the
enemydata
index of the element:- 2 enemies: 1.5 *
enemydata
's index + 3.5 - 3 enemies: 1.5 *
enemydata
's index + 2.5 - 4 enemies: 0.75 *
enemydata
's index + 2.0
- 2 enemies: 1.5 *
- y: always 0.1
- z: 0.0 for the 1st enemy, 0.15 for the 2nd, 0.30 for the 3rd and 0.45 for the 4th
- x: This depends on the amount of enemy party member and the
- The battleentity gets childed to the
battlemap
- battleentity.
hologram
gets set to the value of flag 162 (we are in a B.O.S.S or Cave of Trials session) battlepos
is set to the battleentity's position- Some enemies have additional logic here:
VenusBoss
:extraentities
is initialised to a new array with one element being a new entity created via CreateNewEntity with a name ofVenus
, an animid of 80 (Venus
) and a position of (0.0, 0.0, 4.0) childed to thebattlemap
. This entity gets further adjustements:hologram
gets set to the value of flag 162 (we are in a B.O.S.S or Cave of Trials battle), but if they have the Holographic property in theirweakness
, the value always gets set to true regardlessalwaysactive
gets set to trueactiveonpause
gets set to true- A VenusBattle component gets added to the gameObject and its SetUp gets called on it with itself as the parent and the battleentity as the target
Scarlet
: battleentity.basesate
is set to 5 (Angry
)BeeBoss
:battlepos
and the battleentity position are set to (4.5, 0.0, 0.0)SandWyrmTail
: entity.height
and entity.initialheight
are set to 0.0Cenn
andPisci
: If flags 497 is true (beat them for the first time) , eventondeath is set to -1. If it's false,AlwaysSurvive
is added to the weakness. In either cases,battlepos
and the battleentity position are set to (1.0, 0.0, 0.0)Spuder
andSpuderReal
: If flags 41 is false (before the end of chapter 1) and either flags 613 (RUIGEE) or 614 (HARDEST) is true, thehp
andmaxhp
are decreased by 15Zasp
andMothiva
: If flags 606 is true (after the second round of the colosseum in chapter 6),hp
/maxhp
are increased by 15,hardatk
is incremented andlockrelayreceive
is set to truePitcher
: battleentity position is incremented by Vector3.rightMaki
,Kina
andYin
: If flags 614 is true (HARDEST is active),hp
/maxhp
are increased by 10 anddef
is incremented
- If the calledfrom.entity or the battleentity is
inice
while it's aKrawler
orCursedSkull
enemy: - If battleentity.
forcefire
or we are in theGiantLair
area except for theGiantLairFridgeInside
map while the enemy is aKrawler
,CursedSkull
orCape
:- If instance.
partylevel
is less than 27 (meaning it's not maxed) and flags 613 is false (RUIGEE is inactive), theexp
is incremented by the floored result of a lerp from 10.0 to 3.0 with a factor of instance.partylevel
/ 27.0 freezeres
is set to 110 (immune to freeze inflictions)hp
andmaxhp
are increased by 3- weakness is set to a new list with one element being
Magic
- If instance.
- A frame is yielded
- battleentity.animstate is set to its
basesate
After, there are more setup logic, but this time, it's based on the entire enemydata
array instead of each element:
- If it contains a
MotherChomper
enemy with a length of 3, thebattlepos
are changed as follows depending on theirenemydata
indexes:- 0: (1.2, 0.0, 1.0)
- 1: (2.7, 0.0, -0.5)
- 2: (4.6, 0.0, -0.1)
- If it contains a
UltimaxTank
enemy, thebattlepos
of the first element is incremented by (0.0, 0.0, 1.0) - If it contains a
SandWyrm
enemy, the first 2 elements gets a VenusBattle component added to their battleentity.gameObject with its SetUp called on them where the target is the battleentity itself and the parent being the other of the 2 battleentity. It also changes theirbattlepos
depending on theirenemydata
indexes:- 0: (3.0, 0.0, 0.0)
- 1: (5.9, 0.0, 0.0)
- All battleentity in
enemydata
gets their position set to their correspondingbattlepos
- A frame is yielded
Player party setup¶
This part initialises the playerdata
elements for the battle. It first involves initialising partyentities
, tiredpart
and receivedrelay
to new arrays with a length of the instance.playerdata
length.
From there, the following fields gets initialised to each playerdata
:
Field | Initial value |
---|---|
battleentity | A new entity created via CreateNewEntity with the name PlayerX where X is the index of the element |
tired |
0 |
cantmove |
0, but if the LastWind medal is equipped on them, the value is -1 (2 actor turns on the first main turn) |
charge |
0 |
atkdownonloseatkup |
false |
battleentity's position | Depends on the playerdata index:
|
battleentity's tag | Player |
battleentity.animid | The corresponding trueid (see battle party addressing for why this happens) |
battleentity.flip |
true |
battleentity.battle |
true |
moreturnnextturn |
0 |
turnssincedeath |
0 |
turnsalive |
0 |
battleentity.overridejump |
true |
battleentity.alwaysactive |
true |
eatenby |
null |
didnothing |
false |
battleentity.nocondition |
false |
isnumb |
false |
pointer |
The playerdata index |
plating |
Whether or not the player party member has the Plating medal equipped |
isasleep |
false |
isdefending |
false |
battleentity.battleid |
The playerdata index |
battleentity.parent | battlemap (gets childed to it) |
battleentity.gameObject.layer | 9 (Follower ) |
battleentity.emoticonoffset |
(0.0, 1.8 + 0.25 * the playerdata index, 0.0) |
battleentity.destroytype |
PlayerDeath |
battleentity.animstate | 13 (BattleIdle ) |
eventondeath |
-1 |
cursoroffset |
(0.0, 2.5, 0.0) |
haspassed |
false |
weakness |
New empty list |
condition | New empty list |
battleentity.dead |
If hp is 0, it's set to true |
battleentity.hologram |
If the HoloCloak medal is equipped on them, this is set to true alongside an UpdateSpriteMat call which updates their material to MainManager.holosprite |
Additionally, the following also happens for each playerdata
:
- The corresponding
partyentities
element gets set to the battlentity - The corresponding battle.
tiredpart
gets initialised to the transform of a newPrefabs/Particles/Tired
with the following:- Childed to the battleentity
- Local position being the
cursoroffset
+ (0.0, -5.0, 0.0) - Angles of (-45.0, 270.0, 0.0)
- Disabled for now
After initialising all player party members, MainManager.ApplyBadges is called.
Chompy setup¶
This part involves the initialisation of the chompy
field. It happens if flags 402 is true (Chompy is with Team Snakemouth).
chompy
is initialised to a new entity created via CreateNewEntity with name chompy
with the ChompyChan
animid with a position of (-0.5, 0.0, 1) with the following:
- Childed to the
battlemap
- gameObject.layer set to 9 (
Follower
) flip
set to truebattle
set to true
AI setup¶
This part initialises battle aiparty
which is a battle AI. A battle AI is an entity that sits closely to the player party, but has scripted actions after the player party's actions (and chompy
if applicable) is over. They are only added under specific conditions, usually involving having a follower.
The method used for this is called AddAI and it initalises aiparty
to a new entity created via CreateNewEntity with name ai party
using the matching animid and am animstate with position (-3.0, 0.0, 2.0) childed to the battlemap
and with a flip
and battle
field set to true.
The method takes an animid and am animstate to set to the entity (the animstate parameter is called basestate, but it actually sets the animstate
field).
While technically, the method can be called multiple time, this isn't supported and will likely result in entities not being tracked by the game should this happen.
Here are the different AIs added and their conditions by their animid (aiparty
starts with a value of null):
Maki
is added with animstate 13 (BattleIdle
) if any of the following is true:- The MainManager.map.
mapid
is theFGClearing
map - flags 594 is true (Chapter 7 when maki should be present in battle)
Maki
is a tempfollower while the current area isFarGrasslands
orWildGrasslands
or the map is theTestRoom
- The MainManager.map.
KungFuMantis
is added with animstate 5 (Angry
) if they are a tempfollowerMadeleine
is added with animstate 0 (Idle
) if they are a tempfollowerAntCapitain
is added with animstate 13 (BattleIdle
) if map.mapid
is theAbandonedCity
map and flags 400 is true (reserved temporary flag). If they are added, it also causes every element ofenemydata
to have MainManager.SetCondition called twice on them as the entity withAttackUp
andDefenseUp
for 999999 actor turnsLadybugKnight
is added if MainManager.lastevent
is 47 meaning this battle was caused by event 47 (Chapter 2 approaching the tunnel entrance to the Golden Path)Gen
is added if MainManager.lastevent
is 93 meaning this battle was caused by event 93 (Chapter 3 approaching the area where the merchants gets ambushed by bandits and wasps)
Helper
medal logic¶
If the helper
medal is equipped and aiparty
is still null at this point (meaning none of the above conditions were fufilled to get an aiparty
), it's still possible for an aiparty
to be assigned, but it will be selected randomly amongst all the possible ones. aiparty
will stay at null (none) if the medal isn't equipped or it is, but no aiparty
exists in the possible pool.
For an aiparty
to be in the pool, each requires to have some flags set to true. Here are all the possible ones with their flags slot required:
animid | animstate | Required flags slot(s) |
---|---|---|
KungFuMantis |
5 (Angry ) |
514 (Completed the Help Me Get it Back! quest) |
Gen |
0 (Idle ) |
498 (Completed the Explorer Check! quest) |
Maki |
13 (BattleIdle ) |
610 (Beaten Maki’s team for the first time) |
LadybugKnight |
0 (Idle ) |
135 (Completed the Requesting Assistance quest) |
ShielderAnt |
13 (BattleIdle ) |
135 (Completed the Requesting Assistance quest) |
AntCapitain |
13 (BattleIdle ) |
709 (Completed the Loose Ends quest) |
Madeleine |
0 (Idle ) |
391 (Completed the Butler Missing Again! quest) |
Zasp |
5 (BattleIdle ) |
298 (Chapter 4, beat the Dune Scorpion) and 189 (Completed the Lost Item quest) |
If at least one exists in the possible pool, then a random one is selected and AddAI will be called with the selected party. This is also followed by their battleentity.hologram
set to true with an UpdateSpriteMat call which will set their sprite
material to MainManager.holosprite
.
Gen
special handling as aiparty
¶
This particular aiparty
is special because it requires 2 entities, but as said earlier, the AI party system doesn't allow to have multiple entities. As a workaround, if the animid of the aiparty
that was added is 47 (Gen
), the following will happen:
- A new entity named
eri
is created with animid 48 (Eri
) using CreateNewEntity childed to theaiparty
positioned at theaiparty
+ (-1.15, 0.0, 0.5) with a z scale multiplied by -1.0 - The entity's
hologram
is set to true followed by an UpdateSpriteMat call which will set theirsprite
material to MainManager.holosprite
- The entity's
flip
andoverrideflip
are set to true so they will look to the right
Last pre halfload
initialisations¶
This part only contains miscellaneous initialisations logic before halfload
is set to true:
- Yield for a frame
- MainManager.RefreshEntities is called
- instance.
camspeed
is set to 0.1 - If
actiontext
doesn't exist, it is created as a SpriteRenderer component added to a new GameObject namedActionText
and the following:- Childed to the
GUICamera
- Local position of (-5.0, 4.0, 10.0)
- Scale of (1.15, 1.75, 1.1)
- No angles
- sprite of
guisprites[0]
(white rectangle) - gameObject.layer of 5 (UI)
- sortingOrder of -1
- color of pure white with 75% opacity
- Childed to the
- CreateCursor is called which initialises
cursor
to a new GameObject namedcursor
with the following:- A SpriteRenderer with the sprite being
cursorsprite[0]
(the leaf cursor sprite) with a sortingOrder of -20 - A SpriteBounce with MessageBounce called on it
- Childed to the
battlemap
- gameObject.layer set to 15 (
3DUI
) - Angles of (0.0, 0.0, 270.0)
- A SpriteRenderer with the sprite being
avaliableplayers
is set to the return of MainManager.GetFreePlayerAmmount- A frame is yielded
- The
cursor
position is set to (0.0, 999.0, 0.0) - The SpriteRenderer material of the
cursor
has its renderQueue set to 10000 - UpdateText is called
- MainManager.RefreshSkills is called
- RefreshAllData is called which sets
alldata
to a new list which consists of all theplayerdata
followed by all theenemydata
appended together and it also resets all enemy party member'sblockTimes
to 0 - If the
fronticon
doesn't exist, it is initialised to the SpriteRenderer of a new UI object with the nameattackicon
childed to theGUICamera
with position of Vector.zero, size of Vector3.one / 3.0, sortingOrder of 20 and with a sprite ofguisprites[63]
(the red arrow of the front icon in battle) - A frame is yielded
- We exit the
pause
entered earlier - If there's more than one
playerdata
element, then as long as the firstpartypointer
doesn't match the first instance.partyorder
(meaning thebattle
doesn't point to the leading party member), a SwitchParty action coroutine is started with fast (which ends up calling MainManager.SwitchParty immediately) followed by a frame yield until they both match. NOTE: It does mean the coroutine calls can be spammed, but in theory, the while condition gets updated information everytime since the StartCoroutine call immediately causes the party to be updated. For more information on why this is done, check battle party addressing - If the
StrongStart
medal is equipped on a party member, the correspondingplayerdata
gets itscantmove
decremented which gives it an additional turn. NOTE: Thetiredpart
may not render after the first actor turn because the correspondingreceviedrelay
may not be set to true - UpdateConditionIcons is called which calls UpdateConditionBubbles on all battleentity (all
playerdata
with right to false and allenemydata
withhp
above 0 with right to true) - All frames are yielded while
action
is true until it goes to false (this is done to ensure all remainings SwitchParty calls done earlier are fully finished) - RefreshEXP is called
- SetLastTurns is called which resets
lastturns
to a new aray with the length being the amount of free players - 1 and all elements being -1 (this resets the player selection cycle) halfload
is set to true- All
playerdata
battleentity have theirrigid
gravity enabled,onground
set to true and animstate set to 13 (BattleIdle
) - 0.1 seconds are yielded