mirror of
https://github.com/ssstolk/rts4ds.git
synced 2025-06-19 09:25:36 -04:00
668 lines
25 KiB
C
668 lines
25 KiB
C
// SPDX-License-Identifier: MIT
|
|
// Copyright © 2007-2025 Sander Stolk
|
|
|
|
#include "animation.h"
|
|
|
|
#include "gif/gif.h"
|
|
#include "factions.h"
|
|
#include "subtitles.h"
|
|
#include "soundeffects.h"
|
|
#include "music.h"
|
|
#include "ingame_briefing.h"
|
|
#include "fileio.h"
|
|
#include "inputx.h"
|
|
|
|
#define ANIMATION_FADE_TIME SCREEN_REFRESH_RATE
|
|
|
|
#define MAX_ANIMATION_OVERLAY_TILES 10
|
|
#define ANIMATION_OVERLAY_TILE_DURATION (SCREEN_REFRESH_RATE/30)
|
|
#define ANIMATION_OVERLAY_DEFAULT_BLEND_A 6
|
|
#define MAX_ANIMATION_OVERLAY_BLEND_A_DEVIATION 3
|
|
#define ANIMATION_OVERLAY_DEFAULT_BLEND_B 12
|
|
#define MAX_ANIMATION_OVERLAY_BLEND_B_DEVIATION 3
|
|
|
|
// The values below are chosen to overlap as little as possible with the ingame BGs,
|
|
// so that we don't have to reload a lot of graphics when the animation stops and
|
|
// the game logic needs us to return to INGAME state
|
|
#define ANIMATION_BG3_GRAPHICS_OFFSET 5
|
|
#define ANIMATION_BG0_GRAPHICS_OFFSET 2
|
|
|
|
|
|
enum SceneState { SCS_FADEIN, SCS_NORMAL, SCS_FADEOUT };
|
|
enum FadeType { FT_NONE, FT_WHITE=1, FT_BLACK=2 };
|
|
|
|
char animationFilename[256];
|
|
int animationKeepMainFree;
|
|
int animationKeepMusicFree;
|
|
int animationKeepSoundFree;
|
|
|
|
int amountOfScenes;
|
|
int currentScene;
|
|
int newScene;
|
|
int manualMode; // 0 or 1 => false/true
|
|
enum SceneState currentSceneState;
|
|
int fadeTimer;
|
|
int animationTimer;
|
|
int sceneFirstFrame;
|
|
enum FadeType fadeIn, fadeOut;
|
|
float currentScenePlaybackSpeed;
|
|
|
|
uint16 animationOverlayGraphics[16*16/2 * MAX_ANIMATION_OVERLAY_TILES];
|
|
int animationOverlayTimer;
|
|
int animationOverlayTiles;
|
|
|
|
int animationInputDelay;
|
|
|
|
pGifHandler animationAni = NULL;
|
|
|
|
int animationLinked = 0;
|
|
|
|
|
|
|
|
void setAnimationOverlayTile(int nr) {
|
|
uint16* animationBG0Base = (uint16*)(CHAR_BASE_BLOCK_SUB(ANIMATION_BG0_GRAPHICS_OFFSET));
|
|
int i;
|
|
|
|
for (i=0; i<(16*16/2); i++)
|
|
animationBG0Base[((8*8)/2) + i] = animationOverlayGraphics[nr * ((16*16)/2) + i];
|
|
}
|
|
|
|
|
|
void drawAnimation() {
|
|
unsigned int i, j, k;
|
|
unsigned int fadeLevel;
|
|
uint16* animationBG3Base = (uint16*)(CHAR_BASE_BLOCK_SUB(ANIMATION_BG3_GRAPHICS_OFFSET));
|
|
|
|
if (!animationKeepMainFree)
|
|
initSpritesUsedPlayScreen();
|
|
initSpritesUsedInfoScreen();
|
|
|
|
if (currentScene == 0)
|
|
return;
|
|
|
|
if (sceneFirstFrame) {
|
|
swiWaitForVBlank();
|
|
drawAnimationBG();
|
|
for (i=1; i<animationAni->colCount; i++)
|
|
BG_PALETTE_SUB[i] = animationAni->gifPalette[i];
|
|
}
|
|
|
|
switch (currentSceneState) {
|
|
case SCS_FADEIN:
|
|
fadeLevel = (fadeTimer * (16+1)) / ANIMATION_FADE_TIME;
|
|
if (fadeLevel > 16)
|
|
fadeLevel = 16;
|
|
REG_MASTER_BRIGHT_SUB = fadeLevel | (fadeIn<<14);
|
|
case SCS_NORMAL:
|
|
if (fadeTimer == ANIMATION_FADE_TIME || animationTimer == 0) {
|
|
if (sceneFirstFrame) {
|
|
REG_BG3X_SUB = -(((SCREEN_WIDTH - animationAni->dimX) / 2) << 8);
|
|
REG_BG3Y_SUB = -(((SCREEN_HEIGHT - animationAni->dimY) / 2) << 8);
|
|
|
|
for (i=0; i<animationAni->dimY; i++) {
|
|
for (j=0; j<animationAni->dimX/2; j++) {
|
|
animationBG3Base[i*256/2 + j] = ((uint16*)animationAni->gifFrame)[i*(animationAni->dimX/2) + j];
|
|
}
|
|
for (; j<256/2; j++) {
|
|
animationBG3Base[i*256/2 + j] = 0;
|
|
}
|
|
}
|
|
for (i*=256/2; i<256*192/2; i++) {
|
|
animationBG3Base[i] = 0;
|
|
}
|
|
} else {
|
|
for (i=0; i<animationAni->dimY; i++) {
|
|
for (j=0; j<animationAni->dimX/2; j++) {
|
|
k = ((uint16*)animationAni->gifFrame)[i*(animationAni->dimX/2) + j];
|
|
// only draw if it's not transparent, otherwise it'd just cost precious VRAM access time
|
|
if (k) {
|
|
if (!(k & 0x00FF))
|
|
k |= (animationBG3Base[i*256/2 + j] & 0x00FF);
|
|
else if (!(k & 0xFF00))
|
|
k |= (animationBG3Base[i*256/2 + j] & 0xFF00);
|
|
animationBG3Base[i*256/2 + j] = k;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*if (sceneFirstFrame) {
|
|
// make block above actual GIF colour 0 (black)
|
|
j = 192-animationAni->dimY)/2;
|
|
k = j * 256 / 2;
|
|
for (i=0; i<k; i++)
|
|
BG_GFX_SUB[i] = 0;
|
|
|
|
// make block below actual GIF colour 0 (black)
|
|
j = 192-animationAni->dimY)/2;
|
|
k = j * 256 / 2;
|
|
for (i=0; i<256*192/2; i++)
|
|
BG_GFX_SUB[i] = 0;
|
|
}
|
|
|
|
|
|
for (i=0; i<animationAni->dimY; i++) {
|
|
for (j=0; j<animationAni->dimX/2; j++) {
|
|
k = ((uint16*)animationAni->gifFrame)[i*(animationAni->dimX/2) + j];
|
|
if (k) // if not transparent, otherwise it'd just cost precious VRAM access time
|
|
BG_GFX_SUB[i*256/2 + j] = k;
|
|
}
|
|
}*/
|
|
|
|
}
|
|
break;
|
|
case SCS_FADEOUT:
|
|
fadeLevel = (fadeTimer * (16+1)) / ANIMATION_FADE_TIME;
|
|
if (fadeLevel > 16)
|
|
fadeLevel = 16;
|
|
fadeLevel = 16 - fadeLevel;
|
|
REG_MASTER_BRIGHT_SUB = fadeLevel | (fadeOut<<14);
|
|
break;
|
|
}
|
|
|
|
if (animationOverlayTiles > 0) {
|
|
animationOverlayTimer++;
|
|
if (animationOverlayTimer >= animationOverlayTiles * ANIMATION_OVERLAY_TILE_DURATION)
|
|
animationOverlayTimer = 0;
|
|
if (animationOverlayTimer % ANIMATION_OVERLAY_TILE_DURATION == 0)
|
|
setAnimationOverlayTile(animationOverlayTimer / ANIMATION_OVERLAY_TILE_DURATION);
|
|
REG_BLDALPHA_SUB = ((ANIMATION_OVERLAY_DEFAULT_BLEND_A - MAX_ANIMATION_OVERLAY_BLEND_A_DEVIATION) + (rand() % (MAX_ANIMATION_OVERLAY_BLEND_A_DEVIATION*2 + 1))) |
|
|
(((ANIMATION_OVERLAY_DEFAULT_BLEND_B - MAX_ANIMATION_OVERLAY_BLEND_B_DEVIATION) + (rand() % (MAX_ANIMATION_OVERLAY_BLEND_B_DEVIATION*2 + 1))) << 8);
|
|
}
|
|
|
|
drawSubtitles();
|
|
sceneFirstFrame = 0;
|
|
}
|
|
|
|
void drawAnimationBG() {
|
|
int i;
|
|
uint16* animationBG3Base = (uint16*)(CHAR_BASE_BLOCK_SUB(ANIMATION_BG3_GRAPHICS_OFFSET));
|
|
|
|
BG_PALETTE_SUB[0] = 0; // set black as background
|
|
for (i=0; i<256*256/2; i++)
|
|
animationBG3Base[i] = 0;
|
|
|
|
if (!animationKeepMainFree)
|
|
REG_DISPCNT |= DISPLAY_BG3_ACTIVE;
|
|
REG_DISPCNT_SUB |= DISPLAY_BG3_ACTIVE;
|
|
}
|
|
|
|
|
|
enum FadeType getFadeType(char *oneline) {
|
|
char *charPosition = strchr(oneline, '=');
|
|
if (charPosition == NULL)
|
|
error("Could not find the type of\nthe fade in\n", "");
|
|
if (*(charPosition + 2) == 'B' || *(charPosition + 2) == 'b')
|
|
return FT_BLACK;
|
|
if (*(charPosition + 2) == 'W' || *(charPosition + 2) == 'w')
|
|
return FT_WHITE;
|
|
return FT_NONE;
|
|
}
|
|
|
|
|
|
void doAnimationFrameSoundeffectAndSubtitles(int frame) {
|
|
FILE *fp;
|
|
char oneline[256];
|
|
char *charPosition;
|
|
int amountOfSoundsToPlay;
|
|
int amountOfSubtitlesToShow;
|
|
int frameRead;
|
|
int i;
|
|
|
|
if (frame == 1)
|
|
setSubtitles("");
|
|
|
|
fp = openFile(animationFilename, FS_ANIMATIONS_FILE);
|
|
for (i=0; i<currentScene; i++) {
|
|
do {
|
|
readstr(fp, oneline);
|
|
} while (strncmp(oneline, "[SCENE", strlen("[SCENE")));
|
|
}
|
|
readstr(fp, oneline); // Name
|
|
readstr(fp, oneline); // Overlay or Fade-In
|
|
if (oneline[0] == 'O')
|
|
readstr(fp, oneline); // Fade-In
|
|
readstr(fp, oneline); // Fade-Out
|
|
readstr(fp, oneline); // Playback-Speed
|
|
readstr(fp, oneline); // Sounds to play
|
|
charPosition = strchr(oneline, '=');
|
|
if (charPosition == NULL)
|
|
error("Could not find the amount of\nsounds to play for current scene\n", "");
|
|
sscanf(charPosition, "= %i", &amountOfSoundsToPlay);
|
|
|
|
if (animationKeepSoundFree)
|
|
i=0;
|
|
else {
|
|
for (i=0; i<amountOfSoundsToPlay; i++) {
|
|
readstr(fp, oneline);
|
|
sscanf(oneline, "Frame%i ", &frameRead);
|
|
if (frameRead == frame) {
|
|
charPosition = strchr(oneline, '=');
|
|
if (charPosition == NULL)
|
|
error("Could not find the name of\nthe sound to play\n", "");
|
|
replaceEOLwithEOF(charPosition+2, 255);
|
|
playMiscSoundeffect(charPosition+2);
|
|
i++;
|
|
break;
|
|
} else if (frameRead > frame) {
|
|
i++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
for (; i<amountOfSoundsToPlay; i++)
|
|
readstr(fp, oneline);
|
|
|
|
if (getSubtitlesEnabled()) {
|
|
readstr(fp, oneline); // Subtitles to show
|
|
charPosition = strchr(oneline, '=');
|
|
if (charPosition == NULL)
|
|
error("Could not find the amount of\nsubs to play for current scene\n", "");
|
|
sscanf(charPosition, "= %i", &amountOfSubtitlesToShow);
|
|
for (i=0; i<amountOfSubtitlesToShow; i++) {
|
|
readstr(fp, oneline);
|
|
sscanf(oneline, "Frame%i ", &frameRead);
|
|
if (frameRead == frame) {
|
|
charPosition = strchr(oneline, '=');
|
|
if (charPosition == NULL)
|
|
error("Could not find the subtitles", "");
|
|
replaceEOLwithEOF(charPosition+2, 255);
|
|
setSubtitles(charPosition+2);
|
|
break;
|
|
} else if (frameRead > frame)
|
|
break;
|
|
}
|
|
}
|
|
|
|
closeFile(fp);
|
|
}
|
|
|
|
|
|
int shutdownAnimation(int stopMusicOnLinked, int stopSoundeffectsOnLinked) {
|
|
char oneline[256];
|
|
FILE *fp;
|
|
|
|
setSubtitles("");
|
|
// drawAnimation();
|
|
swiWaitForVBlank();
|
|
updateOAMafterVBlank();
|
|
|
|
if (animationAni != NULL) {
|
|
gifHandlerDestroy(animationAni);
|
|
animationAni = NULL;
|
|
}
|
|
|
|
fp = openFile(animationFilename, FS_ANIMATIONS_FILE);
|
|
if (!fp) { // shouldn't occur, but ok.
|
|
if (!animationKeepMainFree)
|
|
REG_MASTER_BRIGHT_SUB = 0;
|
|
if (!animationKeepMusicFree)
|
|
stopMusic();
|
|
if (!animationKeepSoundFree)
|
|
stopSoundeffects();
|
|
animationLinked = 0;
|
|
return 1;
|
|
}
|
|
|
|
do {
|
|
readstr(fp, oneline);
|
|
} while (strncmp(oneline, "[GENERAL]", strlen("[GENERAL]")));
|
|
readstr(fp, oneline);
|
|
readstr(fp, oneline);
|
|
readstr(fp, oneline);
|
|
closeFile(fp);
|
|
replaceEOLwithEOF(oneline, 255);
|
|
if (oneline[0] != '[') { // a Linked animation was specified
|
|
if (!initAnimation(oneline + strlen("Linked="), animationKeepMainFree, animationKeepMusicFree, animationKeepSoundFree)) { // Linked animation was a success
|
|
if (stopMusicOnLinked)
|
|
stopMusic();
|
|
if (stopSoundeffectsOnLinked)
|
|
stopSoundeffects();
|
|
animationLinked = 1;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// if (!animationKeepMainFree)
|
|
// REG_MASTER_BRIGHT_SUB = 0; // setGameState() will take care of setting REG_MASTER_BRIGHT_SUB to 0
|
|
if (!animationKeepMusicFree)
|
|
stopMusic();
|
|
if (!animationKeepSoundFree)
|
|
stopSoundeffects();
|
|
animationLinked = 0;
|
|
return 1;
|
|
}
|
|
|
|
|
|
int doAnimationLogic() {
|
|
char oneline[256];
|
|
char *charPosition = NULL;
|
|
int i;
|
|
FILE *fp;
|
|
|
|
unsigned x1, y1, x2, y2;
|
|
char overlayName[128];
|
|
unsigned ui, uj;
|
|
|
|
uint16* animationBG0Base = (uint16*)(CHAR_BASE_BLOCK_SUB(ANIMATION_BG0_GRAPHICS_OFFSET));
|
|
|
|
if (animationInputDelay > 0)
|
|
animationInputDelay--;
|
|
|
|
if (amountOfScenes <= 0 ||
|
|
(animationInputDelay==0 &&
|
|
((!manualMode && !animationKeepMainFree && ((getKeysOnUp() & KEY_TOUCH) || (getKeysOnUp() & (KEY_A | KEY_START)))) ||
|
|
( manualMode && (((getKeysOnUp() & (KEY_A | KEY_RIGHT)) && (currentScene==amountOfScenes)) ||
|
|
((getKeysOnUp() & KEY_TOUCH) && (currentScene==amountOfScenes)) ||
|
|
((getKeysOnUp() & (KEY_B | KEY_LEFT)) && (currentScene==1)) ||
|
|
(getKeysOnUp() & KEY_START))) ||
|
|
(getGameState() == INGAME && ((getKeysOnUp() & KEY_TOUCH) || (getKeysOnUp() & (KEY_A | KEY_START))))))) {
|
|
setKeysToIgnoreOnceOnUp(0);
|
|
return shutdownAnimation(0, 1);
|
|
}
|
|
|
|
// guide keys
|
|
if (manualMode && ((currentSceneState == SCS_NORMAL) || (currentSceneState == SCS_FADEIN))) {
|
|
newScene=currentScene;
|
|
if ((getKeysOnUp() & KEY_A) || (getKeysOnUp() & KEY_RIGHT) || (getKeysOnUp() & KEY_TOUCH))
|
|
newScene = currentScene+1;
|
|
if ((getKeysOnUp() & KEY_B) || (getKeysOnUp() & KEY_LEFT))
|
|
newScene = currentScene-1;
|
|
if ((getKeysOnUp() & KEY_L) || (getKeysOnUp() & KEY_UP))
|
|
newScene = (currentScene>10) ? (currentScene-10) : 1;
|
|
if ((getKeysOnUp() & KEY_R) || (getKeysOnUp() & KEY_DOWN))
|
|
newScene = (currentScene<(amountOfScenes-10)) ? (currentScene+10) : amountOfScenes;
|
|
|
|
// if scene needs to be changed
|
|
if (newScene != currentScene) {
|
|
if (currentSceneState == SCS_FADEIN)
|
|
fadeTimer = (ANIMATION_FADE_TIME-fadeTimer) * (fadeOut != FT_NONE);
|
|
else
|
|
fadeTimer = ANIMATION_FADE_TIME * (fadeOut != FT_NONE);
|
|
animationTimer = -1;
|
|
currentSceneState = SCS_FADEOUT;
|
|
}
|
|
}
|
|
|
|
if (currentSceneState == SCS_FADEIN) {
|
|
fadeTimer--;
|
|
if (fadeTimer == 0)
|
|
currentSceneState = SCS_NORMAL;
|
|
}
|
|
|
|
if (animationTimer == -1 && currentSceneState == SCS_FADEOUT) {
|
|
fadeTimer--;
|
|
if (fadeTimer <= 0) {
|
|
|
|
if (manualMode)
|
|
currentScene=newScene;
|
|
else
|
|
currentScene++;
|
|
|
|
currentSceneState = SCS_FADEIN;
|
|
fadeTimer = ANIMATION_FADE_TIME;
|
|
|
|
if (currentScene > amountOfScenes) {
|
|
setKeysToIgnoreOnceOnUp(0);
|
|
return shutdownAnimation(0, 0);
|
|
}
|
|
|
|
fp = openFile(animationFilename, FS_ANIMATIONS_FILE);
|
|
for (i=0; i<currentScene; i++) {
|
|
do {
|
|
readstr(fp, oneline);
|
|
} while (strncmp(oneline, "[SCENE", strlen("[SCENE")));
|
|
}
|
|
readstr(fp, oneline);
|
|
replaceEOLwithEOF(oneline, 255);
|
|
charPosition = strchr(oneline, '=');
|
|
|
|
if (charPosition == NULL)
|
|
error("Could not find the name of the\nnext scene", "");
|
|
|
|
animationAni = gifHandlerLoad(openFile(charPosition + 2, FS_ANIMATIONS_GRAPHICS), animationAni);
|
|
if (animationAni == NULL)
|
|
error("Could not start up animation of", charPosition + 2);
|
|
|
|
readstr(fp, oneline);
|
|
if (oneline[0] != 'O') {
|
|
animationOverlayTiles = 0;
|
|
REG_DISPCNT_SUB &= (~DISPLAY_BG0_ACTIVE);
|
|
REG_BLDCNT_SUB = BLEND_NONE;
|
|
} else {
|
|
replaceEOLwithEOF(oneline, 255);
|
|
charPosition = strchr(oneline, '=');
|
|
if (charPosition == NULL)
|
|
error("Could not find the settings of the overlay", "");
|
|
if (sscanf(charPosition, "= %u,%u,%u,%u,%s", &x1, &y1, &x2, &y2, overlayName) < 5 ||
|
|
x2 < x1 || y2 < y1 || x2 > SCREEN_WIDTH || y2 > SCREEN_HEIGHT)
|
|
error("Could not use settings of the overlay", charPosition+2);
|
|
|
|
for (i=0; i<(8*8)/2; i++)
|
|
animationBG0Base[i] = 0;
|
|
|
|
animationOverlayTiles = copyFile(animationOverlayGraphics, overlayName, FS_ANIMATIONS_OVERLAY_GRAPHICS);
|
|
setAnimationOverlayTile(0);
|
|
// unfortunately it has to share palette with the GIF playing
|
|
|
|
animationOverlayTimer = 0;
|
|
animationOverlayTiles /= (16*16);
|
|
if (animationOverlayTiles > MAX_ANIMATION_OVERLAY_TILES)
|
|
errorSI("Animation overlay tiles limit was surpassed. Limit is:", MAX_ANIMATION_OVERLAY_TILES);
|
|
|
|
x1 /= 16;
|
|
x2 /= 16;
|
|
y1 /= 16;
|
|
y2 /= 16;
|
|
|
|
for (ui=0; ui<y1; ui++) { // blank out the first unwanted lines
|
|
for (uj=0; uj<2*(SCREEN_WIDTH/8); uj++)
|
|
mapSubBG0[ui*(2*(SCREEN_WIDTH/8)) + uj] = 0;
|
|
}
|
|
|
|
for (; ui<y2; ui++) { // fill in the overlay lines
|
|
for (uj=0; uj<x1; uj++) { // blank out the first unwanted columns
|
|
mapSubBG0[ui*(2*(SCREEN_WIDTH/8)) + 2*uj] = 0;
|
|
mapSubBG0[ui*(2*(SCREEN_WIDTH/8)) + 2*uj + 1] = 0;
|
|
mapSubBG0[ui*(2*(SCREEN_WIDTH/8)) + (SCREEN_WIDTH/8) + 2*uj] = 0;
|
|
mapSubBG0[ui*(2*(SCREEN_WIDTH/8)) + (SCREEN_WIDTH/8) + 2*uj + 1] = 0;
|
|
}
|
|
for (; uj<x2; uj++) { // fill in the overlay columns
|
|
mapSubBG0[ui*(2*(SCREEN_WIDTH/8)) + 2*uj] = 1;
|
|
mapSubBG0[ui*(2*(SCREEN_WIDTH/8)) + 2*uj + 1] = 2;
|
|
mapSubBG0[ui*(2*(SCREEN_WIDTH/8)) + (SCREEN_WIDTH/8) + 2*uj] = 3;
|
|
mapSubBG0[ui*(2*(SCREEN_WIDTH/8)) + (SCREEN_WIDTH/8) + 2*uj + 1] = 4;
|
|
}
|
|
for (; uj<(SCREEN_WIDTH / 16); uj++) { // blank out the last unwanted columns
|
|
mapSubBG0[ui*(2*(SCREEN_WIDTH/8)) + 2*uj] = 0;
|
|
mapSubBG0[ui*(2*(SCREEN_WIDTH/8)) + 2*uj + 1] = 0;
|
|
mapSubBG0[ui*(2*(SCREEN_WIDTH/8)) + (SCREEN_WIDTH/8) + 2*uj] = 0;
|
|
mapSubBG0[ui*(2*(SCREEN_WIDTH/8)) + (SCREEN_WIDTH/8) + 2*uj + 1] = 0;
|
|
}
|
|
}
|
|
|
|
for (; ui<(SCREEN_HEIGHT/16); ui++) { // blank out the last unwanted lines
|
|
for (uj=0; uj<2*(SCREEN_WIDTH/8); uj++)
|
|
mapSubBG0[ui*(2*(SCREEN_WIDTH/8)) + uj] = 0;
|
|
}
|
|
|
|
REG_DISPCNT_SUB |= DISPLAY_BG0_ACTIVE;
|
|
REG_BLDCNT_SUB = BLEND_ALPHA | BLEND_SRC_BG0 | BLEND_DST_BG3;
|
|
|
|
readstr(fp, oneline);
|
|
}
|
|
fadeIn = getFadeType(oneline);
|
|
readstr(fp, oneline);
|
|
fadeOut = getFadeType(oneline);
|
|
readstr(fp, oneline);
|
|
charPosition = strchr(oneline, '=');
|
|
if (charPosition == NULL)
|
|
error("Could not find playback speed\nof the next scene\n", "");
|
|
if (sscanf(charPosition, "= %f", ¤tScenePlaybackSpeed) < 1)
|
|
currentScenePlaybackSpeed = 1.0f;
|
|
|
|
closeFile(fp);
|
|
|
|
sceneFirstFrame = 1;
|
|
|
|
if (fadeIn == FT_NONE) {
|
|
currentSceneState = SCS_NORMAL;
|
|
REG_MASTER_BRIGHT_SUB = 0;
|
|
} else
|
|
REG_MASTER_BRIGHT_SUB = 16 | (fadeIn<<14);
|
|
|
|
doAnimationFrameSoundeffectAndSubtitles(animationAni->frmCount);
|
|
}
|
|
}
|
|
|
|
if (!manualMode) { // no animations in 'Manual' mode
|
|
if (currentSceneState == SCS_NORMAL) {
|
|
animationTimer++;
|
|
|
|
if (animationAni->gifTiming == 0) // if a still frame is found, make it last 100 ms
|
|
animationAni->gifTiming = (int) (((float) 1000) / currentScenePlaybackSpeed);
|
|
|
|
if (animationTimer >= (int) (((float) (animationAni->gifTiming / 15)) / currentScenePlaybackSpeed)) {
|
|
memset(animationAni->gifFrame, 0, animationAni->dimX * animationAni->dimY); // this ensures gifFrame will only have a "diff" stored instead of the exact frame
|
|
i = animationAni->frmCount;
|
|
if (i < gifHandlerLoadNextFrame(animationAni)) {
|
|
animationTimer = 0;
|
|
doAnimationFrameSoundeffectAndSubtitles(animationAni->frmCount);
|
|
} else {
|
|
animationTimer = -1;
|
|
currentSceneState = SCS_FADEOUT;
|
|
fadeTimer = ANIMATION_FADE_TIME * (fadeOut != FT_NONE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void loadAnimationGraphics(enum GameState oldState) {
|
|
char filename[256];
|
|
|
|
loadSubtitlesGraphics();
|
|
|
|
if (animationKeepMainFree)
|
|
return;
|
|
|
|
strcpy(filename, "animation_");
|
|
|
|
if (oldState <= MENU_MAIN)
|
|
strcat(filename, "intro");
|
|
else
|
|
strcat(filename, factionInfo[getFaction(FRIENDLY)].name);
|
|
|
|
copyFileVRAM(BG_PALETTE, filename, FS_PALETTES);
|
|
copyFileVRAM(BG_GFX, filename, FS_MENU_GRAPHICS);
|
|
}
|
|
|
|
int initAnimation(char *filename, int keepMainFree, int keepMusicFree, int keepSoundFree) {
|
|
char manualModeChar;
|
|
char oneline[256];
|
|
FILE *fp;
|
|
int i;
|
|
uint16* animationBG3Base;
|
|
|
|
setKeysToIgnoreOnceOnUp(getKeysDown() | getKeysOnUp()); // all but the buttons which have been up for more than one frame already
|
|
|
|
initSpritesUsedInfoScreen();
|
|
swiWaitForVBlank();
|
|
updateOAMafterVBlank();
|
|
|
|
setSubtitles("");
|
|
|
|
strcpy(animationFilename, filename);
|
|
animationKeepMainFree = keepMainFree;
|
|
animationKeepMusicFree = keepMusicFree;
|
|
animationKeepSoundFree = keepSoundFree;
|
|
|
|
amountOfScenes = 0;
|
|
currentScene = 0;
|
|
newScene = 1;
|
|
animationTimer = -1; // load up a next scene animation
|
|
animationInputDelay = (getIngameBriefingState() == IBS_ACTIVE) ? (2*FPS) : 0; // only ingame briefing has input delayed
|
|
|
|
if (animationAni != NULL) {
|
|
gifHandlerDestroy(animationAni);
|
|
animationAni = NULL;
|
|
}
|
|
|
|
fadeIn = FT_NONE;
|
|
fadeOut = FT_NONE;
|
|
currentSceneState = SCS_FADEOUT;
|
|
fadeTimer = 0;
|
|
sceneFirstFrame = 0;
|
|
|
|
fp = openFile(animationFilename, FS_ANIMATIONS_FILE);
|
|
if (!fp)
|
|
return 1;
|
|
do {
|
|
readstr(fp, oneline);
|
|
} while (strncmp(oneline, "[GENERAL]", strlen("[GENERAL]")));
|
|
readstr(fp, oneline);
|
|
sscanf(oneline, "Amount-Of-Scenes = %i", &amountOfScenes);
|
|
if (amountOfScenes <= 0) {
|
|
closeFile(fp);
|
|
return 1;
|
|
}
|
|
readstr(fp, oneline);
|
|
|
|
manualMode=0;
|
|
if (!strncmp(oneline, "Manual = ", strlen("Manual = "))) {
|
|
manualModeChar = oneline[strlen("Manual = ")];
|
|
manualMode = (manualModeChar=='Y') || (manualModeChar=='y');
|
|
readstr(fp, oneline); // read another line because this was present
|
|
}
|
|
|
|
closeFile(fp);
|
|
replaceEOLwithEOF(oneline, 255);
|
|
if (!animationKeepMusicFree) {
|
|
if (strncmp(oneline + strlen("Music = "), "None", strlen("None"))) // !None
|
|
playMiscMusic(oneline + strlen("Music = "), MUSIC_LOOP);
|
|
else if (!animationLinked)
|
|
stopMusic();
|
|
}
|
|
|
|
if (animationLinked)
|
|
return 0;
|
|
|
|
animationBG3Base = (uint16*)(CHAR_BASE_BLOCK_SUB(ANIMATION_BG3_GRAPHICS_OFFSET));
|
|
|
|
BG_PALETTE_SUB[0] = 0; // set black as background
|
|
for (i=0; i<256*256/2; i++)
|
|
animationBG3Base[i] = 0;
|
|
|
|
REG_DISPCNT_SUB = ( MODE_3_2D | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | DISPLAY_SPR_1D_SIZE_64 );
|
|
REG_BG3CNT_SUB = BG_PRIORITY_3 | BG_BMP_BASE(ANIMATION_BG3_GRAPHICS_OFFSET) | BG_BMP8_256x256;
|
|
REG_BG3PA_SUB = 1<<8; // scaling of 1
|
|
REG_BG3PB_SUB = 0;
|
|
REG_BG3PC_SUB = 0;
|
|
REG_BG3PD_SUB = 1<<8; // scaling of 1
|
|
REG_BG3X_SUB = 0;
|
|
REG_BG3Y_SUB = 0;
|
|
REG_BG3HOFS_SUB = 0;
|
|
REG_BG3VOFS_SUB = 0;
|
|
REG_BG0CNT_SUB = BG_PRIORITY_0 | BG_TILE_BASE(ANIMATION_BG0_GRAPHICS_OFFSET) | BG_COLOR_256 | BG_MAP_BASE(31) | BG_32x32;
|
|
REG_BG0HOFS_SUB = 0;
|
|
REG_BG0VOFS_SUB = 0;
|
|
|
|
if (animationKeepMainFree)
|
|
return 0;
|
|
|
|
REG_DISPCNT = ( MODE_3_2D | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D | DISPLAY_SPR_1D_SIZE_64 );
|
|
REG_BG3CNT = BG_BMP8_256x256;
|
|
REG_BG3PA = 1<<8; // scaling of 1
|
|
REG_BG3PB = 0;
|
|
REG_BG3PC = 0;
|
|
REG_BG3PD = 1<<8; // scaling of 1
|
|
REG_BG3X = 0;
|
|
REG_BG3Y = 0;
|
|
REG_BG3HOFS = 0;
|
|
REG_BG3VOFS = 0;
|
|
|
|
return 0;
|
|
}
|