Animation system overhaul part 1. This allows for an unlimited number of .anm/.ivf files to be defined via duke3d.def and played back at any time with the new CON commands. Syntax is currently as follows, but may change:

cutscene "somefile.anm" { delay 10 } // defines somefile.anm with a delay of 10 120Hz tics between frames. a more typical framerate method may come later, but this is how the originals worked.

Once defined, they can be played through CON with the new playback command, also called "cutscene". It works like this:

definequote 12345 somefile.anm
define ANIM_SOMEFILE 12345

...

cutscene ANIM_SOMEFILE // halts game execution and immediately plays cutscene, resuming execution when finished

...

Sounds can be played during animations (and tiles can be overlaid, etc) like this:

onevent EVENT_CUTSCENE
    ifcutscene ANIM_SOMEFILE
    {
        ifvare RETURN 12 // frame 12
            sound FLY_BY
        rotatesprite ...
    }
endevent

The value of the RETURN var at the end of EVENT_CUTSCENE determines the next frame to play. This can be used for looping, etc. Attempting to play animations backwards outright is not advised as animations only seek in one direction (so rewinding requires running it through from frame 0 again). This is will WIP and hasn't been heavily tested at all, so please try it out.

git-svn-id: https://svn.eduke32.com/eduke32@4987 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
terminx 2015-02-11 05:22:07 +00:00
parent cc4ddf9ce7
commit 50c30ab790
16 changed files with 530 additions and 356 deletions

View file

@ -220,7 +220,7 @@ MAPSTER32_TARGET:=$(MAPSTER32)$(EXESUFFIX)
COMMON_OBJS=rev
COMMON_EDITOR_OBJS=m32common m32def m32exec m32vars mathutil rev
DUKE3D_OBJS=game actors anim common config demo gamedef gameexec gamevars global input menus namesdyn net player premap savegame sector rts osdfuncs osdcmds grpscan sounds soundsdyn $(MACT_OBJ)
DUKE3D_OBJS=game global actors gamedef gameexec gamevars player premap sector anim animsounds common config demo input menus namesdyn net savegame rts osdfuncs osdcmds grpscan sounds soundsdyn $(MACT_OBJ)
DUKE3D_EDITOR_OBJS=astub common grpscan sounds_mapster32
ifneq ($(USE_LIBVPX),0)

View file

@ -38,7 +38,8 @@ game_defs_dep=$(DUKE3D_SRC)/lunatic/defs.ilua
$(DUKE3D_OBJ)/game.$o: $(DUKE3D_SRC)/game.c $(game_defs_dep) $(DUKE3D_SRC)/jmact/scriplib.h $(duke3d_h) $(DUKE3D_SRC)/input.h $(DUKE3D_INC)/osdfuncs.h $(DUKE3D_INC)/osdcmds.h $(DUKE3D_INC)/grpscan.h $(DUKE3D_INC)/demo.h $(ENGINE_INC)/hightile.h
$(DUKE3D_OBJ)/actors.$o: $(DUKE3D_SRC)/actors.c $(duke3d_h)
$(DUKE3D_OBJ)/anim.$o: $(DUKE3D_SRC)/anim.c $(duke3d_h) $(DUKE3D_SRC)/input.h $(DUKE3D_SRC)/jmact/animlib.h $(DUKE3D_SRC)/animvpx.h
$(DUKE3D_OBJ)/anim.$o: $(DUKE3D_SRC)/anim.c $(duke3d_h) $(DUKE3D_SRC)/input.h $(DUKE3D_SRC)/jmact/animlib.h $(DUKE3D_SRC)/animvpx.h $(DUKE3D_SRC)/animsounds.h
$(DUKE3D_OBJ)/animsounds.$o: $(DUKE3D_SRC)/animsounds.c $(DUKE3D_SRC)/animsounds.h
$(DUKE3D_OBJ)/demo.$o: $(DUKE3D_SRC)/demo.c $(duke3d_h) $(DUKE3D_SRC)/input.h
$(DUKE3D_OBJ)/gamedef.$o: $(DUKE3D_SRC)/gamedef.c $(duke3d_h) $(gamedef_h) $(DUKE3D_SRC)/savegame.h
$(DUKE3D_OBJ)/gameexec.$o: $(DUKE3D_SRC)/gameexec.c $(DUKE3D_SRC)/gamestructures.c $(duke3d_h) $(gamedef_h)

View file

@ -190,6 +190,7 @@ DUKE3D_OBJS=$(DUKE3D_OBJ)\game.$o \
$(DUKE3D_OBJ)\actors.$o \
$(DUKE3D_OBJ)\actors_inline.$o \
$(DUKE3D_OBJ)\anim.$o \
$(DUKE3D_OBJ)\animsounds.$o \
$(DUKE3D_OBJ)\animvpx.$o \
$(DUKE3D_OBJ)\common.$o \
$(DUKE3D_OBJ)\demo.$o \

View file

