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 intofogdistwhile 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
tskyboxexists (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
LevelUpmusic andGameoversound are loaded, but not stored. This is purely to preload them to not get a stutter when they eventually play damcountersis reset to a new listcharmdanceis set to 2 elements being sprite 98 and 99 ofSprites/Entities/moth0. These are the 2 Charmy's sprites used when they performs a charmscopeequippedis set to whether or not theHPScopemedal is equippeddimmeris set to a new Sprite of 1 pure black pixel namedMainDimmerscaled 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
oldcamoffsetis set to instance.camoffsetoldcamrotationis set to instance.camangleoffsetoldcamtargetis set to instance.camtargetoldcamspeedis set to instance.camspeed
- SetDefaultCamera is called
chompylockis set to falselockmmatteris set to falsegameoveris set to nullattackedallyis set to -1- instance.
camspeedis set to 99.0 - MainManager.parent (the
MainCamobject) angles are set to instance.camangleoffset calleris 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
playerdataentities have the following happen to each of them:flyinganimis set to false- SetAnimForce is called
- A frame is yielded
- The entity.gameObject is disabled
- The map is disabled
battlemapis set to a new GameObject namedBattle- The corresponding
Prefabs/BattleMaps/Xbattle 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
battlemapwith 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.
nobattlemusicis 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,Battle6will be used - Otherwise, if flag 348 (Start of chapter 5) is true and the current area is among
BarrenLands,FarGrasslands,WildGrasslands,RubberPrison,MetalLakeorStreamMountain,Battle6will be used - Otherwise,
Battle0will 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.
battleidis set to the corresponding index of theenemydata turnsnodamageis set to -1- battleentity.
alwaysactiveis set to true - battle.
estimatedexpis incremented by theenemydata'sexp - If the enemy's
animid(the enemy id) is less than the amount of instance.enemyencounterelements (which is normally 256) and battleentity.cotunknownis false (it's not a Cave of Trials battle entity), the correspondingenemyencounterelement's seen counter is incremented - The battleentity position is determined:
- x: This depends on the amount of enemy party member and the
enemydataindex 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.
hologramgets set to the value of flag 162 (we are in a B.O.S.S or Cave of Trials session) battleposis set to the battleentity's position- Some enemies have additional logic here:
VenusBoss:extraentitiesis 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:hologramgets 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 regardlessalwaysactivegets set to trueactiveonpausegets 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.basesateis set to 5 (Angry)BeeBoss:battleposand the battleentity position are set to (4.5, 0.0, 0.0)SandWyrmTail: entity.heightand entity.initialheightare set to 0.0CennandPisci: If flags 497 is true (beat them for the first time) , eventondeath is set to -1. If it's false,AlwaysSurviveis added to the weakness. In either cases,battleposand the battleentity position are set to (1.0, 0.0, 0.0)SpuderandSpuderReal: If flags 41 is false (before the end of chapter 1) and either flags 613 (RUIGEE) or 614 (HARDEST) is true, thehpandmaxhpare decreased by 15ZaspandMothiva: If flags 606 is true (after the second round of the colosseum in chapter 6),hp/maxhpare increased by 15,hardatkis incremented andlockrelayreceiveis set to truePitcher: battleentity position is incremented by Vector3.rightMaki,KinaandYin: If flags 614 is true (HARDEST is active),hp/maxhpare increased by 10 anddefis incremented
- If the calledfrom.entity or the battleentity is
inicewhile it's aKrawlerorCursedSkullenemy: - If battleentity.
forcefireor we are in theGiantLairarea except for theGiantLairFridgeInsidemap while the enemy is aKrawler,CursedSkullorCape:- If instance.
partylevelis less than 27 (meaning it's not maxed) and flags 613 is false (RUIGEE is inactive), theexpis incremented by the floored result of a lerp from 10.0 to 3.0 with a factor of instance.partylevel/ 27.0 freezeresis set to 110 (immune to freeze inflictions)hpandmaxhpare 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
MotherChomperenemy with a length of 3, thebattleposare changed as follows depending on theirenemydataindexes:- 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
UltimaxTankenemy, thebattleposof the first element is incremented by (0.0, 0.0, 1.0) - If it contains a
SandWyrmenemy, 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 theirbattleposdepending on theirenemydataindexes:- 0: (3.0, 0.0, 0.0)
- 1: (5.9, 0.0, 0.0)
- All battleentity in
enemydatagets 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
partyentitieselement gets set to the battlentity - The corresponding battle.
tiredpartgets initialised to the transform of a newPrefabs/Particles/Tiredwith 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) flipset to truebattleset 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):
Makiis added with animstate 13 (BattleIdle) if any of the following is true:- The MainManager.map.
mapidis theFGClearingmap - flags 594 is true (Chapter 7 when maki should be present in battle)
Makiis a tempfollower while the current area isFarGrasslandsorWildGrasslandsor the map is theTestRoom
- The MainManager.map.
KungFuMantisis added with animstate 5 (Angry) if they are a tempfollowerMadeleineis added with animstate 0 (Idle) if they are a tempfollowerAntCapitainis added with animstate 13 (BattleIdle) if map.mapidis theAbandonedCitymap and flags 400 is true (reserved temporary flag). If they are added, it also causes every element ofenemydatato have MainManager.SetCondition called twice on them as the entity withAttackUpandDefenseUpfor 999999 actor turnsLadybugKnightis added if MainManager.lasteventis 47 meaning this battle was caused by event 47 (Chapter 2 approaching the tunnel entrance to the Golden Path)Genis added if MainManager.lasteventis 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
eriis created with animid 48 (Eri) using CreateNewEntity childed to theaipartypositioned at theaiparty+ (-1.15, 0.0, 0.5) with a z scale multiplied by -1.0 - The entity's
hologramis set to true followed by an UpdateSpriteMat call which will set theirspritematerial to MainManager.holosprite - The entity's
flipandoverrideflipare 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.
camspeedis set to 0.1 - If
actiontextdoesn't exist, it is created as a SpriteRenderer component added to a new GameObject namedActionTextand 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
cursorto a new GameObject namedcursorwith 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
avaliableplayersis set to the return of MainManager.GetFreePlayerAmmount- A frame is yielded
- The
cursorposition is set to (0.0, 999.0, 0.0) - The SpriteRenderer material of the
cursorhas its renderQueue set to 10000 - UpdateText is called
- MainManager.RefreshSkills is called
- RefreshAllData is called which sets
alldatato a new list which consists of all theplayerdatafollowed by all theenemydataappended together and it also resets all enemy party member'sblockTimesto 0 - If the
fronticondoesn't exist, it is initialised to the SpriteRenderer of a new UI object with the nameattackiconchilded to theGUICamerawith 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
pauseentered earlier - If there's more than one
playerdataelement, then as long as the firstpartypointerdoesn't match the first instance.partyorder(meaning thebattledoesn'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
StrongStartmedal is equipped on a party member, the correspondingplayerdatagets itscantmovedecremented which gives it an additional turn - UpdateConditionIcons is called which calls UpdateConditionBubbles on all battleentity (all
playerdatawith right to false and allenemydatawithhpabove 0 with right to true) - All frames are yielded while
actionis 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
lastturnsto a new aray with the length being the amount of free players - 1 and all elements being -1 (this resets the player selection cycle) halfloadis set to true- All
playerdatabattleentity have theirrigidgravity enabled,ongroundset to true and animstate set to 13 (BattleIdle) - 0.1 seconds are yielded