2019-09-19 22:42:45 +00:00
//-------------------------------------------------------------------------
/*
Copyright ( C ) 2010 - 2019 EDuke32 developers and contributors
Copyright ( C ) 2019 Nuke . YKT
This file is part of NBlood .
NBlood 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 .
*/
//-------------------------------------------------------------------------
2019-09-21 18:59:54 +00:00
# include "ns.h" // Must come before everything else!
2019-09-19 22:42:45 +00:00
# include <string.h>
# include "build.h"
# include "common_game.h"
# include "blood.h"
# include "db.h"
# include "eventq.h"
2019-06-27 04:33:22 +00:00
# include "globals.h"
2019-09-19 22:42:45 +00:00
# include "levels.h"
# include "loadsave.h"
# include "sound.h"
# include "seq.h"
# include "gameutil.h"
# include "actor.h"
2019-10-12 20:45:46 +00:00
# include "view.h"
2020-04-12 06:09:38 +00:00
# include "raze_sound.h"
2019-09-19 22:42:45 +00:00
2019-09-22 06:39:22 +00:00
BEGIN_BLD_NS
2020-10-11 10:18:25 +00:00
enum
{
kMaxSeqClients = 256 ,
kMaxSequences = 1024
} ;
2019-09-19 22:42:45 +00:00
static ACTIVE activeList [ kMaxSequences ] ;
2020-10-11 08:54:05 +00:00
static int seqActiveCount = 0 ;
static int nSeqClients = 0 ;
static void ( * seqClientCallback [ kMaxSeqClients ] ) ( int , int ) ;
2019-09-19 22:42:45 +00:00
int seqRegisterClient ( void ( * pClient ) ( int , int ) )
{
2020-10-11 10:38:17 +00:00
assert ( nSeqClients < kMaxSeqClients ) ;
2020-10-11 08:54:05 +00:00
seqClientCallback [ nSeqClients ] = pClient ;
return nSeqClients + + ;
2019-09-19 22:42:45 +00:00
}
void Seq : : Preload ( void )
{
if ( memcmp ( signature , " SEQ \x1a " , 4 ) ! = 0 )
2020-10-11 10:22:36 +00:00
I_Error ( " Invalid sequence " ) ;
2019-09-19 22:42:45 +00:00
if ( ( version & 0xff00 ) ! = 0x300 )
2020-10-11 10:22:36 +00:00
I_Error ( " Obsolete sequence version " ) ;
2019-09-19 22:42:45 +00:00
for ( int i = 0 ; i < nFrames ; i + + )
tilePreloadTile ( seqGetTile ( & frames [ i ] ) ) ;
}
2020-09-08 17:18:11 +00:00
void Seq : : Precache ( HitList & hits )
2019-09-19 22:42:45 +00:00
{
if ( memcmp ( signature , " SEQ \x1a " , 4 ) ! = 0 )
2020-10-11 10:22:36 +00:00
I_Error ( " Invalid sequence " ) ;
2019-09-19 22:42:45 +00:00
if ( ( version & 0xff00 ) ! = 0x300 )
2020-10-11 10:22:36 +00:00
I_Error ( " Obsolete sequence version " ) ;
2019-09-19 22:42:45 +00:00
for ( int i = 0 ; i < nFrames ; i + + )
2020-09-08 17:18:11 +00:00
tilePrecacheTile ( seqGetTile ( & frames [ i ] ) , - 1 , hits ) ;
2019-09-19 22:42:45 +00:00
}
2020-09-08 17:18:11 +00:00
void seqPrecacheId ( int id , HitList & hits )
2019-09-19 22:42:45 +00:00
{
2020-07-25 20:47:46 +00:00
auto pSeq = getSequence ( id ) ;
2020-09-08 17:18:11 +00:00
if ( pSeq ) pSeq - > Precache ( hits ) ;
2019-09-19 22:42:45 +00:00
}
SEQINST siWall [ kMaxXWalls ] ;
SEQINST siCeiling [ kMaxXSectors ] ;
SEQINST siFloor [ kMaxXSectors ] ;
SEQINST siSprite [ kMaxXSprites ] ;
SEQINST siMasked [ kMaxXWalls ] ;
void UpdateSprite ( int nXSprite , SEQFRAME * pFrame )
{
2020-10-11 10:38:17 +00:00
assert ( nXSprite > 0 & & nXSprite < kMaxXSprites ) ;
2019-09-19 22:42:45 +00:00
int nSprite = xsprite [ nXSprite ] . reference ;
2020-10-11 10:38:17 +00:00
assert ( nSprite > = 0 & & nSprite < kMaxSprites ) ;
2019-09-19 22:42:45 +00:00
spritetype * pSprite = & sprite [ nSprite ] ;
2020-10-11 10:38:17 +00:00
assert ( pSprite - > extra = = nXSprite ) ;
2019-09-30 07:18:01 +00:00
if ( pSprite - > flags & 2 )
2019-09-19 22:42:45 +00:00
{
2020-05-24 10:31:38 +00:00
if ( tilesiz [ pSprite - > picnum ] . y ! = tilesiz [ seqGetTile ( pFrame ) ] . y | | tileTopOffset ( pSprite - > picnum ) ! = tileTopOffset ( seqGetTile ( pFrame ) )
2019-09-19 22:42:45 +00:00
| | ( pFrame - > at3_0 & & pFrame - > at3_0 ! = pSprite - > yrepeat ) )
2019-09-30 07:18:01 +00:00
pSprite - > flags | = 4 ;
2019-09-19 22:42:45 +00:00
}
pSprite - > picnum = seqGetTile ( pFrame ) ;
if ( pFrame - > at5_0 )
pSprite - > pal = pFrame - > at5_0 ;
pSprite - > shade = pFrame - > at4_0 ;
int scale = xsprite [ nXSprite ] . scale ; // SEQ size scaling
if ( pFrame - > at2_0 ) {
2019-11-08 19:57:01 +00:00
if ( scale ) pSprite - > xrepeat = ClipRange ( mulscale8 ( pFrame - > at2_0 , scale ) , 0 , 255 ) ;
2019-09-19 22:42:45 +00:00
else pSprite - > xrepeat = pFrame - > at2_0 ;
}
if ( pFrame - > at3_0 ) {
2019-11-08 19:57:01 +00:00
if ( scale ) pSprite - > yrepeat = ClipRange ( mulscale8 ( pFrame - > at3_0 , scale ) , 0 , 255 ) ;
2019-09-19 22:42:45 +00:00
else pSprite - > yrepeat = pFrame - > at3_0 ;
}
if ( pFrame - > at1_4 )
pSprite - > cstat | = 2 ;
else
pSprite - > cstat & = ~ 2 ;
if ( pFrame - > at1_5 )
pSprite - > cstat | = 512 ;
else
pSprite - > cstat & = ~ 512 ;
if ( pFrame - > at1_6 )
pSprite - > cstat | = 1 ;
else
pSprite - > cstat & = ~ 1 ;
if ( pFrame - > at1_7 )
pSprite - > cstat | = 256 ;
else
pSprite - > cstat & = ~ 256 ;
if ( pFrame - > at6_2 )
pSprite - > cstat | = 32768 ;
else
pSprite - > cstat & = ( unsigned short ) ~ 32768 ;
if ( pFrame - > at6_0 )
pSprite - > cstat | = 4096 ;
else
pSprite - > cstat & = ~ 4096 ;
if ( pFrame - > at5_6 )
2019-09-30 07:18:01 +00:00
pSprite - > flags | = 256 ;
2019-09-19 22:42:45 +00:00
else
2019-09-30 07:18:01 +00:00
pSprite - > flags & = ~ 256 ;
2019-09-19 22:42:45 +00:00
if ( pFrame - > at5_7 )
2019-09-30 07:18:01 +00:00
pSprite - > flags | = 8 ;
2019-09-19 22:42:45 +00:00
else
2019-09-30 07:18:01 +00:00
pSprite - > flags & = ~ 8 ;
2019-09-19 22:42:45 +00:00
if ( pFrame - > at6_3 )
2019-09-30 07:18:01 +00:00
pSprite - > flags | = 1024 ;
2019-09-19 22:42:45 +00:00
else
2019-09-30 07:18:01 +00:00
pSprite - > flags & = ~ 1024 ;
2019-09-19 22:42:45 +00:00
if ( pFrame - > at6_4 )
2019-09-30 07:18:01 +00:00
pSprite - > flags | = 2048 ;
2019-09-19 22:42:45 +00:00
else
2019-09-30 07:18:01 +00:00
pSprite - > flags & = ~ 2048 ;
2019-09-19 22:42:45 +00:00
}
void UpdateWall ( int nXWall , SEQFRAME * pFrame )
{
2020-10-11 10:38:17 +00:00
assert ( nXWall > 0 & & nXWall < kMaxXWalls ) ;
2019-09-19 22:42:45 +00:00
int nWall = xwall [ nXWall ] . reference ;
2020-10-11 10:38:17 +00:00
assert ( nWall > = 0 & & nWall < kMaxWalls ) ;
2019-09-19 22:42:45 +00:00
walltype * pWall = & wall [ nWall ] ;
2020-10-11 10:38:17 +00:00
assert ( pWall - > extra = = nXWall ) ;
2019-09-19 22:42:45 +00:00
pWall - > picnum = seqGetTile ( pFrame ) ;
if ( pFrame - > at5_0 )
pWall - > pal = pFrame - > at5_0 ;
if ( pFrame - > at1_4 )
pWall - > cstat | = 128 ;
else
pWall - > cstat & = ~ 128 ;
if ( pFrame - > at1_5 )
pWall - > cstat | = 512 ;
else
pWall - > cstat & = ~ 512 ;
if ( pFrame - > at1_6 )
pWall - > cstat | = 1 ;
else
pWall - > cstat & = ~ 1 ;
if ( pFrame - > at1_7 )
pWall - > cstat | = 64 ;
else
pWall - > cstat & = ~ 64 ;
}
void UpdateMasked ( int nXWall , SEQFRAME * pFrame )
{
2020-10-11 10:38:17 +00:00
assert ( nXWall > 0 & & nXWall < kMaxXWalls ) ;
2019-09-19 22:42:45 +00:00
int nWall = xwall [ nXWall ] . reference ;
2020-10-11 10:38:17 +00:00
assert ( nWall > = 0 & & nWall < kMaxWalls ) ;
2019-09-19 22:42:45 +00:00
walltype * pWall = & wall [ nWall ] ;
2020-10-11 10:38:17 +00:00
assert ( pWall - > extra = = nXWall ) ;
assert ( pWall - > nextwall > = 0 ) ;
2019-09-19 22:42:45 +00:00
walltype * pWallNext = & wall [ pWall - > nextwall ] ;
pWall - > overpicnum = pWallNext - > overpicnum = seqGetTile ( pFrame ) ;
if ( pFrame - > at5_0 )
pWall - > pal = pWallNext - > pal = pFrame - > at5_0 ;
if ( pFrame - > at1_4 )
{
pWall - > cstat | = 128 ;
pWallNext - > cstat | = 128 ;
}
else
{
pWall - > cstat & = ~ 128 ;
pWallNext - > cstat & = ~ 128 ;
}
if ( pFrame - > at1_5 )
{
pWall - > cstat | = 512 ;
pWallNext - > cstat | = 512 ;
}
else
{
pWall - > cstat & = ~ 512 ;
pWallNext - > cstat & = ~ 512 ;
}
if ( pFrame - > at1_6 )
{
pWall - > cstat | = 1 ;
pWallNext - > cstat | = 1 ;
}
else
{
pWall - > cstat & = ~ 1 ;
pWallNext - > cstat & = ~ 1 ;
}
if ( pFrame - > at1_7 )
{
pWall - > cstat | = 64 ;
pWallNext - > cstat | = 64 ;
}
else
{
pWall - > cstat & = ~ 64 ;
pWallNext - > cstat & = ~ 64 ;
}
}
void UpdateFloor ( int nXSector , SEQFRAME * pFrame )
{
2020-10-11 10:38:17 +00:00
assert ( nXSector > 0 & & nXSector < kMaxXSectors ) ;
2019-09-19 22:42:45 +00:00
int nSector = xsector [ nXSector ] . reference ;
2020-10-11 10:38:17 +00:00
assert ( nSector > = 0 & & nSector < kMaxSectors ) ;
2019-09-19 22:42:45 +00:00
sectortype * pSector = & sector [ nSector ] ;
2020-10-11 10:38:17 +00:00
assert ( pSector - > extra = = nXSector ) ;
2019-09-19 22:42:45 +00:00
pSector - > floorpicnum = seqGetTile ( pFrame ) ;
pSector - > floorshade = pFrame - > at4_0 ;
if ( pFrame - > at5_0 )
pSector - > floorpal = pFrame - > at5_0 ;
}
void UpdateCeiling ( int nXSector , SEQFRAME * pFrame )
{
2020-10-11 10:38:17 +00:00
assert ( nXSector > 0 & & nXSector < kMaxXSectors ) ;
2019-09-19 22:42:45 +00:00
int nSector = xsector [ nXSector ] . reference ;
2020-10-11 10:38:17 +00:00
assert ( nSector > = 0 & & nSector < kMaxSectors ) ;
2019-09-19 22:42:45 +00:00
sectortype * pSector = & sector [ nSector ] ;
2020-10-11 10:38:17 +00:00
assert ( pSector - > extra = = nXSector ) ;
2019-09-19 22:42:45 +00:00
pSector - > ceilingpicnum = seqGetTile ( pFrame ) ;
pSector - > ceilingshade = pFrame - > at4_0 ;
if ( pFrame - > at5_0 )
pSector - > ceilingpal = pFrame - > at5_0 ;
}
void SEQINST : : Update ( ACTIVE * pActive )
{
2020-10-11 10:38:17 +00:00
assert ( frameIndex < pSequence - > nFrames ) ;
2019-09-19 22:42:45 +00:00
switch ( pActive - > type )
{
case 0 :
UpdateWall ( pActive - > xindex , & pSequence - > frames [ frameIndex ] ) ;
break ;
case 1 :
UpdateCeiling ( pActive - > xindex , & pSequence - > frames [ frameIndex ] ) ;
break ;
case 2 :
UpdateFloor ( pActive - > xindex , & pSequence - > frames [ frameIndex ] ) ;
break ;
case 3 :
{
UpdateSprite ( pActive - > xindex , & pSequence - > frames [ frameIndex ] ) ;
2019-07-29 16:18:41 +00:00
if ( pSequence - > frames [ frameIndex ] . at6_1 ) {
int sound = pSequence - > ata ;
// by NoOne: add random sound range feature
if ( ! VanillaMode ( ) & & pSequence - > frames [ frameIndex ] . soundRange > 0 )
sound + = Random ( ( ( pSequence - > frames [ frameIndex ] . soundRange = = 1 ) ? 2 : pSequence - > frames [ frameIndex ] . soundRange ) ) ;
sfxPlay3DSound ( & sprite [ xsprite [ pActive - > xindex ] . reference ] , sound , - 1 , 0 ) ;
}
2019-09-19 22:42:45 +00:00
2020-01-26 11:19:01 +00:00
// by NoOne: add surfaceSound trigger feature
2019-09-19 22:42:45 +00:00
spritetype * pSprite = & sprite [ xsprite [ pActive - > xindex ] . reference ] ;
2020-02-07 19:47:43 +00:00
if ( ! VanillaMode ( ) & & pSequence - > frames [ frameIndex ] . surfaceSound & & zvel [ pSprite - > index ] = = 0 & & xvel [ pSprite - > index ] ! = 0 ) {
2020-01-26 11:19:01 +00:00
2019-09-19 22:42:45 +00:00
if ( gUpperLink [ pSprite - > sectnum ] > = 0 ) break ; // don't play surface sound for stacked sectors
int surf = tileGetSurfType ( pSprite - > sectnum + 0x4000 ) ; if ( ! surf ) break ;
static int surfSfxMove [ 15 ] [ 4 ] = {
/* {snd1, snd2, gameVolume, myVolume} */
{ 800 , 801 , 80 , 25 } ,
{ 802 , 803 , 80 , 25 } ,
{ 804 , 805 , 80 , 25 } ,
{ 806 , 807 , 80 , 25 } ,
{ 808 , 809 , 80 , 25 } ,
{ 810 , 811 , 80 , 25 } ,
{ 812 , 813 , 80 , 25 } ,
{ 814 , 815 , 80 , 25 } ,
{ 816 , 817 , 80 , 25 } ,
{ 818 , 819 , 80 , 25 } ,
{ 820 , 821 , 80 , 25 } ,
{ 822 , 823 , 80 , 25 } ,
{ 824 , 825 , 80 , 25 } ,
{ 826 , 827 , 80 , 25 } ,
{ 828 , 829 , 80 , 25 } ,
} ;
int sndId = surfSfxMove [ surf ] [ Random ( 2 ) ] ;
2019-12-17 18:37:05 +00:00
auto snd = soundEngine - > FindSoundByResID ( sndId ) ;
if ( snd > 0 )
{
2020-02-23 17:30:48 +00:00
auto udata = soundEngine - > GetUserData ( snd ) ;
2019-12-17 18:37:05 +00:00
int relVol = udata ? udata [ 2 ] : 255 ;
sfxPlay3DSoundCP ( pSprite , sndId , - 1 , 0 , 0 , ( surfSfxMove [ surf ] [ 2 ] ! = relVol ) ? relVol : surfSfxMove [ surf ] [ 3 ] ) ;
}
2019-09-19 22:42:45 +00:00
}
break ;
}
case 4 :
UpdateMasked ( pActive - > xindex , & pSequence - > frames [ frameIndex ] ) ;
break ;
}
if ( pSequence - > frames [ frameIndex ] . at5_5 & & atc ! = - 1 )
2020-10-11 08:54:05 +00:00
seqClientCallback [ atc ] ( pActive - > type , pActive - > xindex ) ;
2019-09-19 22:42:45 +00:00
}
SEQINST * GetInstance ( int a1 , int a2 )
{
switch ( a1 )
{
case 0 :
if ( a2 > 0 & & a2 < kMaxXWalls ) return & siWall [ a2 ] ;
break ;
case 1 :
if ( a2 > 0 & & a2 < kMaxXSectors ) return & siCeiling [ a2 ] ;
break ;
case 2 :
if ( a2 > 0 & & a2 < kMaxXSectors ) return & siFloor [ a2 ] ;
break ;
case 3 :
if ( a2 > 0 & & a2 < kMaxXSprites ) return & siSprite [ a2 ] ;
break ;
case 4 :
if ( a2 > 0 & & a2 < kMaxWalls ) return & siMasked [ a2 ] ;
break ;
}
return NULL ;
}
void UnlockInstance ( SEQINST * pInst )
{
2020-10-11 10:38:17 +00:00
assert ( pInst ! = NULL ) ;
assert ( pInst - > pSequence ! = NULL ) ;
2019-09-19 22:42:45 +00:00
pInst - > pSequence = NULL ;
pInst - > at13 = 0 ;
}
void seqSpawn ( int a1 , int a2 , int a3 , int a4 )
{
SEQINST * pInst = GetInstance ( a2 , a3 ) ;
2019-10-12 20:45:46 +00:00
if ( ! pInst ) return ;
2020-07-25 20:47:46 +00:00
auto pSeq = getSequence ( a1 ) ;
if ( ! pSeq )
2020-10-11 10:22:36 +00:00
I_Error ( " Missing sequence #%d " , a1 ) ;
2019-10-12 20:45:46 +00:00
2020-10-11 08:54:05 +00:00
int i = seqActiveCount ;
2019-09-19 22:42:45 +00:00
if ( pInst - > at13 )
{
2020-07-25 20:47:46 +00:00
if ( pSeq = = pInst - > pSequence )
2019-09-19 22:42:45 +00:00
return ;
UnlockInstance ( pInst ) ;
2020-10-11 08:54:05 +00:00
for ( i = 0 ; i < seqActiveCount ; i + + )
2019-09-19 22:42:45 +00:00
{
if ( activeList [ i ] . type = = a2 & & activeList [ i ] . xindex = = a3 )
break ;
}
2020-10-11 10:38:17 +00:00
assert ( i < seqActiveCount ) ;
2019-09-19 22:42:45 +00:00
}
if ( memcmp ( pSeq - > signature , " SEQ \x1a " , 4 ) ! = 0 )
2020-10-11 10:22:36 +00:00
I_Error ( " Invalid sequence %d " , a1 ) ;
2019-09-19 22:42:45 +00:00
if ( ( pSeq - > version & 0xff00 ) ! = 0x300 )
2020-10-11 10:22:36 +00:00
I_Error ( " Sequence %d is obsolete version " , a1 ) ;
2019-09-19 22:42:45 +00:00
if ( ( pSeq - > version & 0xff ) = = 0x00 )
{
for ( int i = 0 ; i < pSeq - > nFrames ; i + + )
pSeq - > frames [ i ] . tile2 = 0 ;
}
pInst - > at13 = 1 ;
pInst - > pSequence = pSeq ;
pInst - > at8 = a1 ;
pInst - > atc = a4 ;
pInst - > at10 = pSeq - > at8 ;
pInst - > frameIndex = 0 ;
2020-10-11 08:54:05 +00:00
if ( i = = seqActiveCount )
2019-09-19 22:42:45 +00:00
{
2020-10-11 10:38:17 +00:00
assert ( seqActiveCount < kMaxSequences ) ;
2020-10-11 08:54:05 +00:00
activeList [ seqActiveCount ] . type = a2 ;
activeList [ seqActiveCount ] . xindex = a3 ;
seqActiveCount + + ;
2019-09-19 22:42:45 +00:00
}
pInst - > Update ( & activeList [ i ] ) ;
}
void seqKill ( int a1 , int a2 )
{
SEQINST * pInst = GetInstance ( a1 , a2 ) ;
if ( ! pInst | | ! pInst - > at13 )
return ;
int i ;
2020-10-11 08:54:05 +00:00
for ( i = 0 ; i < seqActiveCount ; i + + )
2019-09-19 22:42:45 +00:00
{
if ( activeList [ i ] . type = = a1 & & activeList [ i ] . xindex = = a2 )
break ;
}
2020-10-11 10:38:17 +00:00
assert ( i < seqActiveCount ) ;
2020-10-11 08:54:05 +00:00
seqActiveCount - - ;
activeList [ i ] = activeList [ seqActiveCount ] ;
2019-09-19 22:42:45 +00:00
pInst - > at13 = 0 ;
UnlockInstance ( pInst ) ;
}
void seqKillAll ( void )
{
for ( int i = 0 ; i < kMaxXWalls ; i + + )
{
if ( siWall [ i ] . at13 )
UnlockInstance ( & siWall [ i ] ) ;
if ( siMasked [ i ] . at13 )
UnlockInstance ( & siMasked [ i ] ) ;
}
for ( int i = 0 ; i < kMaxXSectors ; i + + )
{
if ( siCeiling [ i ] . at13 )
UnlockInstance ( & siCeiling [ i ] ) ;
if ( siFloor [ i ] . at13 )
UnlockInstance ( & siFloor [ i ] ) ;
}
for ( int i = 0 ; i < kMaxXSprites ; i + + )
{
if ( siSprite [ i ] . at13 )
UnlockInstance ( & siSprite [ i ] ) ;
}
2020-10-11 08:54:05 +00:00
seqActiveCount = 0 ;
2019-09-19 22:42:45 +00:00
}
int seqGetStatus ( int a1 , int a2 )
{
SEQINST * pInst = GetInstance ( a1 , a2 ) ;
if ( pInst & & pInst - > at13 )
return pInst - > frameIndex ;
return - 1 ;
}
int seqGetID ( int a1 , int a2 )
{
SEQINST * pInst = GetInstance ( a1 , a2 ) ;
if ( pInst )
return pInst - > at8 ;
return - 1 ;
}
void seqProcess ( int a1 )
{
2020-10-11 08:54:05 +00:00
for ( int i = 0 ; i < seqActiveCount ; i + + )
2019-09-19 22:42:45 +00:00
{
SEQINST * pInst = GetInstance ( activeList [ i ] . type , activeList [ i ] . xindex ) ;
Seq * pSeq = pInst - > pSequence ;
2020-10-11 10:38:17 +00:00
assert ( pInst - > frameIndex < pSeq - > nFrames ) ;
2019-09-19 22:42:45 +00:00
pInst - > at10 - = a1 ;
while ( pInst - > at10 < 0 )
{
pInst - > at10 + = pSeq - > at8 ;
pInst - > frameIndex + + ;
if ( pInst - > frameIndex = = pSeq - > nFrames )
{
if ( pSeq - > atc & 1 )
pInst - > frameIndex = 0 ;
else
{
UnlockInstance ( pInst ) ;
if ( pSeq - > atc & 2 )
{
switch ( activeList [ i ] . type )
{
case 3 :
{
int nXSprite = activeList [ i ] . xindex ;
int nSprite = xsprite [ nXSprite ] . reference ;
2020-10-11 10:38:17 +00:00
assert ( nSprite > = 0 & & nSprite < kMaxSprites ) ;
2019-09-19 22:42:45 +00:00
evKill ( nSprite , 3 ) ;
2019-10-15 12:36:50 +00:00
if ( ( sprite [ nSprite ] . flags & kHitagRespawn ) & & sprite [ nSprite ] . inittype > = kDudeBase & & sprite [ nSprite ] . inittype < kDudeMax )
evPost ( nSprite , 3 , gGameOptions . nMonsterRespawnTime , kCallbackRespawn ) ;
2019-09-19 22:42:45 +00:00
else
DeleteSprite ( nSprite ) ;
break ;
}
case 4 :
{
int nXWall = activeList [ i ] . xindex ;
int nWall = xwall [ nXWall ] . reference ;
2020-10-11 10:38:17 +00:00
assert ( nWall > = 0 & & nWall < kMaxWalls ) ;
2019-09-19 22:42:45 +00:00
wall [ nWall ] . cstat & = ~ ( 8 + 16 + 32 ) ;
if ( wall [ nWall ] . nextwall ! = - 1 )
wall [ wall [ nWall ] . nextwall ] . cstat & = ~ ( 8 + 16 + 32 ) ;
break ;
}
}
}
2020-10-11 08:54:05 +00:00
activeList [ i - - ] = activeList [ - - seqActiveCount ] ;
2019-09-19 22:42:45 +00:00
break ;
}
}
pInst - > Update ( & activeList [ i ] ) ;
}
}
}
class SeqLoadSave : public LoadSave {
virtual void Load ( void ) ;
virtual void Save ( void ) ;
} ;
void SeqLoadSave : : Load ( void )
{
Read ( & siWall , sizeof ( siWall ) ) ;
Read ( & siMasked , sizeof ( siMasked ) ) ;
Read ( & siCeiling , sizeof ( siCeiling ) ) ;
Read ( & siFloor , sizeof ( siFloor ) ) ;
Read ( & siSprite , sizeof ( siSprite ) ) ;
Read ( & activeList , sizeof ( activeList ) ) ;
2020-10-11 08:54:05 +00:00
Read ( & seqActiveCount , sizeof ( seqActiveCount ) ) ;
2019-09-19 22:42:45 +00:00
for ( int i = 0 ; i < kMaxXWalls ; i + + )
{
siWall [ i ] . pSequence = NULL ;
siMasked [ i ] . pSequence = NULL ;
}
for ( int i = 0 ; i < kMaxXSectors ; i + + )
{
siCeiling [ i ] . pSequence = NULL ;
siFloor [ i ] . pSequence = NULL ;
}
for ( int i = 0 ; i < kMaxXSprites ; i + + )
{
siSprite [ i ] . pSequence = NULL ;
}
2020-10-11 08:54:05 +00:00
for ( int i = 0 ; i < seqActiveCount ; i + + )
2019-09-19 22:42:45 +00:00
{
SEQINST * pInst = GetInstance ( activeList [ i ] . type , activeList [ i ] . xindex ) ;
if ( pInst - > at13 )
{
int nSeq = pInst - > at8 ;
2020-07-25 20:47:46 +00:00
auto pSeq = getSequence ( nSeq ) ;
if ( ! pSeq ) {
2020-10-11 10:22:36 +00:00
I_Error ( " Missing sequence #%d " , nSeq ) ;
2019-10-12 20:45:46 +00:00
continue ;
}
2019-09-19 22:42:45 +00:00
if ( memcmp ( pSeq - > signature , " SEQ \x1a " , 4 ) ! = 0 )
2020-10-11 10:22:36 +00:00
I_Error ( " Invalid sequence %d " , nSeq ) ;
2019-09-19 22:42:45 +00:00
if ( ( pSeq - > version & 0xff00 ) ! = 0x300 )
2020-10-11 10:22:36 +00:00
I_Error ( " Sequence %d is obsolete version " , nSeq ) ;
2019-09-19 22:42:45 +00:00
pInst - > pSequence = pSeq ;
}
}
}
void SeqLoadSave : : Save ( void )
{
Write ( & siWall , sizeof ( siWall ) ) ;
Write ( & siMasked , sizeof ( siMasked ) ) ;
Write ( & siCeiling , sizeof ( siCeiling ) ) ;
Write ( & siFloor , sizeof ( siFloor ) ) ;
Write ( & siSprite , sizeof ( siSprite ) ) ;
Write ( & activeList , sizeof ( activeList ) ) ;
2020-10-11 08:54:05 +00:00
Write ( & seqActiveCount , sizeof ( seqActiveCount ) ) ;
2019-09-19 22:42:45 +00:00
}
void SeqLoadSaveConstruct ( void )
{
2020-10-11 08:54:05 +00:00
new SeqLoadSave ( ) ;
2019-09-19 22:42:45 +00:00
}
2019-09-22 06:39:22 +00:00
2020-07-25 20:47:46 +00:00
static void ByteSwapSEQ ( Seq * pSeq )
{
2020-07-25 21:35:39 +00:00
# if B_BIG_ENDIAN == 1
2020-08-03 17:09:57 +00:00
pSeq - > version = LittleShort ( pSeq - > version ) ;
pSeq - > nFrames = LittleShort ( pSeq - > nFrames ) ;
pSeq - > at8 = LittleShort ( pSeq - > at8 ) ;
pSeq - > ata = LittleShort ( pSeq - > ata ) ;
pSeq - > atc = LittleLong ( pSeq - > atc ) ;
2020-07-25 20:47:46 +00:00
for ( int i = 0 ; i < pSeq - > nFrames ; i + + )
{
SEQFRAME * pFrame = & pSeq - > frames [ i ] ;
BitReader bitReader ( ( char * ) pFrame , sizeof ( SEQFRAME ) ) ;
SEQFRAME swapFrame ;
swapFrame . tile = bitReader . readUnsigned ( 12 ) ;
swapFrame . at1_4 = bitReader . readBit ( ) ;
swapFrame . at1_5 = bitReader . readBit ( ) ;
swapFrame . at1_6 = bitReader . readBit ( ) ;
swapFrame . at1_7 = bitReader . readBit ( ) ;
swapFrame . at2_0 = bitReader . readUnsigned ( 8 ) ;
swapFrame . at3_0 = bitReader . readUnsigned ( 8 ) ;
swapFrame . at4_0 = bitReader . readSigned ( 8 ) ;
swapFrame . at5_0 = bitReader . readUnsigned ( 5 ) ;
swapFrame . at5_5 = bitReader . readBit ( ) ;
swapFrame . at5_6 = bitReader . readBit ( ) ;
swapFrame . at5_7 = bitReader . readBit ( ) ;
swapFrame . at6_0 = bitReader . readBit ( ) ;
swapFrame . at6_1 = bitReader . readBit ( ) ;
swapFrame . at6_2 = bitReader . readBit ( ) ;
swapFrame . at6_3 = bitReader . readBit ( ) ;
swapFrame . at6_4 = bitReader . readBit ( ) ;
swapFrame . tile2 = bitReader . readUnsigned ( 4 ) ;
swapFrame . soundRange = bitReader . readUnsigned ( 4 ) ;
swapFrame . surfaceSound = bitReader . readBit ( ) ;
swapFrame . reserved = bitReader . readUnsigned ( 2 ) ;
* pFrame = swapFrame ;
}
2020-07-25 21:35:39 +00:00
# endif
2020-07-25 20:47:46 +00:00
}
// This is to eliminate a huge design issue in NBlood that was apparently copied verbatim from the DOS-Version.
// Sequences were cached in the resource and directly returned from there in writable form, with byte swapping directly performed in the cache on Big Endian systems.
// To avoid such unsafe operations this caches the read data separately in static memory that's guaranteed not to be touched by the file system.
FMemArena seqcache ;
static TMap < int , Seq * > sequences ;
Seq * getSequence ( int res_id )
{
auto p = sequences . CheckKey ( res_id ) ;
if ( p ! = nullptr ) return * p ;
int index = fileSystem . FindResource ( res_id , " SEQ " ) ;
if ( index < 0 )
{
return nullptr ;
}
auto fr = fileSystem . OpenFileReader ( index ) ;
auto seqdata = ( Seq * ) seqcache . Alloc ( fr . GetLength ( ) ) ;
fr . Read ( seqdata , fr . GetLength ( ) ) ;
sequences . Insert ( res_id , seqdata ) ;
ByteSwapSEQ ( seqdata ) ;
return seqdata ;
}
2019-09-22 06:39:22 +00:00
END_BLD_NS