@ -86,6 +86,7 @@ enum scripttoken_t
T_TILEFROMTEXTURE, T_XOFFSET, T_YOFFSET, T_TEXHITSCAN, T_NOFULLBRIGHT,
T_INCLUDEDEFAULT,
T_ANIMSOUNDS,
T_CUTSCENE,
T_NOFLOORPALRANGE,
T_TEXHITSCANRANGE,
T_NOFULLBRIGHTRANGE,
@ -250,6 +251,7 @@ static int32_t defsparser(scriptfile *script)
{ "music", T_MUSIC },
{ "sound", T_SOUND },
{ "animsounds", T_ANIMSOUNDS }, // dummy
{ "cutscene", T_CUTSCENE },
{ "nofloorpalrange", T_NOFLOORPALRANGE },
{ "texhitscanrange", T_TEXHITSCANRANGE },
{ "nofullbrightrange", T_NOFULLBRIGHTRANGE },
@ -2073,6 +2075,7 @@ static int32_t defsparser(scriptfile *script)
}
break;
case T_CUTSCENE:
case T_ANIMSOUNDS:
{
char *dummy;

View file

@ -293,9 +293,11 @@
<ClInclude Include="source\android.h" />
<ClInclude Include="source\android\in_android.h" />
<ClInclude Include="source\anim.h" />
<ClInclude Include="source\animsounds.h" />
<ClInclude Include="source\animvpx.h" />
<ClInclude Include="source\common_game.h" />
<ClInclude Include="source\demo.h" />
<ClInclude Include="source\events_defs.h" />
<ClInclude Include="source\game.h" />
<ClInclude Include="source\game_inline.h" />
<ClInclude Include="source\gameexec.h" />
@ -407,6 +409,7 @@
<ClCompile Include="source\android\android-jni.cpp" />
<ClCompile Include="source\android\in_android.c" />
<ClCompile Include="source\anim.c" />
<ClCompile Include="source\animsounds.c" />
<ClCompile Include="source\animvpx.c" />
<ClCompile Include="source\astub.c" />
<ClCompile Include="source\config.c" />

View file

@ -363,6 +363,9 @@
<ClInclude Include="source\demo.h">
<Filter>eduke32\headers</Filter>
</ClInclude>
<ClInclude Include="source\events_defs.h">
<Filter>eduke32\headers</Filter>
</ClInclude>
<ClInclude Include="source\quotes.h">
<Filter>eduke32\headers</Filter>
</ClInclude>
@ -453,6 +456,9 @@
<ClInclude Include="build\include\buildtypes.h">
<Filter>build\headers</Filter>
</ClInclude>
<ClInclude Include="source\animsounds.h">
<Filter>eduke32\headers</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="build\src\a-c.c">
@ -785,6 +791,9 @@
<ClCompile Include="build\src\sdlayer12.c">
<Filter>build\source</Filter>
</ClCompile>
<ClCompile Include="source\animsounds.c">
<Filter>eduke32\source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="Makefile.msvc">

View file

@ -32,228 +32,77 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifdef USE_LIBVPX
# include "animvpx.h"
uint16_t anim_hi_numsounds[NUM_HARDCODED_ANIMS], *anim_hi_sounds[NUM_HARDCODED_ANIMS];
#endif
static void endanimsounds(int32_t fr)
#include "animsounds.h"
hashtable_t h_dukeanim = { 8, NULL };
dukeanim_t * g_animPtr;
dukeanim_t *G_FindAnim(const char *s)
{
switch (ud.volume_number)
{
case 0:
break;
case 1:
switch (fr)
{
case 1:
S_PlaySound(WIND_AMBIENCE);
break;
case 26:
S_PlaySound(ENDSEQVOL2SND1);
break;
case 36:
S_PlaySound(ENDSEQVOL2SND2);
break;
case 54:
S_PlaySound(THUD);
break;
case 62:
S_PlaySound(ENDSEQVOL2SND3);
break;
case 75:
S_PlaySound(ENDSEQVOL2SND4);
break;
case 81:
S_PlaySound(ENDSEQVOL2SND5);
break;
case 115:
S_PlaySound(ENDSEQVOL2SND6);
break;
case 124:
S_PlaySound(ENDSEQVOL2SND7);
break;
}
break;
case 2:
switch (fr)
{
case 1:
S_PlaySound(WIND_REPEAT);
break;
case 98:
S_PlaySound(DUKE_GRUNT);
break;
case 82+20:
S_PlaySound(THUD);
S_PlaySound(SQUISHED);
break;
case 104+20:
S_PlaySound(ENDSEQVOL3SND3);
break;
case 114+20:
S_PlaySound(ENDSEQVOL3SND2);
break;
case 158:
S_PlaySound(PIPEBOMB_EXPLODE);
break;
}
break;
}
intptr_t ptr = hash_findcase(&h_dukeanim, s);
return (dukeanim_t *)(ptr == -1 ? NULL : (dukeanim_t *)ptr);
}
static void logoanimsounds(int32_t fr)
dukeanim_t * G_DefineAnim(const char *fn, uint8_t fdelay, void (*sound_func)(int32_t))
{
switch (fr)
{
case 1:
S_PlaySound(FLY_BY);
break;
case 19:
S_PlaySound(PIPEBOMB_EXPLODE);
break;
}
dukeanim_t * anim = G_FindAnim(fn);
if (!anim)
anim = (dukeanim_t *)Xcalloc(1, sizeof(dukeanim_t));
hash_add(&h_dukeanim, fn, (intptr_t)anim, 0);
if (sound_func)
anim->sound_func = sound_func;
anim->framedelay = fdelay;
return anim;
}
static void intro4animsounds(int32_t fr)
void G_InitAnim(void)
{
switch (fr)
{
case 1:
S_PlaySound(INTRO4_B);
break;
case 12:
case 34:
S_PlaySound(SHORT_CIRCUIT);
break;
case 18:
S_PlaySound(INTRO4_5);
break;
}
hash_init(&h_dukeanim);
G_DefineAnim("logo.anm", 9, logoanimsounds);
G_DefineAnim("3dr.anm", 10, NULL);
G_DefineAnim("vol4e1.anm", 10, endanimvol41);
G_DefineAnim("vol4e2.anm", 14, endanimvol42);
G_DefineAnim("vol4e3.anm", 10, endanimvol43);
G_DefineAnim("vol41a.anm", 14, first4animsounds);
G_DefineAnim("vol42a.anm", 18, intro4animsounds);
G_DefineAnim("vol43a.anm", 10, intro42animsounds);
G_DefineAnim("duketeam.anm", 10, NULL);
G_DefineAnim("radlogo.anm", 10, NULL);
G_DefineAnim("cineov2.anm", 18, endanimsounds);
G_DefineAnim("cineov3.anm", 10, endanimsounds);
}
static void first4animsounds(int32_t fr)
int32_t G_PlayAnim(const char *fn)
{
switch (fr)
dukeanim_t *anim = G_FindAnim(fn);
if (!anim)
{
case 1:
S_PlaySound(INTRO4_1);
break;
case 12:
S_PlaySound(INTRO4_2);
break;
case 7:
S_PlaySound(INTRO4_3);
break;
case 26:
S_PlaySound(INTRO4_4);
break;
OSD_Printf("Animation %s is undefined!\n", fn);
return 0;
}
}
static void intro42animsounds(int32_t fr)
{
switch (fr)
{
case 10:
S_PlaySound(INTRO4_6);
break;
}
}
static void endanimvol41(int32_t fr)
{
switch (fr)
{
case 3:
S_PlaySound(DUKE_UNDERWATER);
break;
case 35:
S_PlaySound(VOL4ENDSND1);
break;
}
}
static void endanimvol42(int32_t fr)
{
switch (fr)
{
case 11:
S_PlaySound(DUKE_UNDERWATER);
break;
case 20:
S_PlaySound(VOL4ENDSND1);
break;
case 39:
S_PlaySound(VOL4ENDSND2);
break;
case 50:
FX_StopAllSounds();
break;
}
}
static void endanimvol43(int32_t fr)
{
switch (fr)
{
case 1:
S_PlaySound(BOSS4_DEADSPEECH);
break;
case 40:
S_PlaySound(VOL4ENDSND1);
S_PlaySound(DUKE_UNDERWATER);
break;
case 50:
S_PlaySound(BIGBANG);
break;
}
}
static uint8_t* animbuf[NUM_HARDCODED_ANIMS];
static char animlock[NUM_HARDCODED_ANIMS];
int32_t G_PlayAnim(const char *fn, char t)
{
int32_t i, length=0, numframes=0;
#ifdef USE_OPENGL
int32_t ogltexfiltermode=gltexfiltermode;
#endif
int32_t handle=-1;
int32_t frametime = 0;
int32_t running = 1;
// t parameter:
//
// 1: cineov2
// 2: cineov3
// 3: RADLOGO
// 4: DUKETEAM
// 5: logo
// 6: vol41a
// 7: vol42a
// 8: vol4e1
// 9: vol43a
// 10: vol4e2
// 11: vol4e3
// 12: 3drealms anim
int32_t framenum = 0, soundidx = 0; // custom anim sounds
int32_t running = 1, i;
I_ClearAllInput();
#ifdef USE_LIBVPX
while (getrendermode() >= REND_POLYMOST && glinfo.glsl) // if, really
{
char vpxfn[BMAX_PATH], *dot;
animvpx_ivf_header_t info;
animvpx_codec_ctx codec;
uint8_t *pic;
uint32_t msecsperframe, nextframetime;
int32_t animidx, framenum=0, soundidx=0, numtotalsounds=0; // custom anim sounds
char vpxfn[BMAX_PATH];
Bstrncpyz(vpxfn, fn, BMAX_PATH);
dot = Bstrrchr(vpxfn, '.');
if (!dot || (dot-vpxfn)+4 >= BMAX_PATH)
char *dot = Bstrrchr(vpxfn, '.');
if (!dot || (dot - vpxfn) + 4 >= BMAX_PATH)
break;
dot[1] = 'i';
@ -261,20 +110,24 @@ int32_t G_PlayAnim(const char *fn, char t)
dot[3] = 'f';
dot[4] = 0;
handle = kopen4loadfrommod(vpxfn, 0);
int32_t handle = kopen4loadfrommod(vpxfn, 0);
if (handle == -1)
break;
animvpx_ivf_header_t info;
i = animvpx_read_ivf_header(handle, &info);
if (i)
{
OSD_Printf("Failed reading IVF file: %s\n",
animvpx_read_ivf_header_errmsg[i]);
OSD_Printf("Failed reading IVF file: %s\n", animvpx_read_ivf_header_errmsg[i]);
kclose(handle);
return 0;
}
animvpx_setup_glstate();
animvpx_codec_ctx codec;
if (animvpx_init_codec(&info, handle, &codec))
{
OSD_Printf("Error initializing VPX codec.\n");
@ -282,24 +135,20 @@ int32_t G_PlayAnim(const char *fn, char t)
return 0;
}
animidx = t-1;
if ((unsigned)animidx < NUM_HARDCODED_ANIMS && anim_hi_sounds[animidx])
numtotalsounds = anim_hi_numsounds[animidx];
uint32_t msecsperframe = ((uint64_t)info.fpsdenom * 1000) / info.fpsnumer;
uint32_t nextframetime = getticks();
uint8_t *pic;
msecsperframe = ((uint64_t)info.fpsdenom*1000)/info.fpsnumer;
// OSD_Printf("msecs per frame: %d\n", msecsperframe);
// OSD_Printf("msecs per frame: %d\n", msecsperframe);
nextframetime = getticks();
while (running)
do
{
nextframetime += msecsperframe;
i = animvpx_nextpic(&codec, &pic);
if (i)
{
OSD_Printf("Failed getting next pic: %s\n",
animvpx_nextpic_errmsg[i]);
OSD_Printf("Failed getting next pic: %s\n", animvpx_nextpic_errmsg[i]);
if (codec.errmsg)
{
OSD_Printf(" %s\n", codec.errmsg);
@ -316,9 +165,9 @@ int32_t G_PlayAnim(const char *fn, char t)
// after rendering the frame but before displaying: maybe play sound...
framenum++;
while (soundidx < numtotalsounds && anim_hi_sounds[animidx][2*soundidx] == framenum)
while (soundidx < anim->numsounds && anim->sounds[soundidx << 1] == framenum)
{
S_PlaySound(anim_hi_sounds[animidx][2*soundidx+1]);
S_PlaySound(anim->sounds[(soundidx << 1) + 1]);
soundidx++;
}
@ -327,7 +176,7 @@ int32_t G_PlayAnim(const char *fn, char t)
palfadedelta = 0;
showframe(0);
// I_ClearAllInput();
// I_ClearAllInput();
do
{
@ -338,9 +187,8 @@ int32_t G_PlayAnim(const char *fn, char t)
running = 0;
break;
}
}
while (getticks() < nextframetime);
}
} while (getticks() < nextframetime);
} while (running);
animvpx_print_stats(&codec);
@ -353,32 +201,39 @@ int32_t G_PlayAnim(const char *fn, char t)
return !running; // done with playing VP8!
}
#endif
// ANM playback --- v v v ---
// ANM playback --- v v v ---
#ifdef USE_OPENGL
int32_t ogltexfiltermode = gltexfiltermode;
#endif
int32_t handle = kopen4load(fn, 0);
handle = kopen4load(fn, 0);
if (handle == -1)
return 0;
length = kfilelength(handle);
int32_t length = kfilelength(handle);
if (length == 0)
{
OSD_Printf("Warning: skipping playback of empty ANM file \"%s\".\n", fn);
goto end_anim;
}
walock[TILE_ANIM] = 219+t;
animlock[t-1] = 1;
walock[TILE_ANIM] = 219;
anim->animlock = 1;
if (!animbuf[t-1])
allocache((intptr_t *)&animbuf[t-1], length+1, &animlock[t-1]);
if (!anim->animbuf)
allocache((intptr_t *)&anim->animbuf, length + 1, &anim->animlock);
tilesiz[TILE_ANIM].x = 200;
tilesiz[TILE_ANIM].y = 320;
kread(handle, animbuf[t-1], length);
kread(handle, anim->animbuf, length);
kclose(handle);
if (ANIM_LoadAnim(animbuf[t-1], length) < 0 || (numframes = ANIM_NumFrames()) <= 0)
int32_t numframes;
if (ANIM_LoadAnim(anim->animbuf, length) < 0 || (numframes = ANIM_NumFrames()) <= 0)
{
// XXX: ANM_LoadAnim() still checks less than the bare minimum,
// e.g. ANM file could still be too small and not contain any frames.
@ -388,9 +243,9 @@ int32_t G_PlayAnim(const char *fn, char t)
basepaltable[ANIMPAL] = ANIM_GetPalette();
//setpalette(0L,256L,tempbuf);
//setbrightness(ud.brightness>>2,tempbuf,2);
P_SetGamePalette(g_player[myconnectindex].ps, ANIMPAL, 8+2);
// setpalette(0L,256L,tempbuf);
// setbrightness(ud.brightness>>2,tempbuf,2);
P_SetGamePalette(g_player[myconnectindex].ps, ANIMPAL, 8 + 2);
#ifdef USE_OPENGL
gltexfiltermode = 0;
@ -400,6 +255,7 @@ int32_t G_PlayAnim(const char *fn, char t)
ototalclock = totalclock + 10;
i = 1;
int32_t frametime; frametime = 0;
do
{
@ -411,11 +267,11 @@ int32_t G_PlayAnim(const char *fn, char t)
G_HandleAsync();
if (totalclock < ototalclock-1)
if (totalclock < ototalclock - 1)
continue;
waloff[TILE_ANIM] = (intptr_t) ANIM_DrawFrame(i);
invalidatetile(TILE_ANIM, 0, 1<<4); // JBF 20031228
waloff[TILE_ANIM] = (intptr_t)ANIM_DrawFrame(i);
invalidatetile(TILE_ANIM, 0, 1 << 4); // JBF 20031228
if (I_CheckAllInput())
{
@ -433,30 +289,28 @@ int32_t G_PlayAnim(const char *fn, char t)
clearallviews(0);
rotatesprite_fs(0<<16, 0<<16, 65536L, 512, TILE_ANIM, 0, 0, 2+4+8+16+64+(ud.bgstretch ? 1024 : 0));
rotatesprite_fs(0 << 16, 0 << 16, 65536L, 512, TILE_ANIM, 0, 0, 2 + 4 + 8 + 16 + 64 + BGSTRETCH);
g_animPtr = anim;
i = VM_OnEventWithReturn(EVENT_CUTSCENE, -1, myconnectindex, i);
g_animPtr = NULL;
nextpage();
I_ClearAllInput();
if (t == 10) ototalclock += 14;
else if (t == 9) ototalclock += 10;
else if (t == 7) ototalclock += 18;
else if (t == 6) ototalclock += 14;
else if (t == 5) ototalclock += 9;
else if (ud.volume_number == 3) ototalclock += 10;
else if (ud.volume_number == 2) ototalclock += 10;
else if (ud.volume_number == 1) ototalclock += 18;
else ototalclock += 10;
ototalclock += anim->framedelay;
if (t == 8) endanimvol41(i);
else if (t == 10) endanimvol42(i);
else if (t == 11) endanimvol43(i);
else if (t == 9) intro42animsounds(i);
else if (t == 7) intro4animsounds(i);
else if (t == 6) first4animsounds(i);
else if (t == 5) logoanimsounds(i);
else if (t < 4) endanimsounds(i);
i++;
if (!anim->numsounds && anim->sound_func)
anim->sound_func(i);
framenum = i++;
while (soundidx < anim->numsounds && anim->sounds[soundidx << 1] == framenum)
{
S_PlaySound(anim->sounds[(soundidx << 1) + 1]);
soundidx++;
}
} while (i < numframes);
end_anim_restore_gl:
@ -468,7 +322,7 @@ end_anim:
I_ClearAllInput();
ANIM_FreeAnim();
walock[TILE_ANIM] = 1;
animlock[t-1] = 0;
anim->animlock = 0;
return !running;
}

View file

@ -25,19 +25,21 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define NUM_HARDCODED_ANIMS 12
# ifdef USE_LIBVPX
extern uint16_t anim_hi_numsounds[NUM_HARDCODED_ANIMS], *anim_hi_sounds[NUM_HARDCODED_ANIMS];
# endif
typedef struct
{
uint8_t* animbuf;
void (*sound_func)(int32_t);
uint16_t *sounds;
int16_t numsounds;
uint8_t framedelay;
char animlock;
} dukeanim_t;
extern dukeanim_t * g_animPtr;
extern hashtable_t h_dukeanim;
extern dukeanim_t * G_FindAnim(const char *s);
extern dukeanim_t * G_DefineAnim(const char *fn, uint8_t framerate, void (*sound_func)(int32_t));
int32_t G_PlayAnim(const char *fn);
void G_InitAnim(void);
int32_t G_PlayAnim(const char *fn,char t);
/*
void endanimvol43(int32_t fr);
void endanimvol42(int32_t fr);
void endanimvol41(int32_t fr);
void intro42animsounds(int32_t fr);
void first4animsounds(int32_t fr);
void intro4animsounds(int32_t fr);
void logoanimsounds(int32_t fr);
void endanimsounds(int32_t fr);
*/
#endif

View file

@ -0,0 +1,197 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2015 EDuke32 developers and contributors
This file is part of EDuke32.
EDuke32 is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "duke3d.h"
#include "animsounds.h"
void endanimsounds(int32_t fr)
{
switch (ud.volume_number)
{
case 0:
break;
case 1:
switch (fr)
{
case 1:
S_PlaySound(WIND_AMBIENCE);
break;
case 26:
S_PlaySound(ENDSEQVOL2SND1);
break;
case 36:
S_PlaySound(ENDSEQVOL2SND2);
break;
case 54:
S_PlaySound(THUD);
break;
case 62:
S_PlaySound(ENDSEQVOL2SND3);
break;
case 75:
S_PlaySound(ENDSEQVOL2SND4);
break;
case 81:
S_PlaySound(ENDSEQVOL2SND5);
break;
case 115:
S_PlaySound(ENDSEQVOL2SND6);
break;
case 124:
S_PlaySound(ENDSEQVOL2SND7);
break;
}
break;
case 2:
switch (fr)
{
case 1:
S_PlaySound(WIND_REPEAT);
break;
case 98:
S_PlaySound(DUKE_GRUNT);
break;
case 82+20:
S_PlaySound(THUD);
S_PlaySound(SQUISHED);
break;
case 104+20:
S_PlaySound(ENDSEQVOL3SND3);
break;
case 114+20:
S_PlaySound(ENDSEQVOL3SND2);
break;
case 158:
S_PlaySound(PIPEBOMB_EXPLODE);
break;
}
break;
}
}
void logoanimsounds(int32_t fr)
{
switch (fr)
{
case 1:
S_PlaySound(FLY_BY);
break;
case 19:
S_PlaySound(PIPEBOMB_EXPLODE);
break;
}
}
void intro4animsounds(int32_t fr)
{
switch (fr)
{
case 1:
S_PlaySound(INTRO4_B);
break;
case 12:
case 34:
S_PlaySound(SHORT_CIRCUIT);
break;
case 18:
S_PlaySound(INTRO4_5);
break;
}
}
void first4animsounds(int32_t fr)
{
switch (fr)
{
case 1:
S_PlaySound(INTRO4_1);
break;
case 12:
S_PlaySound(INTRO4_2);
break;
case 7:
S_PlaySound(INTRO4_3);
break;
case 26:
S_PlaySound(INTRO4_4);
break;
}
}
void intro42animsounds(int32_t fr)
{
switch (fr)
{
case 10:
S_PlaySound(INTRO4_6);
break;
}
}
void endanimvol41(int32_t fr)
{
switch (fr)
{
case 3:
S_PlaySound(DUKE_UNDERWATER);
break;
case 35:
S_PlaySound(VOL4ENDSND1);
break;
}
}
void endanimvol42(int32_t fr)
{
switch (fr)
{
case 11:
S_PlaySound(DUKE_UNDERWATER);
break;
case 20:
S_PlaySound(VOL4ENDSND1);
break;
case 39:
S_PlaySound(VOL4ENDSND2);
break;
case 50:
FX_StopAllSounds();
break;
}
}
void endanimvol43(int32_t fr)
{
switch (fr)
{
case 1:
S_PlaySound(BOSS4_DEADSPEECH);
break;
case 40:
S_PlaySound(VOL4ENDSND1);
S_PlaySound(DUKE_UNDERWATER);
break;
case 50:
S_PlaySound(BIGBANG);
break;
}
}

View file

@ -0,0 +1,33 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2015 EDuke32 developers and contributors
This file is part of EDuke32.
EDuke32 is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#ifndef animsounds_h__
#define animsounds_h__
void endanimsounds(int32_t fr);
void logoanimsounds(int32_t fr);
void intro4animsounds(int32_t fr);
void endanimvol43(int32_t fr);
void endanimvol42(int32_t fr);
void endanimvol41(int32_t fr);
void intro42animsounds(int32_t fr);
void first4animsounds(int32_t fr);
#endif // animsounds_h__

View file

@ -104,6 +104,7 @@ enum GameEvent_t {
EVENT_ACTIVATECHEAT,
EVENT_DISPLAYINACTIVEMENU,
EVENT_DISPLAYINACTIVEMENUREST,
EVENT_CUTSCENE,
#ifdef LUNATIC
EVENT_ANIMATEALLSPRITES,
#endif

View file

@ -222,9 +222,11 @@ enum gametokens
T_MUSIC,
T_SOUND,
T_FILE,
T_CUTSCENE,
T_ANIMSOUNDS,
T_NOFLOORPALRANGE,
T_ID
T_ID,
T_DELAY
};
@ -3767,13 +3769,13 @@ void G_DisplayRest(int32_t smoothratio)
{
int32_t a = VM_OnEvent(EVENT_DISPLAYCROSSHAIR, g_player[screenpeek].ps->i, screenpeek);
if (a == 0 || a > 1)
if ((unsigned)a < MAXTILES)
{
vec2_t crosshairpos = { 160<<16, 100<<16 };
if (a == 0)
a = CROSSHAIR;
vec2_t crosshairpos = { 160<<16, 100<<16 };
rotatesprite_win(crosshairpos.x-(g_player[myconnectindex].ps->look_ang<<15),crosshairpos.y,scale(65536,ud.crosshairscale,100),
0,a,0,CROSSHAIR_PAL,2+1);
@ -3809,13 +3811,8 @@ void G_DisplayRest(int32_t smoothratio)
#endif
#ifdef USE_OPENGL
{
extern int32_t mdpause;
mdpause = 0;
if (ud.pause_on || (ud.recstat==2 && (g_demo_paused && g_demo_goalCnt==0)) || (g_player[myconnectindex].ps->gm&MODE_MENU && numplayers < 2))
mdpause = 1;
}
extern int32_t mdpause;
mdpause = (ud.pause_on || (ud.recstat==2 && (g_demo_paused && g_demo_goalCnt==0)) || (g_player[myconnectindex].ps->gm&MODE_MENU && numplayers < 2));
#endif
G_PrintFPS();
@ -3823,7 +3820,7 @@ void G_DisplayRest(int32_t smoothratio)
// JBF 20040124: display level stats in screen corner
if ((ud.overhead_on != 2 && ud.levelstats) && (g_player[myconnectindex].ps->gm&MODE_MENU) == 0)
{
const DukePlayer_t *myps = g_player[myconnectindex].ps;
DukePlayer_t const * const myps = g_player[myconnectindex].ps;
if (ud.screen_size == 4)
{
@ -9366,9 +9363,8 @@ static int32_t parsedefinitions_game(scriptfile *script, int32_t preload)
{ "noautoload", T_NOAUTOLOAD },
{ "music", T_MUSIC },
{ "sound", T_SOUND },
#ifdef USE_LIBVPX
{ "cutscene", T_CUTSCENE },
{ "animsounds", T_ANIMSOUNDS },
#endif
};
static const tokenlist sound_musictokens[] =
@ -9377,6 +9373,11 @@ static int32_t parsedefinitions_game(scriptfile *script, int32_t preload)
{ "file", T_FILE },
};
static const tokenlist animtokens [] =
{
{ "delay", T_DELAY },
};
while (1)
{
tokn = getatoken(script,tokens,ARRAY_SIZE(tokens));
@ -9471,50 +9472,75 @@ static int32_t parsedefinitions_game(scriptfile *script, int32_t preload)
}
break;
#ifdef USE_LIBVPX
case T_CUTSCENE:
{
int32_t delay = 10;
char *animend;
dukeanim_t *anim = NULL;
char *animname = NULL;
scriptfile_getstring(script, &animname);
if (scriptfile_getbraces(script, &animend))
break;
while (script->textptr < animend)
{
switch (getatoken(script, animtokens, ARRAY_SIZE(animtokens)))
{
case T_DELAY: scriptfile_getnumber(script, &delay); break;
}
}
// if (!preload)
{
/*
if (check_file_exist(animname))
break;
*/
anim = G_FindAnim(animname);
if (!anim)
anim = G_DefineAnim(animname, delay, NULL);
else
anim->framedelay = delay;
}
}
break;
case T_ANIMSOUNDS:
{
char *otokptr = script->ltextptr;
char *animsoundsend = NULL;
int32_t animnum, numpairs=0, allocsz=4, bad=1, lastframenum=INT32_MIN;
int32_t numpairs = 0, allocsz = 4, bad = 1, lastframenum = INT32_MIN;
dukeanim_t *anim = NULL;
char *animname = NULL;
static const tokenlist hardcoded_anim_tokens[] =
scriptfile_getstring(script, &animname);
if (animname)
anim = G_FindAnim(animname);
if (!anim)
{
{ "cineov2", 0 },
{ "cineov3", 1 },
{ "RADLOGO", 2 },
{ "DUKETEAM", 3 },
{ "logo", 4 },
{ "vol41a", 5 },
{ "vol42a", 6 },
{ "vol4e1", 7 },
{ "vol43a", 8 },
{ "vol4e2", 9 },
{ "vol4e3", 10 },
{ "3dr", 11 },
// NUM_HARDCODED_ANIMS
};
EDUKE32_STATIC_ASSERT(ARRAY_SIZE(hardcoded_anim_tokens) == NUM_HARDCODED_ANIMS);
animnum = getatoken(script, hardcoded_anim_tokens, NUM_HARDCODED_ANIMS);
if ((unsigned)animnum >= NUM_HARDCODED_ANIMS)
initprintf("Error: expected a hardcoded anim file name (sans extension) on line %s:%d\n",
script->filename, scriptfile_getlinum(script, otokptr));
break;
}
if (scriptfile_getbraces(script, &animsoundsend)) break;
if (scriptfile_getbraces(script, &animsoundsend))
break;
if (anim_hi_sounds[animnum])
if (anim->sounds)
{
initprintf("Warning: overwriting already defined hi-anim %s's sounds on line %s:%d\n",
hardcoded_anim_tokens[animnum].text, script->filename,
scriptfile_getlinum(script, otokptr));
Bfree(anim_hi_sounds[animnum]);
anim_hi_numsounds[animnum] = 0;
initprintf("Warning: overwriting already defined hi-anim %s's sounds on line %s:%d\n", animname,
script->filename, scriptfile_getlinum(script, otokptr));
Bfree(anim->sounds);
anim->numsounds = 0;
}
if (!preload)
anim_hi_sounds[animnum] = (uint16_t *)Xcalloc(allocsz, 2*sizeof(anim_hi_sounds[0]));
anim->sounds = (uint16_t *)Xcalloc(allocsz, 2 * sizeof(uint16_t));
while (script->textptr < animsoundsend)
{
int32_t framenum, soundnum;
@ -9522,7 +9548,10 @@ static int32_t parsedefinitions_game(scriptfile *script, int32_t preload)
if (preload)
{
// dummy
getatoken(script, hardcoded_anim_tokens, NUM_HARDCODED_ANIMS);
scriptfile_getstring(script, &animname);
if (animname)
anim = G_FindAnim(animname);
continue;
}
@ -9534,21 +9563,23 @@ static int32_t parsedefinitions_game(scriptfile *script, int32_t preload)
// would produce error when it encounters the closing '}'
// without the above hack
if (scriptfile_getnumber(script, &framenum)) break;
bad=1;
// TODO: look carefully at whether this can be removed.
if (anim_hi_sounds[animnum]==NULL) // Bcalloc check
if (scriptfile_getnumber(script, &framenum))
break;
if (scriptfile_getsymbol(script, &soundnum)) break;
bad = 1;
// TODO: look carefully at whether this can be removed.
if (anim->sounds == NULL) // Bcalloc check
break;
if (scriptfile_getsymbol(script, &soundnum))
break;
// frame numbers start at 1 for us
if (framenum <= 0)
{
initprintf("Error: frame number must be greater zero on line %s:%d\n",
script->filename, scriptfile_getlinum(script, script->ltextptr));
initprintf("Error: frame number must be greater zero on line %s:%d\n", script->filename,
scriptfile_getlinum(script, script->ltextptr));
break;
}
@ -9563,8 +9594,8 @@ static int32_t parsedefinitions_game(scriptfile *script, int32_t preload)
if ((unsigned)soundnum >= MAXSOUNDS)
{
initprintf("Error: sound number #%d invalid on line %s:%d\n", soundnum,
script->filename, scriptfile_getlinum(script, script->ltextptr));
initprintf("Error: sound number #%d invalid on line %s:%d\n", soundnum, script->filename,
scriptfile_getlinum(script, script->ltextptr));
break;
}
@ -9573,15 +9604,15 @@ static int32_t parsedefinitions_game(scriptfile *script, int32_t preload)
void *newptr;
allocsz *= 2;
newptr = Xrealloc(anim_hi_sounds[animnum], allocsz*2*sizeof(anim_hi_sounds[0]));
newptr = Xrealloc(anim->sounds, allocsz * 2 * sizeof(uint16_t));
anim_hi_sounds[animnum] = (uint16_t *)newptr;
anim->sounds = (uint16_t *)newptr;
}
bad=0;
bad = 0;
anim_hi_sounds[animnum][2*numpairs] = framenum;
anim_hi_sounds[animnum][2*numpairs+1] = soundnum;
anim->sounds[2 * numpairs] = framenum;
anim->sounds[2 * numpairs + 1] = soundnum;
numpairs++;
}
@ -9589,21 +9620,20 @@ static int32_t parsedefinitions_game(scriptfile *script, int32_t preload)
{
if (!bad)
{
anim_hi_numsounds[animnum] = numpairs;
anim->numsounds = numpairs;
// initprintf("Defined sound sequence for hi-anim \"%s\" with %d frame/sound pairs\n",
// hardcoded_anim_tokens[animnum].text, numpairs);
}
else
{
Bfree(anim_hi_sounds[animnum]);
anim_hi_sounds[animnum] = NULL;
DO_FREE_AND_NULL(anim->sounds);
initprintf("Failed defining sound sequence for hi-anim \"%s\".\n",
hardcoded_anim_tokens[animnum].text);
animname);
}
}
}
break;
#endif // defined USE_LIBVPX
case T_SOUND:
{
char *tinttokptr = script->ltextptr;
@ -10443,7 +10473,7 @@ static void G_DisplayLogo(void)
if (!I_CheckAllInput() && g_noLogoAnim == 0)
{
Net_GetPackets();
G_PlayAnim("logo.anm",5);
G_PlayAnim("logo.anm");
G_FadePalette(0,0,0,63);
I_ClearAllInput();
}
@ -10485,7 +10515,7 @@ static void G_DisplayLogo(void)
if (i != -1)
{
kclose(i);
G_PlayAnim("3dr.anm", 12);
G_PlayAnim("3dr.anm");
G_FadePalette(0, 0, 0, 63);
I_ClearAllInput();
}
@ -10682,6 +10712,8 @@ static void G_Cleanup(void)
hash_free(&h_labels);
hash_free(&h_gamefuncs);
#endif
hash_free(&h_dukeanim); // TODO: free the dukeanim_t structs the hash table entries point to
}
/*
@ -11476,15 +11508,15 @@ int32_t app_main(int32_t argc, const char **argv)
if (quitevent) return 4;
G_InitAnim();
const char *defsfile = G_DefFile();
uint32_t stime = getticks();
if (!loaddefinitionsfile(defsfile))
{
const char *defsfile = G_DefFile();
uint32_t stime = getticks();
if (!loaddefinitionsfile(defsfile))
{
uint32_t etime = getticks();
initprintf("Definitions file \"%s\" loaded in %d ms.\n", defsfile, etime-stime);
loaddefinitions_game(defsfile, FALSE);
}
uint32_t etime = getticks();
initprintf("Definitions file \"%s\" loaded in %d ms.\n", defsfile, etime-stime);
loaddefinitions_game(defsfile, FALSE);
}
for (i=0; i < g_defModulesNum; ++i)
@ -12211,7 +12243,7 @@ VOL1_END:
if (ud.lockout == 0 && !(G_GetLogoFlags() & LOGO_NOE2BONUSSCENE))
{
fadepal(0,0,0, 63,0,-1);
G_PlayAnim("cineov2.anm",1);
G_PlayAnim("cineov2.anm");
I_ClearAllInput();
clearallviews(0L);
nextpage();
@ -12247,19 +12279,19 @@ VOL1_END:
fadepal(0,0,0, 63,0,-1);
I_ClearAllInput();
t = G_PlayAnim("vol4e1.anm",8);
t = G_PlayAnim("vol4e1.anm");
clearallviews(0L);
nextpage();
if (t)
goto end_vol4e;
t = G_PlayAnim("vol4e2.anm",10);
t = G_PlayAnim("vol4e2.anm");
clearallviews(0L);
nextpage();
if (t)
goto end_vol4e;
G_PlayAnim("vol4e3.anm",11);
G_PlayAnim("vol4e3.anm");
clearallviews(0L);
nextpage();
}
@ -12300,7 +12332,7 @@ VOL4_DUKETEAM:
clearallviews(0L);
nextpage();
G_PlayAnim("DUKETEAM.ANM",4);
G_PlayAnim("DUKETEAM.ANM");
I_ClearAllInput();
G_HandleEventsWhileNoInput();
@ -12326,7 +12358,7 @@ VOL4_END:
if (ud.lockout == 0 && !(G_GetLogoFlags() & LOGO_NOE3BONUSSCENE))
{
fadepal(0,0,0, 63,0,-1);
G_PlayAnim("cineov3.anm",2);
G_PlayAnim("cineov3.anm");
I_ClearAllInput();
ototalclock = totalclock+200;
while (totalclock < ototalclock)
@ -12341,7 +12373,7 @@ VOL4_END:
if (G_GetLogoFlags() & LOGO_NOE3RADLOGO)
goto ENDANM;
G_PlayAnim("RADLOGO.ANM",3);
G_PlayAnim("RADLOGO.ANM");
if (ud.lockout == 0 && !I_CheckAllInput())
{
@ -12377,7 +12409,7 @@ ENDANM:
clearallviews(0L);
nextpage();
G_PlayAnim("DUKETEAM.ANM",4);
G_PlayAnim("DUKETEAM.ANM");
I_ClearAllInput();
G_HandleEventsWhileNoInput();

View file

@ -96,6 +96,8 @@ static struct { uint32_t keyw; uint32_t date; } g_keywdate[] =
{ CON_DYNAMICSOUNDREMAP, 20130530 },
{ CON_SCREENSOUND, 20130628 },
{ CON_SETMUSICPOSITION, 20150115 },
{ CON_CUTSCENE, 20150117 },
{ CON_IFCUTSCENE, 20150117 },
};
#endif
@ -555,6 +557,8 @@ const char *keyw[] =
"undefinevolume", // 375
"undefineskill", // 376
"undefinelevel", // 377
"cutscene", // 378
"ifcutscene", // 379
"<null>"
};
#endif
@ -661,6 +665,7 @@ const char *EventNames[MAXEVENTS] =
"EVENT_ACTIVATECHEAT",
"EVENT_DISPLAYINACTIVEMENU",
"EVENT_DISPLAYINACTIVEMENUREST",
"EVENT_CUTSCENE",
#ifdef LUNATIC
"EVENT_ANIMATEALLSPRITES",
#endif
@ -4162,6 +4167,7 @@ static int32_t C_ParseCommand(int32_t loop)
case CON_SETACTORANGLE:
case CON_SETPLAYERANGLE:
case CON_SETMUSICPOSITION:
case CON_CUTSCENE:
C_GetNextVar();
continue;
@ -5124,6 +5130,7 @@ repeatcase:
case CON_IFP:
case CON_IFPINVENTORY:
case CON_IFPLAYERSL:
case CON_IFCUTSCENE:
{
intptr_t offset;
intptr_t lastScriptPtr = (g_scriptPtr-&script[0]-1);
@ -5132,6 +5139,9 @@ repeatcase:
switch (tw)
{
case CON_IFCUTSCENE:
C_GetNextVar();
break;
case CON_IFAI:
C_GetNextValue(LABEL_AI);
break;

View file

@ -982,6 +982,8 @@ enum ScriptKeywords_t
CON_UNDEFINEVOLUME, // 375
CON_UNDEFINESKILL, // 376
CON_UNDEFINELEVEL, // 377
CON_CUTSCENE, // 378
CON_IFCUTSCENE, // 379
CON_END
};
// KEEPINSYNC with the keyword list in lunatic/con_lang.lua

View file

@ -38,6 +38,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "osd.h"
#include "menus.h"
#include "input.h"
#include "anim.h"
#ifdef LUNATIC
# include "lunatic_game.h"
@ -2712,6 +2713,31 @@ nullquote:
}
continue;
case CON_CUTSCENE:
case CON_IFCUTSCENE:
insptr++;
{
int32_t j = Gv_GetVarX(*insptr++);
if (EDUKE32_PREDICT_FALSE((unsigned)j >= MAXQUOTES || ScriptQuotes[j] == NULL))
{
CON_ERRPRINTF("invalid quote ID %d for anim!\n", j);
continue;
}
if (tw == CON_IFCUTSCENE)
{
VM_CONDITIONAL(g_animPtr == G_FindAnim(ScriptQuotes[j]));
continue;
}
tw = ps->palette;
G_PlayAnim(ScriptQuotes[j]);
P_SetGamePalette(ps, tw, 2 + 16);
continue;
}
continue;
case CON_GUNIQHUDID:
insptr++;
{

View file

@ -1363,19 +1363,19 @@ void G_NewGame(int32_t vn, int32_t ln, int32_t sk)
clearview(0L);
nextpage();
i = G_PlayAnim("vol41a.anm",6);
i = G_PlayAnim("vol41a.anm");
clearview(0L);
nextpage();
if (i)
goto end_vol4a;
i = G_PlayAnim("vol42a.anm",7);
i = G_PlayAnim("vol42a.anm");
clearview(0L);
nextpage();
if (i)
goto end_vol4a;
G_PlayAnim("vol43a.anm",9);
G_PlayAnim("vol43a.anm");
clearview(0L);
nextpage();