Digimon World 3 decomp
The European version, SLES_039.36
Loading...
Searching...
No Matches
result.c
Go to the documentation of this file.
1/* The training's run and its result (STGTRAIN_runTraining), and an idle task
2 that nothing creates: STGTRAIN.PRO's second object (see sprite.c), whose
3 rodata starts at 0x8008251C (USA) */
4
5#include "menus/gym.h"
6
7/* Raises a battle stat (1-5) by the training's gain, up to 999 */
10 s32 column = 6;
11 s16 *value;
12 s32 gained;
13
14 if (stat < 1 || stat > 5) {
15 return 0;
16 }
17 value = &stats->stats[stat + 5];
18 if (result->training < 0xD) {
19 column = 0;
20 }
21 column += result->bonusWorked * 3 + result->screen->intensity;
22 if (STGTRAIN_statGains[column].range != 0) {
23 gained = STGTRAIN_statGains[column].base + RANDOM.next() % STGTRAIN_statGains[column].range;
24 } else {
25 gained = STGTRAIN_statGains[column].base;
26 }
27 *value += gained;
28 if (*value >= 1000) {
29 *value = 999;
30 }
31 return gained;
32}
33
34/* Lowers a battle stat (1-5) by the training's loss, half of the time, down to 0 */
37 s16 *value;
38 s32 lost;
39 s32 column;
40
41 if (stat < 1 || stat > 5 || (RANDOM.next() & 1)) {
42 return 0;
43 }
44 value = &stats->stats[stat + 5];
45 column = result->screen->intensity;
46 if (STGTRAIN_statLosses[column].range != 0) {
47 lost = STGTRAIN_statLosses[column].base + RANDOM.next() % STGTRAIN_statLosses[column].range;
48 } else {
49 lost = STGTRAIN_statLosses[column].base;
50 }
51 *value -= lost;
52 if (*value < 0) {
53 *value = 0;
54 }
55 return lost;
56}
57
58/*
59 * Raises a resistance (stat 8-14) by the training's gain, up to 999: the
60 * table goes by the Digimon's growth of it and how high it already is.
61 */
63 PartnerStats *stats;
64 s16 *value;
65 DigimonData *digimon;
66 TrainGain *gains;
67 s32 column;
68 s32 gained;
69 s32 resist = stat - 8;
70
71 if (resist < 0 || resist >= 7) {
72 return 0;
73 }
74 stats = GAME.funcs.getPartnerStats(result->partner);
75 digimon = &DIGIMON_DATA[result->partner];
76 value = &stats->stats[stat + 4];
77 if (*value < 100) {
78 gains = STGTRAIN_resistGainTables[(digimon->resistGrowth[resist] - 1) * 3];
79 } else if (*value < 300) {
80 gains = STGTRAIN_resistGainTables[(digimon->resistGrowth[resist] - 1) * 3 + 1];
81 } else {
82 gains = STGTRAIN_resistGainTables[(digimon->resistGrowth[resist] - 1) * 3 + 2];
83 }
84 /* the match depends on column being set in each branch: set before the
85 test, its delay slot copy keeps a0 live where the table's lui wants it */
86 if (result->bonusWorked == 0) {
87 column = 0;
88 } else if (result->training < 0xD) {
89 column = 1;
90 } else {
91 column = 2;
92 }
93 column += result->screen->intensity * 3;
94 if (gains[column].range != 0) {
95 gained = gains[column].base + RANDOM.next() % gains[column].range;
96 } else {
97 gained = gains[column].base;
98 }
99 *value += gained;
100 if (*value >= 1000) {
101 *value = 999;
102 }
103 return gained;
104}
105
106/*
107 * Raises the maximum HP (stat 15) or MP (16) by the training's gain, up to
108 * 9999; the US version also raises the current value, up to the maximum.
109 */
111 PartnerStats *stats;
112 s16 *value;
113#if VERSION_US
114 s16 *current;
115#endif
116 s32 column;
117 s32 gained;
118
119 if (stat < 15 || stat > 16) {
120 return 0;
121 }
122 stats = GAME.funcs.getPartnerStats(result->partner);
123 if (stat == 15) {
124 value = &stats->stats[3];
125#if VERSION_US
126 current = &stats->stats[2];
127#endif
128 } else {
129 value = &stats->stats[5];
130#if VERSION_US
131 current = &stats->stats[4];
132#endif
133 }
134 column = 0;
135 if (result->bonusWorked != 0) {
136 if (result->training < 0xD) {
137 column = 1;
138 } else {
139 column = 2;
140 }
141 }
142 column += result->screen->intensity * 3;
143 if (STGTRAIN_maxHpMpGains[column].range != 0) {
144 gained = STGTRAIN_maxHpMpGains[column].base + RANDOM.next() % STGTRAIN_maxHpMpGains[column].range;
145 } else {
146 gained = STGTRAIN_maxHpMpGains[column].base;
147 }
148 *value += gained;
149 if (*value >= 10000) {
150 *value = 9999;
151 }
152#if VERSION_US
153 *current += gained;
154 if (*current > *value) {
155 *current = *value;
156 }
157#endif
158 return gained;
159}
160
161/*
162 * Applies the i-th try of a training (if it worked) and shows what it
163 * changed: the stat it raises, and the one it lowers or also raises.
164 */
166 TrainResultWindows *win = result->children;
167 TrainEntry *entry = STGTRAIN_state.findTableEntry(result->modeArg, result->training);
168
169 if (result->trained[i] != 0) {
170 /* The match depends on stat (and other below) being s16 locals. */
171 s16 stat = entry->stat;
172
173 if (stat != 0) {
174 if (stat >= 1 && stat <= 5) {
175 result->gains[i] = STGTRAIN_raiseStat(result, stat);
176 } else {
177 result->gains[i] = STGTRAIN_raiseResistance(result, stat);
178 stat = entry->other;
179 if (stat != 0) {
180 if (stat >= 1 && stat <= 5) {
181 result->losses[i] = STGTRAIN_lowerStat(result, stat);
182 } else {
183 result->losses[i] = STGTRAIN_raiseMaxHpMp(result, stat);
184 }
185 }
186 }
187 }
188 }
189 if (result->trained[i] != 0) {
190 if (entry->stat >= 1 && entry->stat <= 5) {
191 win->message[0]->setString(win->message[0], FILE_CACHE.load(STGTRAIN_TEXT), 0x5C);
192 win->message[0]->setSubString(win->message[0], FILE_CACHE.load(STGTRAIN_TEXT), entry->stat + 0x46, 1);
193 win->message[0]->setNumber(win->message[0], 2, result->gains[i]);
194 win->message[0]->setPalette(win->message[0], PALETTE_BLUE);
195 win->message[1]->setVisible(win->message[1], 0);
196 } else {
197 s16 other;
198
199 win->message[0]->setString(win->message[0], FILE_CACHE.load(STGTRAIN_TEXT), 0x5C);
200 win->message[0]->setSubString(win->message[0], FILE_CACHE.load(STGTRAIN_TEXT), entry->stat + 0x4D, 1);
201 win->message[0]->setNumber(win->message[0], 2, result->gains[i]);
202 win->message[0]->setPalette(win->message[0], PALETTE_BLUE);
203 other = entry->other;
204 if (other != 0) {
205 if (other >= 1 && other <= 5) {
206 if (result->losses[i] != 0) {
207 win->message[1]->setString(win->message[1], FILE_CACHE.load(STGTRAIN_TEXT), 0x5D);
208 win->message[1]->setSubString(win->message[1], FILE_CACHE.load(STGTRAIN_TEXT), entry->other + 0x46, 1);
209 win->message[1]->setNumber(win->message[1], 2, result->losses[i]);
210 win->message[1]->setPalette(win->message[1], PALETTE_RED);
211 } else {
212 win->message[1]->setVisible(win->message[1], 0);
213 }
214 } else {
215 win->message[1]->setString(win->message[1], FILE_CACHE.load(STGTRAIN_TEXT), 0x5C);
216 win->message[1]->setSubString(win->message[1], FILE_CACHE.load(STGTRAIN_TEXT), entry->other + 0x44, 1);
217 win->message[1]->setNumber(win->message[1], 2, result->losses[i]);
218 win->message[1]->setPalette(win->message[1], PALETTE_BLUE);
219 }
220 }
221 }
222 } else {
223 win->message[0]->setString(win->message[0], FILE_CACHE.load(STGTRAIN_TEXT), 0x46);
224 win->message[0]->setPalette(win->message[0], PALETTE_WHITE);
225 win->message[1]->setVisible(win->message[1], 0);
226 }
227}
228
229/* The bonus of the accessories 0x151 (3) and 0x152 (6) */
232
233 if (stats->equip[4] == 0x151 || stats->equip[5] == 0x151) {
234 return 3;
235 }
236 if (stats->equip[4] == 0x152 || stats->equip[5] == 0x152) {
237 return 6;
238 }
239 return 0;
240}
241
242/* Creates the training result's text windows and cursor */
244 win->message[0] = createTextWindow(result->layerId, 1, 0x74, 0xC0);
245 win->message[0]->setLines(win->message[0], 2);
246 win->message[1] = createTextWindow(result->layerId, 1, 0x74, 0xCE);
247 win->question[0] = createTextWindow(0x1002, 1, 0xA2, 0x75);
248 win->question[1] = createTextWindow(0x1002, 1, 0xA2, 0x91);
249 win->question[2] = createTextWindow(0x1002, 1, 0xA2, 0xA1);
250 win->cursor = createCursor(0x1002, result->depth - 1, 0x94, 0x91);
251 win->cursor->setVisible(win->cursor, 0);
252}
253
254/*
255 * Draws the training result: the blinking arrow, a mark for each try (0x45
256 * worked, 0x46 failed) and the four panels.
257 */
259 SpriteDrawer sprite;
260 s32 i;
261
262 if (result->prompting != 0) {
263 initSpriteDrawer(&sprite);
264 sprite.setLayerId(0x1002, 3);
265 sprite.setTexture(0x140, 0);
266 if (GFX.funcs.getTime() - result->arrowTime >= 4) {
267 result->arrowTime = GFX.funcs.getTime();
268 result->arrowClut++;
269 if (result->arrowClut >= 5) {
270 result->arrowClut = 0;
271 }
272 }
273 sprite.setClutRow(result->arrowClut);
274 sprite.draw(FILE_CACHE.getEntry(FILE_MENU_SPRITES << 16), 0xA, 0x124, 0xCD);
275 }
276 initSpriteDrawer(&sprite);
277 sprite.setTexture(0x240, 0x100);
278 sprite.setLayerId(result->layerId, result->depth);
279 if (result->bonusTrying != 0) {
280 if (GFX.funcs.getTime() - result->bonusBlinkTime >= 3) {
281 result->bonusBlinkTime = GFX.funcs.getTime();
282 result->bonusBlink = 1 - result->bonusBlink;
283 }
284 sprite.setClutRow(result->bonusBlink + 1);
285 }
286 for (i = 0; i < 5; i++) {
287 if (result->bonusWorked != 0 && i == 3) {
288 sprite.setClutRow(3);
289 }
290 if (result->trained[i] == 1) {
291 sprite.draw(FILE_CACHE.getEntry(STGTRAIN_SPRITES), 0x45, i * 0x11 + 0x80, 0x58);
292 } else if (result->trained[i] == 0) {
293 sprite.draw(FILE_CACHE.getEntry(STGTRAIN_SPRITES), 0x46, i * 0x11 + 0x80, 0x58);
294 }
295 }
296 sprite.setClutRow(0);
297 if (result->panels[0].level != 0) {
298 if (result->panels[0].level != ONE) {
299 sprite.setScale(result->panels[0].level, result->panels[0].level, ONE);
300 sprite.setPivot(0xCF, 0x7F);
301 }
302 sprite.draw(FILE_CACHE.getEntry(STGTRAIN_SPRITES), 0x28, 0x72, 0x4B);
303 }
304 if (result->panels[1].level != 0) {
305 if (result->panels[1].level != ONE) {
306 sprite.setScale(result->panels[1].level, ONE, ONE);
307 sprite.setPivot(0x140, 0xCD);
308 }
309 sprite.draw(FILE_CACHE.getEntry(STGTRAIN_SPRITES), 0x23, 0x46, 0xBA);
310 }
311 sprite.setLayerId(0x1002, result->depth);
312 if (result->panels[2].level != 0) {
313 if (result->panels[2].level != ONE) {
314 sprite.setScale(result->panels[2].level, ONE, ONE);
315 sprite.setPivot(0x140, 0x7B);
316 }
317 sprite.draw(FILE_CACHE.getEntry(STGTRAIN_SPRITES), 0x26, 0x85, 0x70);
318 }
319 if (result->panels[3].level != 0) {
320 if (result->panels[3].level != ONE) {
321 sprite.setScale(result->panels[3].level, ONE, ONE);
322 sprite.setPivot(0x140, 0x9F);
323 }
324 sprite.draw(FILE_CACHE.getEntry(STGTRAIN_SPRITES), 0x1D, 0x82, 0x8B);
325 }
326}
327
328#if VERSION_EU || VERSION_JP
329/* A battle stat (1-5) or a resistance (8-14) of TOTALS: the match depends on
330 reading them through these (indexed in place, the stat's address is
331 summed with the index first) */
332static inline s16 getStat(PartnerTotals *totals, s32 stat) {
333 return totals->fields.battle[stat - 1];
334}
335
336static inline s16 getResistance(PartnerTotals *totals, s32 stat) {
337 return totals->fields.resist[stat - 8];
338}
339#endif
340
341/* Takes the result of a try: plays its sound and applies it, then plays the
342 next try, or, after the last, asks for the bonus try (three good tries) or
343 ends the training (substate 3) */
344static inline void STGTRAIN_takeTry(TrainResult *result, TrainResultWindows *win) {
345 result->trained[result->step] = win->actor->getResult(win->actor);
346 if (result->trained[result->step] != -1) {
347 if (result->trained[result->step] != 0) {
348 SOUND.playSound(0x840001);
349 } else {
350 SOUND.playSound(0x840000);
351 }
352 STGTRAIN_applyTry(result, result->step);
353 result->step++;
354 if (result->counter < result->step) {
355 if (result->counter == 2) {
356 if (result->trained[0] != 0 && result->trained[1] != 0 && result->trained[2] != 0) {
357 result->substate = 0xA;
358 return;
359 }
360 if (result->training >= 0xD) {
361 result->counter = 4;
362 win->actor->play(win->actor);
363 return;
364 }
365 }
366 result->setSubstate(result, 3);
367 } else {
368 win->actor->play(win->actor);
369 }
370 }
371}
372
373/* Once cross is pressed, shows what the training gave: the stat's gain, and
374 the other stat's loss or gain, in the message, and the stats before and
375 after */
376static inline void STGTRAIN_showGains(TrainResult *result, TrainResultWindows *win) {
377 TrainEntry *entry;
378 s32 sums[2];
379#if VERSION_EU || VERSION_JP
380 s32 shown[2]; /* the sums, up to the stats' limits */
381 s16 other;
382#endif
383 s32 i;
384
385 if (!PAD_PRESSED(PAD_CROSS)) {
386 return;
387 }
389 result->prompting = 0;
390 entry = STGTRAIN_state.findTableEntry(result->modeArg, result->training);
391 if (entry->stat != 0) {
392 sums[0] = 0;
393 for (i = 0; i < 5; i++) {
394 sums[0] += result->gains[i];
395 }
396 if (entry->stat >= 8 && entry->stat <= 14) {
397 if (entry->other != 0) {
398 sums[1] = 0;
399 for (i = 0; i < 5; i++) {
400 sums[1] += result->losses[i];
401 }
402 }
403 } else {
404 sums[1] = 0;
405 }
406 }
407 if (sums[0] == 0 && sums[1] == 0) {
408 win->message[0]->setString(win->message[0], FILE_CACHE.load(STGTRAIN_TEXT), 0x71);
409 } else {
410#if VERSION_EU || VERSION_JP
411 for (i = 0; i < 2; i++) {
412 shown[i] = sums[i];
413 }
414 if (sums[0] != 0) {
415 if (entry->stat >= 1 && entry->stat <= 5) {
416 if (getStat(&result->before, entry->stat) + sums[0] >= 1000) {
417 shown[0] = 999 - getStat(&result->before, entry->stat);
418 } else {
419 shown[0] = sums[0];
420 }
421 } else {
422 if (getResistance(&result->before, entry->stat) + sums[0] >= 1000) {
423 shown[0] = 999 - getResistance(&result->before, entry->stat);
424 } else {
425 shown[0] = sums[0];
426 }
427 }
428 }
429 if (sums[1] != 0) {
430 other = entry->other;
431 if (other >= 1 && other <= 5) {
432 if (getStat(&result->before, other) - sums[1] < 0) {
433 shown[1] = getStat(&result->before, other);
434 } else {
435 shown[1] = sums[1];
436 }
437 } else if (other >= 8 && other <= 14) {
438 if (getResistance(&result->before, other) + sums[1] >= 1000) {
439 shown[1] = 999 - getResistance(&result->before, other);
440 } else {
441 shown[1] = sums[1];
442 }
443 } else if (other == 15) {
444 if (result->before.fields.maxHp + sums[1] >= 10000) {
445 shown[1] = 9999 - result->before.fields.maxHp;
446 } else {
447 shown[1] = sums[1];
448 }
449 } else if (other == 16) {
450 if (result->before.fields.maxMp + sums[1] >= 10000) {
451 shown[1] = 9999 - result->before.fields.maxMp;
452 } else {
453 shown[1] = sums[1];
454 }
455 }
456 }
457#endif
458 if (entry->stat >= 1 && entry->stat <= 5) {
459 win->message[0]->setString(win->message[0], FILE_CACHE.load(STGTRAIN_TEXT), entry->stat + 0x5D);
460#if VERSION_US
461 win->message[0]->setNumber(win->message[0], 1, sums[0]);
462#elif VERSION_EU || VERSION_JP
463 win->message[0]->setNumber(win->message[0], 1, shown[0]);
464#endif
465 } else if (sums[1] != 0) {
466 win->message[0]->setString(win->message[0], FILE_CACHE.load(STGTRAIN_TEXT), entry->stat + 0x62);
467#if VERSION_US
468 win->message[0]->setNumber(win->message[0], 1, sums[0]);
469#elif VERSION_EU || VERSION_JP
470 win->message[0]->setNumber(win->message[0], 1, shown[0]);
471#endif
472#if VERSION_US
473 win->message[0]->setNumber(win->message[0], 2, sums[1]);
474#elif VERSION_EU || VERSION_JP
475 win->message[0]->setNumber(win->message[0], 2, shown[1]);
476#endif
477 } else {
478 win->message[0]->setString(win->message[0], FILE_CACHE.load(STGTRAIN_TEXT), entry->stat + 0x5B);
479#if VERSION_US
480 win->message[0]->setNumber(win->message[0], 1, sums[0]);
481#elif VERSION_EU || VERSION_JP
482 win->message[0]->setNumber(win->message[0], 1, shown[0]);
483#endif
484 }
485 }
486 win->message[0]->setPalette(win->message[0], PALETTE_WHITE);
487 win->message[0]->setTypeDelay(win->message[0], 6);
488 win->message[1]->setVisible(win->message[1], 0);
489 result->substate++;
490 result->screen->showStats(result->screen, &result->before);
491}
492
493/* Moves the cursor between yes and no of the bonus try's question, and
494 takes the answer (triangle: no) */
495static inline void STGTRAIN_askBonusTry(TrainResult *result, TrainResultWindows *win) {
496 s32 last;
497
498 last = result->before.fields.spare;
500 result->before.fields.spare = 0;
501 } else if (PAD_PRESSED(PAD_DOWN) || PAD_REPEATED(PAD_DOWN)) {
502 result->before.fields.spare = 1;
503 }
504 if (last != result->before.fields.spare) {
506 win->cursor->setPos(win->cursor, 0x94, result->before.fields.spare * 16 + 0x91);
507 } else if (PAD_PRESSED(PAD_CROSS)) {
509 if (result->before.fields.spare == 0) {
510 result->counter = 0;
511 result->substate++;
512 } else {
513 result->counter = 4;
514 result->substate++;
515 }
516 } else if (PAD_PRESSED(PAD_TRIANGLE)) {
518 result->counter = 4;
519 result->substate++;
520 }
521}
522
523/* Once the question's panels close: yes makes the bonus try with its sound
524 (a sure fail when the training is the partner's last bonus one, else a
525 50% chance), no plays the other tries */
526static inline void STGTRAIN_startBonusTry(TrainResult *result, TrainResultWindows *win) {
527 PartnerStats *stats;
528
529 STGTRAIN_state.updateFade(&result->panels[2]);
530 if (STGTRAIN_state.updateFade(&result->panels[3])) {
531 if (result->counter == 0) {
532 result->substate = 0x14;
533 result->bonusTrying = 1;
534 win->actor->play(win->actor);
535 result->bonusSound = SOUND.playSound(0xA084603C);
536 stats = GAME.funcs.getPartnerStats(result->partner);
537 if (stats->lastBonus != 0 && stats->lastBonus == result->training) {
538 win->actor->setChance(win->actor, 0);
539 } else {
540 stats->lastBonus = 0;
541 win->actor->setChance(win->actor, 0x32);
542 }
543 } else {
544 win->actor->play(win->actor);
545 result->substate = 2;
546 }
547 }
548}
549
550/* Takes the result of the bonus try: a good one makes the training the
551 partner's last bonus one and the gains take their better columns */
552static inline void STGTRAIN_takeBonusTry(TrainResult *result, TrainResultWindows *win) {
553 PartnerStats *stats;
554
555 result->trained[3] = win->actor->getResult(win->actor);
556 if (result->trained[3] != -1) {
557 stats = GAME.funcs.getPartnerStats(result->partner);
558 if (result->trained[3] != 0) {
559 stats->lastBonus = result->training;
560 result->bonusWorked = 1;
561 } else {
562 stats->lastBonus = 0;
563 }
564 if (result->trained[3] != 0) {
565 SOUND.playSound(0x840001);
566 } else {
567 SOUND.playSound(0x840000);
568 }
569 SOUND.keyOff(0xA084603C, result->bonusSound);
570 STGTRAIN_applyTry(result, 3);
571 result->prompting = 1;
572 result->bonusTrying = 0;
573 result->setSubstate(result, 3);
574 }
575}
576
577/*
578 * Runs a training: the partner tries it three times (five at the gyms'
579 * second half), then shows what it gained. Three good tries in a row give
580 * a bonus try, asked for (with the training as the partner's last) after
581 * the gyms' first half.
582 */
584 switch (result->substate) {
585 case 0:
586 default:
587 STGTRAIN_state.startFade(&result->panels[0], 1);
588 STGTRAIN_state.startFade(&result->panels[1], 1);
589 win->actor->grow(win->actor);
590 result->substate++;
591 break;
592 case 1:
593 STGTRAIN_state.updateFade(&result->panels[1]);
594 if (STGTRAIN_state.updateFade(&result->panels[0]) && (win->actor->mode & 1)) {
595 result->counter = 2;
596 result->substate++;
597 win->actor->play(win->actor);
598 win->actor->setChance(win->actor, STGTRAIN_getAccessoryBonus(result) + 0x4B);
599 }
600 break;
601 case 2:
602 STGTRAIN_takeTry(result, win);
603 break;
604 case 3:
605 win->actor->end(win->actor);
606 result->substate++;
607 break;
608 case 4:
609 if (win->actor->mode & 1) {
610 result->prompting = 1;
611 result->substate++;
612 }
613 break;
614 case 5:
615 STGTRAIN_showGains(result, win);
616 break;
617 case 6:
618 if (win->message[0]->isFinished(win->message[0])) {
620 result->substate = 0x32;
621 result->prompting = 0;
622 result->screen->showStats(result->screen, NULL);
623 } else if (win->message[0]->isWaitingForButton(win->message[0])) {
624 result->prompting = 1;
625 if (PAD_PRESSED(PAD_CROSS)) {
627 result->prompting = 0;
628 }
629 } else {
630 result->prompting = 0;
631 if (PAD_PRESSED(PAD_CROSS)) {
632 win->message[0]->showPage(win->message[0]);
633 }
634 }
635 break;
636 case 0xA:
637 if (result->training < 0xD) {
638 result->substate = 0x14;
639 result->bonusTrying = 1;
640 win->actor->play(win->actor);
641 result->bonusSound = SOUND.playSound(0xA084603C);
642 } else {
643 result->substate++;
644 }
645 break;
646 case 0xB:
647 STGTRAIN_state.startFade(&result->panels[2], 1);
648 result->substate++;
649 break;
650 case 0xC:
651 if (STGTRAIN_state.updateFade(&result->panels[2])) {
652 win->question[0]->setString(win->question[0], FILE_CACHE.load(STGTRAIN_TEXT), 0x11);
653 STGTRAIN_state.startFade(&result->panels[3], 1);
654 result->substate++;
655 }
656 break;
657 case 0xD:
658 if (STGTRAIN_state.updateFade(&result->panels[3])) {
659 win->question[1]->setString(win->question[1], FILE_CACHE.load(STGTRAIN_TEXT), 0xC);
660 win->question[2]->setString(win->question[2], FILE_CACHE.load(STGTRAIN_TEXT), 0xD);
661 win->cursor->setPos(win->cursor, 0x94, result->before.fields.spare * 16 + 0x91);
662 win->cursor->setVisible(win->cursor, 1);
663 result->substate++;
664 }
665 break;
666 case 0xE:
667 STGTRAIN_askBonusTry(result, win);
668 break;
669 case 0xF:
670 STGTRAIN_state.startFade(&result->panels[2], 0);
671 STGTRAIN_state.startFade(&result->panels[3], 0);
672 win->question[0]->setVisible(win->question[0], 0);
673 win->question[1]->setVisible(win->question[1], 0);
674 win->question[2]->setVisible(win->question[2], 0);
675 win->cursor->setVisible(win->cursor, 0);
676 result->substate++;
677 break;
678 case 0x10:
679 STGTRAIN_startBonusTry(result, win);
680 break;
681 case 0x14:
682 STGTRAIN_takeBonusTry(result, win);
683 break;
684 case 0x32:
685 result->state = TASK_KILL;
686 break;
687 }
688}
689
690/* The training result's task */
692 s32 i;
693
694 switch (result->state) {
695 case TASK_INIT:
696 default:
697 result->nextState(result);
698 STGTRAIN_createResultWindows(result, win);
699 result->panels[0].duration = 10;
700 result->panels[1].duration = 10;
701 result->panels[2].duration = 10;
702 result->panels[3].duration = 10;
703 for (i = 0; i < 5; i++) {
704 result->trained[i] = -1;
705 }
706 win->actor = STGTRAIN_createActor(result->partner, result->training, result->layerId, result->depth - 3);
707 win->actor->setPos(win->actor, 0x300, 0);
708 win->actor->setClutPos(win->actor, 0x2C0, 0);
709 win->actor->pause(win->actor);
710 win->actor->setScale(win->actor, 0);
711 GAME.funcs.computeStats(result->partner, &result->before);
712 break;
713 case TASK_RUN:
714 STGTRAIN_runTraining(result, win);
715 STGTRAIN_drawResult(result);
716 break;
717 case TASK_DONE:
718 case TASK_KILL:
719 break;
720 }
721}
722
723/* Creates the results of a training of a partner */
726
727 result->layerId = SCREEN_LAYER;
728 result->depth = 6;
729 result->screen = screen;
730 result->partner = partner;
731 result->training = training;
732 result->modeArg = GAME.funcs.getModeArg();
733 return result;
734}
735
736/* Left empty, as are the idle task's other steps */
737void STGTRAIN_initIdle(TrainIdle *task, void *children) {
738}
739
740/* Left empty */
741void STGTRAIN_showIdle(TrainIdle *task, void *children, s32 show) {
742}
743
744/* Only sets up a sprite drawer */
746 SpriteDrawer sprite;
747
748 initSpriteDrawer(&sprite);
749}
750
751/* Left empty */
752void STGTRAIN_runIdle(TrainIdle *task, void *children) {
753}
754
755/* A task that does nothing: its steps are empty, and nothing creates it */
756void STGTRAIN_updateIdle(TrainIdle *task, void *children) {
757 switch (task->state) {
758 case TASK_INIT:
759 default:
760 task->nextState(task);
761 STGTRAIN_initIdle(task, children);
762 STGTRAIN_showIdle(task, children, 1);
763 break;
764 case TASK_RUN:
765 STGTRAIN_runIdle(task, children);
766 STGTRAIN_drawIdle(task);
767 break;
768 case TASK_DONE:
769 case TASK_KILL:
770 break;
771 }
772}
773
774/* Creates the idle task for the screen */
777
778 task->layerId = SCREEN_LAYER;
779 task->depth = 6;
780 task->screen = screen;
781 return task;
782}
783
784/* The data: this object's tables */
785/* The battle stats a training raises, by [training >= 13][bonusWorked][level] */
787 {1, 2}, {7, 2}, {14, 3},
788 {2, 0}, {10, 0}, {20, 0},
789 {1, 2}, {6, 3}, {11, 5},
790 {4, 0}, {22, 0}, {48, 0},
791};
792/* What a training may lower another battle stat by, by level */
794 {1, 0}, {2, 3}, {4, 3},
795};
796/* The resistance gains, by [bonusWorked ? (training < 13 ? 1 : 2) : 0][level] */
798 {1, 0}, {1, 0}, {2, 0},
799 {4, 2}, {8, 0}, {12, 0},
800 {8, 2}, {20, 0}, {30, 0},
801};
803 {1, 2}, {2, 0}, {3, 0},
804 {6, 3}, {12, 0}, {18, 0},
805 {12, 4}, {30, 0}, {40, 0},
806};
808 {2, 0}, {2, 0}, {4, 0},
809 {8, 4}, {12, 0}, {25, 0},
810 {16, 5}, {30, 0}, {50, 0},
811};
812/* The resistance gain tables, by the Digimon's affinity and the
813 resistance's value (under 100, under 300, more) */
820/* The max HP and MP gains, indexed like the resistances */
822 {1, 2}, {2, 0}, {4, 0},
823 {6, 4}, {10, 0}, {20, 0},
824 {13, 5}, {20, 0}, {40, 0},
825};
#define NULL
Definition common.h:17
signed int s32
Definition common.h:11
signed short s16
Definition common.h:9
DigimonData DIGIMON_DATA[55]
55 entries: the 52 Digimon, then three placeholders (0x1D4-0x1D6)
Definition digimon.c:7
GfxState GFX
GFX: the graphics state and its methods.
Definition display.c:209
GameState GAME
The save data, the game mode and the methods.
Definition state.c:64
#define TASK_RUN
Definition task.h:35
#define TASK_KILL
Definition task.h:37
#define TASK_INIT
Tasks: every game object is a task, a heap block that starts with this header and is updated once per...
Definition task.h:34
#define TASK_DONE
Definition task.h:36
Cursor * createCursor(s16 layerId, s32 depth, s16 x, s16 y)
A menu cursor on a layer at (x, y)
Definition cursor.c:92
#define FILE_MENU_SPRITES
Files the engine loads by number.
Definition file.h:188
FileCache FILE_CACHE
The file cache.
Definition file_cache.c:7
TrainState STGTRAIN_state
Definition files.c:422
#define SCREEN_LAYER
The layer over the whole screen that most modes create first and draw their menus on (FIELDSTG and ST...
Definition gfx.h:45
STGTRAIN.PRO: the gyms, where the partners train their stats.
#define STGTRAIN_SPRITES
its sprite bank
Definition gym.h:23
#define STGTRAIN_TEXT
The overlay's files: the discs number them differently.
Definition gym.h:19
TrainActor * STGTRAIN_createActor(s32 set, s32 file, s32 layerId, s32 depth)
Creates an animated sprite of an image set.
Definition actor.c:302
#define PAD_CROSS
Definition pad.h:31
#define PAD_DOWN
Definition pad.h:24
#define PAD_TRIANGLE
Definition pad.h:32
#define PAD_PRESSED(button)
One button of pad 1: newly pressed, auto-repeated while held, or held.
Definition pad.h:140
#define PAD_UP
Definition pad.h:22
#define PAD_REPEATED(button)
Definition pad.h:141
Random RANDOM
Definition random.c:533
void STGTRAIN_applyTry(TrainResult *result, s32 i)
Applies the i-th try of a training (if it worked) and shows what it changed: the stat it raises,...
Definition result.c:165
TrainGain STGTRAIN_resistGainsMid[]
Definition result.c:802
TrainGain STGTRAIN_statLosses[]
What a training may lower another battle stat by, by level.
Definition result.c:793
void STGTRAIN_runIdle(TrainIdle *task, void *children)
Left empty.
Definition result.c:752
s32 STGTRAIN_raiseMaxHpMp(TrainResult *result, s32 stat)
Raises the maximum HP (stat 15) or MP (16) by the training's gain, up to 9999; the US version also ra...
Definition result.c:110
void STGTRAIN_runTraining(TrainResult *result, TrainResultWindows *win)
Runs a training: the partner tries it three times (five at the gyms' second half),...
Definition result.c:583
static void STGTRAIN_startBonusTry(TrainResult *result, TrainResultWindows *win)
Once the question's panels close: yes makes the bonus try with its sound (a sure fail when the traini...
Definition result.c:526
void STGTRAIN_drawResult(TrainResult *result)
Draws the training result: the blinking arrow, a mark for each try (0x45 worked, 0x46 failed) and the...
Definition result.c:258
static s16 getResistance(PartnerTotals *totals, s32 stat)
Definition result.c:336
static void STGTRAIN_takeTry(TrainResult *result, TrainResultWindows *win)
Takes the result of a try: plays its sound and applies it, then plays the next try,...
Definition result.c:344
void STGTRAIN_initIdle(TrainIdle *task, void *children)
Left empty, as are the idle task's other steps.
Definition result.c:737
s32 STGTRAIN_lowerStat(TrainResult *result, s32 stat)
Lowers a battle stat (1-5) by the training's loss, half of the time, down to 0.
Definition result.c:35
void STGTRAIN_showIdle(TrainIdle *task, void *children, s32 show)
Left empty.
Definition result.c:741
s32 STGTRAIN_getAccessoryBonus(TrainResult *result)
The bonus of the accessories 0x151 (3) and 0x152 (6)
Definition result.c:230
static void STGTRAIN_takeBonusTry(TrainResult *result, TrainResultWindows *win)
Takes the result of the bonus try: a good one makes the training the partner's last bonus one and the...
Definition result.c:552
TrainGain STGTRAIN_maxHpMpGains[]
The max HP and MP gains, indexed like the resistances.
Definition result.c:821
void STGTRAIN_drawIdle(TrainIdle *task)
Only sets up a sprite drawer.
Definition result.c:745
static void STGTRAIN_askBonusTry(TrainResult *result, TrainResultWindows *win)
Moves the cursor between yes and no of the bonus try's question, and takes the answer (triangle: no)
Definition result.c:495
static s16 getStat(PartnerTotals *totals, s32 stat)
A battle stat (1-5) or a resistance (8-14) of TOTALS: the match depends on reading them through these...
Definition result.c:332
void STGTRAIN_updateIdle(TrainIdle *task, void *children)
A task that does nothing: its steps are empty, and nothing creates it.
Definition result.c:756
void STGTRAIN_createResultWindows(TrainResult *result, TrainResultWindows *win)
Creates the training result's text windows and cursor.
Definition result.c:243
static void STGTRAIN_showGains(TrainResult *result, TrainResultWindows *win)
Once cross is pressed, shows what the training gave: the stat's gain, and the other stat's loss or ga...
Definition result.c:376
TrainResult * STGTRAIN_createResult(TrainScreen *screen, s32 partner, s32 training)
Creates the results of a training of a partner.
Definition result.c:724
s32 STGTRAIN_raiseStat(TrainResult *result, s32 stat)
Raises a battle stat (1-5) by the training's gain, up to 999.
Definition result.c:8
TrainGain STGTRAIN_statGains[]
The battle stats a training raises, by [training >= 13][bonusWorked][level].
Definition result.c:786
TrainGain STGTRAIN_resistGainsHigh[]
Definition result.c:807
void STGTRAIN_updateResult(TrainResult *result, TrainResultWindows *win)
The training result's task.
Definition result.c:691
TrainIdle * STGTRAIN_createIdle(TrainScreen *screen)
Creates the idle task for the screen.
Definition result.c:775
TrainGain STGTRAIN_resistGainsLow[]
The resistance gains, by [bonusWorked ? (training < 13 ? 1 : 2) : 0][level].
Definition result.c:797
s32 STGTRAIN_raiseResistance(TrainResult *result, s32 stat)
Raises a resistance (stat 8-14) by the training's gain, up to 999: the table goes by the Digimon's gr...
Definition result.c:62
TrainGain * STGTRAIN_resistGainTables[]
The resistance gain tables, by the Digimon's affinity and the resistance's value (under 100,...
Definition result.c:814
SoundState SOUND
rsin and rcos (libgte) read rsin_tbl[a - 0x800] and the like: their addresses before the table fall i...
Definition sound.c:180
#define SOUND_MENU_CONFIRM
SYSTEM07.
Definition sound.h:44
#define SOUND_SELECT
Sounds the overlays share, with SOUNDTST's names.
Definition sound.h:38
#define SOUND_MENU_CANCEL
SYSTEM01.
Definition sound.h:39
#define SOUND_CURSOR
SYSTEM02: a cursor moves.
Definition sound.h:40
void initSpriteDrawer(SpriteDrawer *obj)
Clears a sprite drawer to neutral (no scale, gray tint, follows the scroll), gives it its methods and...
void(* setPos)()
(cursor, x, y)
Definition text.h:34
void(* setVisible)()
(cursor, visible)
Definition text.h:33
Digimon definition (DIGIMON_DATA, 52 of them; the first 8 are the partners)
Definition game_state.h:86
u8 resistGrowth[7]
1-5: how fast the gyms raise them
Definition game_state.h:103
void *(* load)(u32 file)
Definition file.h:92
void *(* getEntry)(u32 fileAndIndex)
Definition file.h:96
s32(* getModeArg)()
Definition game_state.h:20
struct PartnerStats *(* getPartnerStats)(s32 partner)
Definition game_state.h:38
void(* computeStats)(s32 partner, union PartnerTotals *out)
Definition game_state.h:31
GameFuncs funcs
Definition game_state.h:582
s32(* getTime)(void)
Definition gfx.h:31
GfxFuncs funcs
Definition gfx.h:77
s32 level
Definition menu.h:21
s32 duration
Definition menu.h:19
A partner Digimon from its name on (Partner.info), as getPartnerStats gives it.
Definition game_state.h:303
s16 stats[19]
Definition game_state.h:306
u8 lastBonus
the training whose bonus try last worked, 0 for none: its try can't work again at once
Definition game_state.h:311
s32(* next)(void)
0 to RANDOM_COUNT - 1
Definition random.h:15
short(* playSound)(s32 id)
returns the voice of a key-on
Definition sound.h:187
void(* keyOff)(s32 id, s16 voice)
Definition sound.h:189
Draws sprites from a sprite sheet (such as file 0x277, the menu graphics): a sheet has a table of fra...
Definition gfx.h:223
void(* setPivot)()
(x, y)
Definition gfx.h:250
void(* setScale)()
(x, y, z), ONE = 1.0
Definition gfx.h:248
void(* setLayerId)()
(id, depth)
Definition gfx.h:244
void(* setClutRow)()
(row)
Definition gfx.h:247
void(* draw)()
(sheet, frame, x, y)
Definition gfx.h:246
void(* setTexture)()
(x, y)
Definition gfx.h:242
s32(* isWaitingForButton)()
Definition text.h:188
void(* setPalette)(struct TextWindow *obj, u8 arg)
Definition text.h:174
s32(* isFinished)()
s32: callers don't truncate the result to a byte
Definition text.h:186
void(* setTypeDelay)()
Definition text.h:172
void(* setLines)()
no prototype: callers would truncate u8 args
Definition text.h:184
void(* setSubString)()
Definition text.h:168
void(* setNumber)()
Definition text.h:166
void(* setString)()
Definition text.h:165
void(* showPage)()
Definition text.h:170
void(* setVisible)(struct TextWindow *obj, u8 arg)
Definition text.h:177
void(* play)(struct TrainActor *actor)
Definition gym.h:234
void(* setClutPos)(struct TrainActor *actor, s32 x, s32 y)
Definition gym.h:230
void(* setScale)(struct TrainActor *actor, s32 scale)
Definition gym.h:236
void(* grow)(struct TrainActor *actor)
Definition gym.h:232
void(* pause)(struct TrainActor *actor)
Definition gym.h:235
void(* end)(struct TrainActor *actor)
Definition gym.h:238
u32 mode
Definition gym.h:211
void(* setChance)(struct TrainActor *actor, s32 chance)
Definition gym.h:231
s32(* getResult)(struct TrainActor *actor)
Definition gym.h:237
void(* setPos)(struct TrainActor *actor, s32 x, s32 y)
Definition gym.h:229
An entry of a gym level's trainings (STGTRAIN_gymTrainings)
Definition gym.h:326
s16 stat
1-5 battle stats, 8-14 resistances
Definition gym.h:328
s16 other
1-5: lowered, 15 or 16: max HP or MP raised
Definition gym.h:329
A stat change of a training: base plus a random 0..range-1.
Definition gym.h:282
s32 base
Definition gym.h:283
s32 range
Definition gym.h:284
A task the overlay creates (STGTRAIN_createIdle) that does nothing.
Definition gym.h:199
s32 state
Definition gym.h:200
s32 depth
Definition gym.h:203
TrainScreen * screen
Definition gym.h:201
void(* nextState)(struct TrainIdle *task)
Definition gym.h:200
s32 layerId
Definition gym.h:202
The children of TrainResult.
Definition gym.h:274
TextWindow * question[3]
whether to make the bonus try, yes, no
Definition gym.h:276
TrainActor * actor
Definition gym.h:278
TextWindow * message[2]
Definition gym.h:275
Cursor * cursor
Definition gym.h:277
The results of a training (STGTRAIN_createResult)
Definition gym.h:250
void * children
Definition gym.h:251
s32 training
Definition gym.h:256
s16 bonusSound
the slot of the bonus try's sound
Definition gym.h:269
s32 gains[5]
Definition gym.h:258
s32 trained[5]
Definition gym.h:257
s32 depth
Definition gym.h:254
s32 arrowClut
Definition gym.h:267
void(* nextState)(struct TrainResult *task)
Definition gym.h:251
PanelAnim panels[4]
Definition gym.h:270
s32 counter
Definition gym.h:251
s32 losses[5]
Definition gym.h:259
s32 prompting
the blinking arrow: cross goes on
Definition gym.h:266
TrainScreen * screen
Definition gym.h:252
s32 arrowTime
Definition gym.h:268
s32 bonusBlinkTime
Definition gym.h:265
PartnerTotals before
Definition gym.h:261
s32 partner
Definition gym.h:255
s32 substate
Definition gym.h:251
s32 step
Definition gym.h:251
s32 layerId
Definition gym.h:253
s32 bonusBlink
Definition gym.h:264
s32 bonusWorked
the gains take their better columns
Definition gym.h:263
s32 bonusTrying
the bonus try (the fourth) is on: its mark blinks
Definition gym.h:262
void(* setSubstate)(struct TrainResult *task, s32 substate)
Definition gym.h:251
s32 modeArg
Definition gym.h:260
s32 state
Definition gym.h:251
The training screen's main task (STGTRAIN_createScreen)
Definition gym.h:106
void(* showStats)(struct TrainScreen *screen, PartnerTotals *before)
Definition gym.h:127
s32 intensity
the last one picked
Definition gym.h:119
s32(* updateFade)(PanelAnim *fade)
Definition gym.h:348
void(* startFade)(PanelAnim *fade, s32 fadeIn)
Definition gym.h:347
TrainEntry *(* findTableEntry)(s32 index, s32 id)
Definition gym.h:364
void * createTask(void(*update)(), s32 size, s32 childrenSize)
createTaskWithId for a task nothing needs to find
Definition task.c:105
#define PALETTE_BLUE
a light blue: what is highlighted or current
Definition text.h:113
#define PALETTE_RED
Definition text.h:117
#define PALETTE_WHITE
The text windows' palettes (TextWindow.palette, setPalette): rows of the font's CLUTs,...
Definition text.h:112
TextWindow * createTextWindow(s16 layerId, s16 style, s16 x, s16 y)
A text window on a layer, in a font style, at (x, y)
computeStats' result: the stats with the equipment added, by STAT_* or by name.
Definition game_state.h:409
s32 spare
not filled: STGTRAIN's result keeps its yes/no answer here, 0 yes
Definition game_state.h:422
s16 battle[6]
strength (raised by weapons), defense (by armour), spirit, wisdom, speed and charisma (by all equipme...
Definition game_state.h:418
struct PartnerTotals::@10 fields