Alchemy
Loading...
Searching...
No Matches

placement.c

Go to the documentation of this file.
1/// @file
2/// Battle objects made and placed on the battlefield.
3/// Part of battle.c, the battle object, compiled only through it.
4
6
7/// Isaac and Garet hold a Machete with sprites of their own.
8#define SPRITE_ISAAC_MACHETE 480
9#define SPRITE_GARET_MACHETE 482
10
11/// BattleObj.scale and MotionObject scales are 16.16 fixed point.
12#define SCALE_ONE 0x10000
13
14/// BattleObj.effect while no effect is attached.
15#define BATTLE_OBJ_NO_EFFECT 0x1fe
16
17/// Creates the battle object of unit at (x, y) on the battlefield, in
18/// pixels: its sprite (an enemy's from its class, sharing the slot it
19/// already holds; a party member's battle sprite), palette, size and weapon
20/// sprite, turned to face the centre, and starts its motion script
21/// (gBattlePres_ActorObjectScript). Called by BattleUnit_RefreshPlacement
22/// and by BattleTargetExec for an enemy that joins. Fills in actor, creates
23/// a field object for it and, for an enemy, claims its sprite slots.
24void BattleObjMake(struct BattleObj *actor, s32 unitId, s32 x, s32 y) {
25 s32 fixedX;
26 s32 fixedZ;
27 s32 palette;
28 s32 sprite;
29 s32 registeredSprite;
30 struct BattleUnit *unit;
31 struct MotionObject *object;
32 s32 facingAngle;
33 s32 weaponSprite;
34 u8 classId;
35
36 // Positions are 16.16 fixed point; y is the battlefield's depth.
37 fixedX = x * 65536;
38 fixedZ = y * 65536;
39 // Kind 15 skips FieldObject_Create's sprite creation. Battle sprites are
40 // attached later by BattleActor_SpawnObjectsForList.
41 object = (struct MotionObject *)Object_CreateFar(0xf000, fixedX, 0, fixedZ);
42 unit = UnitGetFar(unitId);
43 palette = 0;
44 registeredSprite = SummonSlot_RegisterActorSprites(unitId);
45
46 // The sprite: an enemy's from its class (classIndex 0), a party member's
47 // by character. An enemy whose sprite went into its own slots takes the
48 // slot's sprite and palette 0, else its class's sprite and palette; a
49 // character fighting on the enemy side (a link opponent, unit id 8 or
50 // above) takes palette 1.
51 if (unit->classIndex == 0) {
52 sprite = BattleClass_GetSprite(unit->classId);
53 if (registeredSprite == 0)
54 palette = BattleClass_GetPalette(unit->classId);
55 else
56 sprite = registeredSprite;
57 } else {
58 switch (unit->classId) {
59 case GARET:
60 sprite = BATTLE_CHARACTER(GARET);
61 break;
62 case MIA:
63 sprite = BATTLE_CHARACTER(MIA);
64 break;
65 case IVAN:
66 sprite = BATTLE_CHARACTER(IVAN);
67 break;
68 case JENNA:
69 sprite = BATTLE_CHARACTER(JENNA);
70 break;
71 case ISAAC:
72 default:
73 sprite = BATTLE_CHARACTER(ISAAC);
74 break;
75 }
76 if (unitId < 0 || unitId > 7)
77 palette = 1;
78 }
79
80 // The enemy classes drawn larger or smaller than their sprites, in 16.16
81 // (0x18000 is 1.5, 0xe666 0.9). Grouping equal scale cases shortens the
82 // matching EN function by 148 bytes, so each case keeps its own store.
83 // Class ids are enemies.tsv rows plus ENEMY_CLASS_FIRST.
84 actor->scale = SCALE_ONE;
85 switch (unit->classId) {
86 case 78:
87 actor->scale = 0x19999;
88 break;
89 case 89:
90 actor->scale = 0x18ccc;
91 break;
92 case 130:
93 actor->scale = 0x13333;
94 break;
95 case 131:
96 actor->scale = 0x19999;
97 break;
98 case 138:
99 actor->scale = 0x18000;
100 break;
101 case 147:
102 actor->scale = 0x1cccc;
103 break;
104 case 149:
105 actor->scale = 0x1cccc;
106 break;
107 case 29:
108 actor->scale = 0x10000;
109 break;
110 case 121:
111 actor->scale = 0x1b333;
112 break;
113 case 148:
114 actor->scale = 0x18000;
115 break;
116 case 150:
117 actor->scale = 0x18000;
118 break;
119 case 151:
120 actor->scale = 0x18000;
121 break;
122 case 152:
123 actor->scale = 0x18000;
124 break;
125 case 153:
126 actor->scale = 0x18000;
127 break;
128 case 154:
129 actor->scale = 0x18000;
130 break;
131 case 155:
132 actor->scale = 0x18000;
133 break;
134 case 156:
135 actor->scale = 0x18000;
136 break;
137 case 157:
138 actor->scale = 0x18000;
139 break;
140 case 47:
141 actor->scale = 0x13333;
142 break;
143 case 48:
144 actor->scale = 0x13333;
145 break;
146 case 49:
147 actor->scale = 0x16666;
148 break;
149 case 84:
150 actor->scale = 0x10000;
151 break;
152 case 85:
153 actor->scale = 0x14000;
154 break;
155 case 128:
156 actor->scale = 0x16666;
157 break;
158 case 129:
159 actor->scale = 0x16666;
160 break;
161 case 94:
162 actor->scale = 0x18000;
163 break;
164 case 98:
165 actor->scale = 0x14ccc;
166 break;
167 case 110:
168 actor->scale = 0x13333;
169 break;
170 case 132:
171 actor->scale = 0x10ccc;
172 break;
173 case 133:
174 actor->scale = 0x10ccc;
175 break;
176 case 134:
177 actor->scale = 0x11999;
178 break;
179 case 135:
180 actor->scale = 0x11999;
181 break;
182 case 136:
183 actor->scale = 0x13333;
184 break;
185 case 137:
186 actor->scale = 0x13333;
187 break;
188 case 141:
189 actor->scale = 0x18000;
190 break;
191 case 144:
192 actor->scale = 0x13333;
193 break;
194 case 145:
195 actor->scale = 0x18000;
196 break;
197 case 146:
198 actor->scale = 0x18ccc;
199 break;
200 case 52:
201 actor->scale = 0x14000;
202 break;
203 case 105:
204 actor->scale = 0x14000;
205 break;
206 case 18:
207 case 19:
208 case 20:
209 case 21:
210 case 30:
211 case 68:
212 case 69:
213 case 70:
214 case 92:
215 case 122:
216 case 123:
217 case 124:
218 case 125:
219 case 126:
220 actor->scale = 0xe666;
221 break;
222 }
223
224 actor->object = object;
225 actor->anchorX = fixedX;
226 actor->anchorZ = fixedZ;
227 actor->palette = palette;
228 actor->resource = sprite;
229 weaponSprite = BattleUnit_LookupWeaponValueByClass(unitId);
230 actor->animation = 0;
231 actor->animationEntry = 0;
232 actor->effectEntry = 0;
233 actor->active = 0;
234 actor->fading = 0;
236 classId = unit->classId;
237 actor->overlay = weaponSprite;
238
239 // Isaac and Garet draw a Machete as part of their own sprite, with no
240 // weapon overlay.
241 if (classId <= GARET &&
243 if (unit->classId == ISAAC) {
244 sprite = SPRITE_ISAAC_MACHETE;
245 actor->resource = sprite;
246 } else {
247 sprite = SPRITE_GARET_MACHETE;
248 actor->resource = sprite;
249 }
250 actor->overlay = 0;
251 }
252
253 // Face the centre of the battlefield (0x8000 is half a turn, so the
254 // angle points back along the line to the origin); enemies are drawn at
255 // 1.3 times their size. motionFlags 2 lets the object fall.
256 facingAngle = ArcTan2(y / 8, x) + 0x8000;
257 object->angle = facingAngle;
258 object->unk59 = 3;
259 object->motionFlags = 2;
260 if (unit->classIndex == 0) {
261 object->scaleX = 0x14ccc;
262 object->scaleY = 0x14ccc;
263 } else {
264 object->scaleX = SCALE_ONE;
265 object->scaleY = SCALE_ONE;
266 }
269}
270
271/// Reads the battlefield position of party place index from
272/// gBattlePlacement_StepPairs, in pixels. Nothing in the source calls it;
273/// BattleUnit_RefreshPlacement reads the table directly.
274void BattlePlacement_GetStepPair(s32 partyPlace, s32 *x, s32 *y) {
275 partyPlace *= 2;
276 *x = gBattlePlacement_StepPairs[partyPlace];
277 *y = gBattlePlacement_StepPairs[partyPlace + 1];
278}
279
280/// BattleWork.enemyIds of an enemy that left the battle, and of a place
281/// held for one: unit ids 254 and 255 in the list.
282#define IS_PLACEHOLDER_ID(id) ((u16)((id) - BATTLE_UNIT_REMOVED) <= 1)
283
284/// Lays out count enemies in a column 80 pixels left of the centre, spaced
285/// by their size (38 pixels around a large enemy, 27 around a small one, 25
286/// around an empty place, closer when there are more than four) and centred
287/// on the line. Two large classes stand nearer, 50 pixels left. Called by
288/// BattleUnit_RefreshPlacement and EnemyUpdate; writes only xPositions and
289/// zPositions.
290void Summon_LayoutPositions(u16 *actorIds, s32 count, s32 *xPositions,
291 s32 *zPositions) {
292 s32 totalSpacing = count <= 4 ? 30 : 27;
293 s32 z = ((count - 1) * totalSpacing) / 2;
294 s32 index;
295
296 // z starts half a line's estimated length up and steps down by half of
297 // each enemy's spacing before it and half after it.
298 for (index = 0; index != count; index++) {
299 s32 spacing = 0;
300
301 xPositions[index] = -80;
302 if (index != 0) {
303 struct BattleUnit *actor;
304
305 spacing = 25;
306 if (!IS_PLACEHOLDER_ID(actorIds[index])) {
307 actor = UnitGetFar(actorIds[index]);
308 spacing = BattleClass_IsSmall(actor->classId) ? 27 : 38;
309 if (actor->classId == 148 || actor->classId == 121) {
310 xPositions[index] = -50;
311 }
312 }
313 }
314 z -= spacing / 2;
315 zPositions[index] = z;
316 spacing = 25;
317 if (!IS_PLACEHOLDER_ID(actorIds[index])) {
318 struct BattleUnit *actor = UnitGetFar(actorIds[index]);
319
320 spacing = BattleClass_IsSmall(actor->classId) ? 27 : 38;
321 }
322 z -= spacing / 2;
323 }
324}
325
326/// Returns the id of the first free enemy unit, or -1 when all six are taken.
327/// Called by BattleTargetExec when an enemy calls for help.
329 s32 enemySlot;
330 s32 unitId;
331
332 for (enemySlot = 0; enemySlot < ENEMY_BATTLE_SIZE; enemySlot++) {
333 unitId = enemySlot + FIRST_ENEMY_UNIT;
334 if (UnitGetFar(unitId)->side == BATTLE_UNIT_ABSENT)
335 break;
336 }
337 if (enemySlot == ENEMY_BATTLE_SIZE)
338 return -1;
339 return unitId;
340}
341
342/// Lays the enemies out again and moves each one's object anchor to its new
343/// place. Called by BattleTargetExec after an enemy joins. Writes the
344/// anchorX and anchorZ of every enemy's battle object.
345#ifdef UBFIX
346void EnemyUpdate(void) {
347#else
349#endif
350 struct BattleWork *battle = gBattleWork;
351 u16 unitIds[14];
352 s32 xPositions[6];
353 s32 zPositions[6];
354 s32 enemyCount;
355 s32 enemyIndex;
356
357 for (enemyIndex = 0; enemyIndex < ENEMY_BATTLE_SIZE &&
358 battle->enemyIds[enemyIndex] != BATTLE_UNIT_LIST_END;
359 enemyIndex++)
360 unitIds[enemyIndex] = battle->enemyIds[enemyIndex];
361 enemyCount = enemyIndex;
362 Summon_LayoutPositions(unitIds, enemyCount, xPositions, zPositions);
363 for (enemyIndex = 0; enemyIndex < enemyCount; enemyIndex++) {
364 s32 unitId = battle->enemyIds[enemyIndex];
365
366 if (unitId != BATTLE_UNIT_REMOVED) {
367 struct BattleObj *object = BattleObjGet(unitId);
368
369 object->anchorX = xPositions[enemyIndex] * 65536;
370 object->anchorZ = zPositions[enemyIndex] * 65536;
371 }
372 }
373}
374
375/// Places every unit at the start of a battle: numbers the places (party
376/// members 0 up in their order, enemies 8 to 13) and creates each unit's
377/// object at its spot. Called by Battle_RunEncounter once the unit lists are
378/// filled. Writes gBattleWork->placement and every unit's battle object.
380 struct BattleWork *battle;
381 u16 unitIds[14];
382 s32 xPositions[6];
383 s32 zPositions[6];
384 s32 count;
385 s32 unitIndex;
386 s32 partyPlace;
387 s32 enemyPlace;
388 s32 remainingPlaces;
389 s32 placementValue;
390 u8 *placementCursor;
391
392 partyPlace = 0;
393 enemyPlace = 0;
394 battle = gBattleWork;
395 count = BattleParty_PrepareActiveOwners(unitIds);
396 // placement[0..7] is each party unit id's place (0xff for none) and
397 // placement[8..13] the enemy places, numbered 8 to 13.
398 placementValue = 0xff;
399 for (unitIndex = 13; unitIndex >= 0; unitIndex--)
400 battle->placement[unitIndex] = placementValue;
401 placementCursor = &battle->placement[13];
402 for (remainingPlaces = 5, placementValue = 13; remainingPlaces >= 0;
403 remainingPlaces--, placementValue--)
404 *placementCursor-- = placementValue;
405
406 // The party, at its fixed spots.
407 for (unitIndex = 0; unitIndex < count; partyPlace++, unitIndex++) {
408 s32 unitId = unitIds[unitIndex];
409
410 battle->placement[unitId] = partyPlace;
411 BattleObjMake(BattleObjGet(unitId), unitId,
412 gBattlePlacement_StepPairs[partyPlace * 2],
413 gBattlePlacement_StepPairs[partyPlace * 2 + 1]);
414 }
415
416 // The enemies, laid out by size.
417 for (unitIndex = 0; unitIndex < ENEMY_BATTLE_SIZE &&
418 battle->enemyIds[unitIndex] != BATTLE_UNIT_LIST_END;
419 unitIndex++)
420 unitIds[unitIndex] = battle->enemyIds[unitIndex];
421 count = unitIndex;
422 Summon_LayoutPositions(unitIds, count, xPositions, zPositions);
423 for (unitIndex = 0; unitIndex < count; unitIndex++, enemyPlace++) {
424 s32 unitId = battle->enemyIds[unitIndex];
425
426 if (unitId != BATTLE_UNIT_REMOVED)
427 BattleObjMake(BattleObjGet(unitId), unitId, xPositions[enemyPlace],
428 zPositions[enemyPlace]);
429 }
430}
431
432/// Returns 1 if the unit at place is in list. Called by
433/// BattleActor_SpawnObjectsForList to find the objects to release.
434/// @param list unit ids, ended by BATTLE_UNIT_LIST_END, 14 at most
435/// @param place 0 to 7 a party unit id, 8 to 13 the enemies
437 u32 listIndex;
438
439 // An enemy's place to its unit id.
440 if (place > 7)
441 place += FIRST_ENEMY_UNIT - 8;
442 listIndex = 0;
443 do {
444 u16 unitId = *list++;
445
446 if (unitId == BATTLE_UNIT_LIST_END)
447 break;
448 if (unitId == place)
449 return 1;
450 } while (++listIndex < 14);
451 return 0;
452}
s32 BattleClass_GetPalette(s32 index)
Returns the class's sprite palette.
Definition classes.c:35
s32 BattleClass_IsSmall(s32 index)
Returns 1 for a small class, which takes one enemy sprite slot instead of two and stands closer to it...
Definition classes.c:45
s32 BattleClass_GetSprite(s32 index)
Returns the class's battle sprite, row 0's for a class out of range.
Definition classes.c:24
s32 BattleParty_PrepareActiveOwners(u16 *owners)
Lists the party members who fight (the first four of the party, three in a link battle) and marks eac...
Definition encounter.c:371
struct BattleObj * BattleObjGet(s32 unitId)
Returns unitId's battle object, through its place, or null for a unit with no place.
Definition objects.c:480
s32 SummonSlot_RegisterActorSprites(s32 unitId)
Loads an enemy unit's battle sprite into the first free enemy sprite slots (one for a small enemy,...
Definition sprites.c:67
s32 BattleUnit_LookupWeaponValueByClass(s32 unitId)
Returns the weapon sprite a party member's attack shows for the kind of weapon they have equipped (gB...
Definition sprites.c:197
const s32 gBattlePres_ActorObjectScript[]
const s8 gBattlePlacement_StepPairs[]
What every part of the battle object shares: its includes, in their original order,...
#define FIRST_ENEMY_UNIT
Unit ids from 128 are the enemies'; in a link battle the opponent's party takes the first three.
#define EQUIP_WEAPON
The inventory's weapon slot, for Inventory_FindEquippedFar.
#define ENEMY_BATTLE_SIZE
@ BATTLE_UNIT_LIST_END
ends the list
@ BATTLE_UNIT_REMOVED
a place whose unit has left the battle
@ BATTLE_UNIT_ABSENT
struct BattleWork * gBattleWork
#define GARET
Jerald.
#define MIA
Mary.
#define ISAAC
Robin.
#define JENNA
Jasmine.
#define IVAN
Ivan.
#define BATTLE_CHARACTER(no)
the character's battle sprite
struct ObjectRuntime * Object_CreateFar(s32 id, s32 x, s32 y, s32 z)
Far call to FieldObject_Create.
void ObjectDispatch_InitializeFar(struct DispatchObject *obj, const s32 *script)
struct BattleUnit * UnitGetFar(u32 owner)
s32 Inventory_GetEquippedItemFar(struct BattleUnit *inv, s32 type)
@ ITEM_MACHETE
Definition item_ids.h:13
s32 ArcTan2(s32 x, s32 y)
Returns the angle of the vector (x, y), in 1/65536 turns, measured from the y axis: 0 along +y,...
Definition math.c:36
void BattleUnit_RefreshPlacement(void)
Places every unit at the start of a battle: numbers the places (party members 0 up in their order,...
Definition placement.c:379
s32 BattlePlacement_ContainsId(s16 *list, s32 place)
Returns 1 if the unit at place is in list.
Definition placement.c:436
s32 EnemySlotGet(void)
Returns the id of the first free enemy unit, or -1 when all six are taken.
Definition placement.c:328
#define BATTLE_OBJ_NO_EFFECT
BattleObj.effect while no effect is attached.
Definition placement.c:15
void BattleObjMake(struct BattleObj *actor, s32 unitId, s32 x, s32 y)
Creates the battle object of unit at (x, y) on the battlefield, in pixels: its sprite (an enemy's fro...
Definition placement.c:24
#define SCALE_ONE
BattleObj.scale and MotionObject scales are 16.16 fixed point.
Definition placement.c:12
s32 EnemyUpdate(void)
Lays the enemies out again and moves each one's object anchor to its new place.
Definition placement.c:348
void Summon_LayoutPositions(u16 *actorIds, s32 count, s32 *xPositions, s32 *zPositions)
Lays out count enemies in a column 80 pixels left of the centre, spaced by their size (38 pixels arou...
Definition placement.c:290
void BattlePlacement_GetStepPair(s32 partyPlace, s32 *x, s32 *y)
Reads the battlefield position of party place index from gBattlePlacement_StepPairs,...
Definition placement.c:274
#define SPRITE_GARET_MACHETE
Definition placement.c:9
#define IS_PLACEHOLDER_ID(id)
BattleWork.enemyIds of an enemy that left the battle, and of a place held for one: unit ids 254 and 2...
Definition placement.c:282
#define SPRITE_ISAAC_MACHETE
Isaac and Garet hold a Machete with sprites of their own.
Definition placement.c:8
A unit's place on the battlefield: its sprite object, resources and animations, its anchor spot and s...
struct SpriteEntry * effectEntry
the effect sprite, or NULL
struct MotionObject * object
NULL once released.
u16 animation
the status icon's animation shown; 0 for none
u16 resource
the unit's sprite
s32 palette
the unit sprite's palette
s16 fading
set while a fallen enemy's picture is being removed
s32 scale
16.16 fixed point, 0x10000 full size
u16 effect
an effect sprite drawn with the unit
s16 active
Set by BattleObj_MarkForRelease: the object is released with the others by BattleMotion_DestroyAllSlo...
struct SpriteEntry * animationEntry
the status icon's sprite, or NULL
s32 anchorZ
16.16 fixed-point pixels
u16 overlay
a second sprite drawn over it, the weapon; 0 for none
s32 anchorX
16.16 fixed-point pixels
A unit in battle: a party member's or an enemy's stats, Psynergy, items, Djinn and ailments.
u8 side
BATTLE_UNIT_ABSENT (0), BATTLE_UNIT_ENEMY (1) or BATTLE_UNIT_PARTY (2).
u8 classId
Who the unit is: a character's id (ISAAC to JENNA, below 8) or an enemy's id (BattleUnitSet).
u8 classIndex
The character's class, worked out from its Djinn (Unit_UpdateClass); 0 marks an enemy,...
The battle's own work: its enemies, units and their objects, the turn's actions, the spoils,...
Definition battle_work.h:71
u8 placement[14]
Each unit's index in slots, enemies from 8; 0xff for none.
s16 enemyIds[BATTLE_ENEMY_CAPACITY+1]
ends with BATTLE_UNIT_LIST_END
A field object as the object dispatcher's far calls take it.
An effect object that moves and draws one sprite: its position, scale, velocity and target,...
Definition motobj.h:20
s32 z
16.16 fixed-point pixels
Definition motobj.h:25
s32 y
16.16 fixed-point pixels
Definition motobj.h:24
s32 x
16.16 fixed-point pixels
Definition motobj.h:23
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
signed short s16
Definition types.h:12
unsigned short u16
Definition types.h:13
unsigned char u8
Definition types.h:11