2019-11-20 16:21:32 +00:00
//-------------------------------------------------------------------------
/*
Copyright ( C ) 2010 - 2019 EDuke32 developers and contributors
Copyright ( C ) 2019 sirlemonhead , Nuke . YKT
This file is part of PCExhumed .
PCExhumed 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-11-22 23:11:37 +00:00
# include "ns.h"
2019-09-19 19:45:19 +00:00
# include "compat.h"
2019-09-20 17:04:02 +00:00
# include "build.h"
2019-09-19 19:45:19 +00:00
# include "exhumed.h"
2020-08-18 07:52:08 +00:00
# include "aistuff.h"
2019-09-19 19:45:19 +00:00
# include "player.h"
# include "sequence.h"
2019-09-20 17:04:02 +00:00
# include "menu.h"
# include "names.h"
# include "engine.h"
2020-01-02 18:56:57 +00:00
# include "c_bind.h"
2019-09-19 19:45:19 +00:00
# include "status.h"
2019-09-20 17:04:02 +00:00
# include "sound.h"
# include "names.h"
2019-11-24 09:03:19 +00:00
# include "ps_input.h"
2019-08-26 03:59:14 +00:00
# include "view.h"
2020-04-12 06:09:38 +00:00
# include "raze_sound.h"
2020-06-14 16:57:55 +00:00
# include "menu.h"
2020-01-05 09:48:44 +00:00
# include "v_2ddrawer.h"
2020-08-21 20:30:51 +00:00
# include "gamestate.h"
2019-09-20 17:04:02 +00:00
# include <string>
2019-08-26 03:59:14 +00:00
# include <assert.h>
# ifdef __WATCOMC__
# include <stdlib.h>
# endif
2019-11-22 23:11:37 +00:00
BEGIN_PS_NS
2019-10-29 21:28:14 +00:00
# define kSaveFileName "savgamea.sav"
2019-09-20 17:04:02 +00:00
# define kMaxSaveSlots 5
# define kMaxSaveSlotChars 25
2019-08-26 03:59:14 +00:00
GameStat GameStats ;
short nCinemaSeen [ 30 ] ;
2019-11-18 22:15:48 +00:00
uint8_t energytile [ 66 * 66 ] = { 0 } ;
2019-08-26 03:59:14 +00:00
2019-09-20 17:04:02 +00:00
short nLeft [ 50 ] = { 0 } ;
int line ;
2019-08-26 03:59:14 +00:00
short SavePosition = - 1 ;
2019-08-31 07:47:15 +00:00
uint8_t * cur ;
uint8_t * dest ;
2019-08-26 03:59:14 +00:00
2019-09-20 17:04:02 +00:00
unsigned int nRandom = 0x41C6167E ;
int dword_9AB57 = 0x1F ;
short word_9AB5B = 0 ;
2019-08-26 03:59:14 +00:00
int keytimer = 0 ;
2019-09-20 17:04:02 +00:00
short nMenuKeys [ ] = { sc_N , sc_L , sc_M , sc_V , sc_Q , sc_None } ; // select a menu item using the keys. 'N' for New Gane, 'V' for voume etc. 'M' picks Training for some reason...
2019-08-26 03:59:14 +00:00
void menu_ResetKeyTimer ( ) ;
2019-09-20 17:04:02 +00:00
enum {
2019-08-31 07:47:15 +00:00
kMenuNewGame = 0 ,
kMenuLoadGame ,
kMenuTraining ,
kMenuVolume ,
kMenuQuitGame ,
kMenuMaxItems
2019-08-26 03:59:14 +00:00
} ;
2019-09-20 17:04:02 +00:00
void ClearCinemaSeen ( )
{
memset ( nCinemaSeen , 0 , sizeof ( nCinemaSeen ) ) ;
}
2019-08-26 03:59:14 +00:00
unsigned int menu_RandomBit2 ( )
{
2019-08-31 07:47:15 +00:00
unsigned int result = nRandom & 1 ;
2019-09-20 17:04:02 +00:00
if ( - - dword_9AB57 > 0 )
2019-08-31 07:47:15 +00:00
{
nRandom = ( result < < 31 ) | ( nRandom > > 1 ) ;
}
else
{
dword_9AB57 = 31 ;
nRandom ^ = nRandom > > 4 ;
}
return result ;
2019-08-26 03:59:14 +00:00
}
2019-09-20 17:04:02 +00:00
void InitEnergyTile ( )
{
memset ( energytile , 96 , sizeof ( energytile ) ) ;
}
2019-08-26 03:59:14 +00:00
void DoEnergyTile ( )
{
2019-08-31 07:47:15 +00:00
nButtonColor + = nButtonColor < 0 ? 8 : 0 ;
2019-11-24 15:34:23 +00:00
auto energy1 = TileFiles . tileMakeWritable ( kEnergy1 ) ;
auto energy2 = TileFiles . tileMakeWritable ( kEnergy2 ) ;
uint8_t * ptr1 = energy1 + 1984 ;
uint8_t * ptr2 = energy2 + 2048 ;
2019-08-31 07:47:15 +00:00
short nColor = nButtonColor + 161 ;
int i , j ;
for ( i = 0 ; i < 32 ; i + + )
{
memset ( ptr1 , nColor , 64 ) ;
memset ( ptr2 , nColor , 64 ) ;
ptr1 - = 64 ;
ptr2 + = 64 ;
nColor + + ;
2019-11-20 16:21:32 +00:00
2019-09-20 17:04:02 +00:00
if ( nColor > = 168 ) {
2019-08-31 07:47:15 +00:00
nColor = 160 ;
}
}
2019-11-05 06:15:21 +00:00
tileInvalidate ( kEnergy1 , - 1 , - 1 ) ;
2019-08-31 07:47:15 +00:00
if ( nSmokeSparks )
{
2019-11-18 22:15:48 +00:00
uint8_t * c = & energytile [ 67 ] ; // skip a line
2019-11-24 15:34:23 +00:00
uint8_t * ptrW = energy2 ;
2019-08-31 07:47:15 +00:00
for ( i = 0 ; i < 64 ; i + + )
{
for ( j = 0 ; j < 64 ; j + + )
{
2019-12-03 22:02:17 +00:00
uint8_t val = * c ;
if ( val ! = 96 )
2019-08-31 07:47:15 +00:00
{
2019-12-03 22:02:17 +00:00
if ( val > 158 ) {
* ptrW = val - 1 ;
2019-08-31 07:47:15 +00:00
}
2019-09-20 17:04:02 +00:00
else {
2019-12-03 22:02:17 +00:00
* ptrW = 96 ;
2019-08-31 07:47:15 +00:00
}
}
else
{
2019-09-20 17:04:02 +00:00
if ( menu_RandomBit2 ( ) ) {
2019-08-31 07:47:15 +00:00
* ptrW = * c ;
}
2019-12-03 22:02:17 +00:00
else
{
uint8_t al = * ( c + 1 ) ;
uint8_t ah = * ( c - 1 ) ;
2019-08-31 07:47:15 +00:00
2019-12-03 22:02:17 +00:00
if ( al < = ah ) {
al = ah ;
}
2019-08-31 07:47:15 +00:00
2019-12-03 22:02:17 +00:00
uint8_t cl = al ;
2019-08-31 07:47:15 +00:00
2019-12-03 22:02:17 +00:00
al = * ( c - 66 ) ;
if ( cl < = al ) {
cl = al ;
}
2019-08-31 07:47:15 +00:00
2019-12-03 22:02:17 +00:00
al = * ( c + 66 ) ;
if ( cl < = al ) {
cl = al ;
}
2019-08-31 07:47:15 +00:00
2019-12-03 22:02:17 +00:00
al = * ( c + 66 ) ;
if ( cl < = al ) {
cl = al ;
}
2019-08-31 07:47:15 +00:00
2019-12-03 22:02:17 +00:00
al = * ( c + 66 ) ;
if ( cl < = al ) {
cl = al ;
}
2019-08-31 07:47:15 +00:00
2019-12-03 22:02:17 +00:00
al = * ( c - 65 ) ;
if ( cl < = al ) {
cl = al ;
}
2019-08-31 07:47:15 +00:00
2019-12-03 22:02:17 +00:00
al = * ( c - 67 ) ;
if ( cl > al ) {
al = cl ;
}
2019-08-31 07:47:15 +00:00
2019-12-03 22:02:17 +00:00
cl = al ;
2019-11-18 22:15:48 +00:00
2019-12-03 22:02:17 +00:00
if ( al < = 159 ) {
* ptrW = 96 ;
2019-08-31 07:47:15 +00:00
}
2019-12-03 22:02:17 +00:00
else
{
if ( ! menu_RandomBit2 ( ) ) {
cl - - ;
}
2019-08-31 07:47:15 +00:00
2019-12-03 22:02:17 +00:00
* ptrW = cl ;
}
}
2019-08-31 07:47:15 +00:00
}
c + + ;
ptrW + + ;
}
c + = 2 ;
}
2019-11-18 22:15:48 +00:00
c = & energytile [ 67 ] ;
2019-11-24 15:34:23 +00:00
ptrW = energy2 ;
2019-08-31 07:47:15 +00:00
2019-12-03 22:02:17 +00:00
// copy back to energytile[]
2019-08-31 07:47:15 +00:00
for ( i = 0 ; i < 64 ; i + + )
{
memcpy ( c , ptrW , 64 ) ;
c + = 66 ;
ptrW + = 64 ;
}
2019-11-24 15:34:23 +00:00
ptrW = energy2 ;
2019-11-20 16:21:32 +00:00
2019-12-03 22:02:17 +00:00
// kEnergy2 is 64 x 64
2019-08-31 07:47:15 +00:00
for ( i = 0 ; i < 4096 ; i + + )
{
2019-12-03 22:02:17 +00:00
if ( ptrW [ i ] = = 96 ) {
ptrW [ i ] = 255 ; // -1?
2019-08-31 07:47:15 +00:00
}
}
word_9AB5B - - ;
if ( word_9AB5B < = 0 )
{
int randSize = ( RandomSize ( 5 ) & 0x1F ) + 16 ;
int randSize2 = ( RandomSize ( 5 ) & 0x1F ) + 16 ;
int val = randSize < < 5 ;
val + = randSize ;
val * = 2 ;
val + = randSize2 ;
2019-12-03 22:02:17 +00:00
assert ( val < 4356 ) ;
2019-11-18 22:15:48 +00:00
energytile [ val ] = 175 ;
2019-09-20 17:04:02 +00:00
word_9AB5B = 1 ;
2019-08-31 07:47:15 +00:00
}
2019-11-05 06:15:21 +00:00
tileInvalidate ( kEnergy2 , - 1 , - 1 ) ;
2019-08-31 07:47:15 +00:00
}
2019-08-26 03:59:14 +00:00
}
int menu_NewGameMenu ( )
{
2019-08-31 07:47:15 +00:00
2019-12-13 20:01:14 +00:00
return 0 ;
2019-08-26 03:59:14 +00:00
}
int menu_LoadGameMenu ( )
{
2019-12-13 20:01:14 +00:00
return 0 ;
2019-08-26 03:59:14 +00:00
}
2019-12-02 19:28:02 +00:00
void menu_GameLoad2 ( FILE * fp , bool bIsDemo )
2019-08-26 03:59:14 +00:00
{
2019-12-02 19:28:02 +00:00
if ( bIsDemo )
{
demo_header header ;
fread ( & header , 1 , sizeof ( demo_header ) , fp ) ;
GameStats . nMap = header . nMap ;
GameStats . nWeapons = header . nWeapons ;
GameStats . nCurrentWeapon = header . nCurrentWeapon ;
GameStats . clip = header . clip ;
GameStats . items = header . items ;
GameStats . player . nHealth = header . nHealth ;
GameStats . player . field_2 = header . field_2 ;
GameStats . player . nAction = header . nAction ;
GameStats . player . nSprite = header . nSprite ;
GameStats . player . bIsMummified = header . bIsMummified ;
GameStats . player . someNetVal = header . someNetVal ;
GameStats . player . invincibility = header . invincibility ;
GameStats . player . nAir = header . nAir ;
GameStats . player . nSeq = header . nSeq ;
GameStats . player . nMaskAmount = header . nMaskAmount ;
GameStats . player . keys = header . keys ;
GameStats . player . nMagic = header . nMagic ;
Bmemcpy ( GameStats . player . items , header . item , sizeof ( header . item ) ) ;
Bmemcpy ( GameStats . player . nAmmo , header . nAmmo , sizeof ( header . nAmmo ) ) ;
Bmemcpy ( GameStats . player . pad , header . pad , sizeof ( header . pad ) ) ;
GameStats . player . nCurrentWeapon = header . nCurrentWeapon2 ;
GameStats . player . field_3FOUR = header . field_3FOUR ;
GameStats . player . bIsFiring = header . bIsFiring ;
GameStats . player . field_38 = header . field_38 ;
GameStats . player . field_3A = header . field_3A ;
GameStats . player . field_3C = header . field_3C ;
GameStats . player . nRun = header . nRun ;
GameStats . nLives = header . nLives ;
}
else
fread ( & GameStats , sizeof ( GameStats ) , 1 , fp ) ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
nPlayerWeapons [ nLocalPlayer ] = GameStats . nWeapons ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
PlayerList [ nLocalPlayer ] . nCurrentWeapon = GameStats . nCurrentWeapon ;
2019-09-20 17:04:02 +00:00
nPlayerClip [ nLocalPlayer ] = GameStats . clip ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
int nPistolBullets = PlayerList [ nLocalPlayer ] . nAmmo [ kWeaponPistol ] ;
2019-09-20 17:04:02 +00:00
if ( nPistolBullets > = 6 ) {
2019-08-31 07:47:15 +00:00
nPistolBullets = 6 ;
}
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
nPistolClip [ nLocalPlayer ] = nPistolBullets ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
memcpy ( & PlayerList [ nLocalPlayer ] , & GameStats . player , sizeof ( Player ) ) ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
nPlayerItem [ nLocalPlayer ] = GameStats . items ;
nPlayerLives [ nLocalPlayer ] = GameStats . nLives ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
SetPlayerItem ( nLocalPlayer , nPlayerItem [ nLocalPlayer ] ) ;
CheckClip ( nLocalPlayer ) ;
2019-08-26 03:59:14 +00:00
}
short menu_GameLoad ( int nSlot )
{
2019-08-31 07:47:15 +00:00
memset ( & GameStats , 0 , sizeof ( GameStats ) ) ;
2019-11-20 16:21:32 +00:00
2019-10-29 21:28:14 +00:00
FILE * fp = fopen ( kSaveFileName , " rb " ) ;
2019-09-20 17:04:02 +00:00
if ( fp = = NULL ) {
2019-08-31 07:47:15 +00:00
return 0 ;
}
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
fseek ( fp , 125 , SEEK_SET ) ;
fseek ( fp , nSlot * sizeof ( GameStats ) , SEEK_CUR ) ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
menu_GameLoad2 ( fp ) ;
fclose ( fp ) ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
return GameStats . nMap ;
2019-08-26 03:59:14 +00:00
}
void menu_GameSave2 ( FILE * fp )
{
2019-08-31 07:47:15 +00:00
memset ( & GameStats , 0 , sizeof ( GameStats ) ) ;
2019-08-26 03:59:14 +00:00
2019-09-20 17:04:02 +00:00
GameStats . nMap = ( uint8_t ) levelnew ;
GameStats . nWeapons = nPlayerWeapons [ nLocalPlayer ] ;
2019-08-31 07:47:15 +00:00
GameStats . nCurrentWeapon = PlayerList [ nLocalPlayer ] . nCurrentWeapon ;
2019-09-20 17:04:02 +00:00
GameStats . clip = nPlayerClip [ nLocalPlayer ] ;
GameStats . items = nPlayerItem [ nLocalPlayer ] ;
GameStats . nLives = nPlayerLives [ nLocalPlayer ] ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
memcpy ( & GameStats . player , & PlayerList [ nLocalPlayer ] , sizeof ( GameStats . player ) ) ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
fwrite ( & GameStats , sizeof ( GameStats ) , 1 , fp ) ;
2019-08-26 03:59:14 +00:00
}
void menu_GameSave ( int nSaveSlot )
{
2019-09-20 17:04:02 +00:00
if ( nSaveSlot < 0 ) {
2019-08-31 07:47:15 +00:00
return ;
}
2019-10-29 21:28:14 +00:00
FILE * fp = fopen ( kSaveFileName , " rb+ " ) ;
2019-08-31 07:47:15 +00:00
if ( fp ! = NULL )
{
2019-09-20 17:04:02 +00:00
fseek ( fp , 125 , SEEK_SET ) ; // skip save slot names
2019-08-31 07:47:15 +00:00
fseek ( fp , sizeof ( GameStat ) * nSaveSlot , SEEK_CUR ) ;
menu_GameSave2 ( fp ) ;
fclose ( fp ) ;
}
2019-08-26 03:59:14 +00:00
}
2019-09-20 17:04:02 +00:00
# define kMaxCinemaPals 16
const char * cinpalfname [ kMaxCinemaPals ] = {
" 3454.pal " ,
" 3452.pal " ,
" 3449.pal " ,
" 3445.pal " ,
" set.pal " ,
" 3448.pal " ,
" 3446.pal " ,
" hsc1.pal " ,
" 2972.pal " ,
" 2973.pal " ,
" 2974.pal " ,
" 2975.pal " ,
" 2976.pal " ,
" heli.pal " ,
" 2978.pal " ,
" terror.pal "
} ;
2019-08-26 03:59:14 +00:00
2019-09-20 17:04:02 +00:00
int linecount ;
int nextclock ;
2019-08-26 03:59:14 +00:00
short nHeight ;
short nCrawlY ;
short cinematile ;
2020-05-23 12:36:35 +00:00
int currentCinemaPalette ;
2019-08-26 03:59:14 +00:00
2020-05-23 12:36:35 +00:00
void uploadCinemaPalettes ( )
2019-08-26 03:59:14 +00:00
{
2020-05-23 12:36:35 +00:00
for ( int i = 0 ; i < countof ( cinpalfname ) ; i + + )
{
uint8_t palette [ 768 ] = { } ;
auto hFile = fileSystem . OpenFileReader ( cinpalfname [ i ] ) ;
if ( hFile . isOpen ( ) )
hFile . Read ( palette , 768 ) ;
for ( auto & c : palette )
c < < = 2 ;
2020-05-23 12:40:54 +00:00
paletteSetColorTable ( ANIMPAL + i , palette , false , true ) ;
2019-08-31 07:47:15 +00:00
}
2019-08-26 03:59:14 +00:00
}
2019-10-12 21:09:55 +00:00
//int IncrementCinemaFadeIn()
//{
// dest = cinemapal;
// cur = curpal;
//
// int ebx = 0;
//
// for (int i = 0; i < 768; i++)
// {
// ebx++;
//
// if (*cur < *dest)
// {
// (*cur)++;
// }
// else if (*cur == *dest)
// {
// ebx--;
// }
// else
// {
// (*cur)--;
// }
//
// cur++;
// dest++;
// }
//
// MySetPalette(curpal);
// return ebx;
//}
2019-08-26 03:59:14 +00:00
void CinemaFadeIn ( )
{
2019-08-31 07:47:15 +00:00
BlackOut ( ) ;
2019-08-26 03:59:14 +00:00
2019-10-12 22:27:12 +00:00
# ifdef USE_OPENGL
if ( videoGetRenderMode ( ) > = REND_POLYMOST )
2019-08-31 07:47:15 +00:00
{
2019-10-12 22:27:12 +00:00
videoNextPage ( ) ;
return ;
}
# endif
int val ;
do
{
val = DoFadeIn ( ) ;
2019-08-31 07:47:15 +00:00
WaitTicks ( 2 ) ;
2019-08-26 03:59:14 +00:00
2019-10-12 22:27:12 +00:00
// need to page flip in each iteration of the loop for non DOS version
videoNextPage ( ) ;
} while ( val > 0 ) ;
2019-08-26 03:59:14 +00:00
}
void ComputeCinemaText ( int nLine )
{
2019-08-31 07:47:15 +00:00
linecount = 0 ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
while ( 1 )
{
2019-09-20 17:04:02 +00:00
if ( ! strcmp ( gString [ linecount + nLine ] , " END " ) ) {
2019-08-31 07:47:15 +00:00
break ;
}
2019-08-26 03:59:14 +00:00
2019-09-20 17:04:02 +00:00
int nWidth = MyGetStringWidth ( gString [ linecount + nLine ] ) ;
2019-08-31 07:47:15 +00:00
nLeft [ linecount ] = 160 - nWidth / 2 ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
linecount + + ;
}
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
nCrawlY = 199 ;
nHeight = linecount * 10 ;
2019-11-20 16:21:32 +00:00
2020-01-01 10:35:47 +00:00
inputState . ClearAllInput ( ) ;
2019-08-26 03:59:14 +00:00
}
2019-08-31 09:08:38 +00:00
void ReadyCinemaText ( uint16_t nVal )
2019-08-26 03:59:14 +00:00
{
2019-08-31 07:47:15 +00:00
line = FindGString ( " CINEMAS " ) ;
2019-09-20 17:04:02 +00:00
if ( line < 0 ) {
2019-08-31 07:47:15 +00:00
return ;
}
while ( nVal )
{
2019-09-20 17:04:02 +00:00
while ( strcmp ( gString [ line ] , " END " ) ) {
2019-08-31 07:47:15 +00:00
line + + ;
}
line + + ;
nVal - - ;
}
ComputeCinemaText ( line ) ;
2019-08-26 03:59:14 +00:00
}
2020-03-10 00:38:33 +00:00
bool AdvanceCinemaText ( )
2019-08-26 03:59:14 +00:00
{
2020-03-10 00:38:33 +00:00
bool bDoText = nHeight + nCrawlY > 0 ;
2019-08-31 07:47:15 +00:00
2020-03-10 00:38:33 +00:00
if ( bDoText | | CDplaying ( ) )
2019-08-31 07:47:15 +00:00
{
2020-03-10 00:38:33 +00:00
nextclock = ( int ) totalclock + 15 ; // NOTE: Value was 14 in original code but seems a touch too fast now
2019-08-31 07:47:15 +00:00
2020-03-10 00:38:33 +00:00
if ( bDoText )
2019-08-31 07:47:15 +00:00
{
2019-09-20 17:04:02 +00:00
short y = nCrawlY ;
2020-03-10 00:38:33 +00:00
int i = 0 ;
2019-08-31 07:47:15 +00:00
2020-03-10 00:38:33 +00:00
while ( i < linecount & & y < = 199 )
2019-08-31 07:47:15 +00:00
{
2019-09-20 17:04:02 +00:00
if ( y > = - 10 ) {
2020-05-23 12:36:35 +00:00
myprintext ( nLeft [ i ] , y , gString [ line + i ] , 0 , currentCinemaPalette ) ;
2019-08-31 07:47:15 +00:00
}
2020-03-10 00:38:33 +00:00
i + + ;
2019-08-31 07:47:15 +00:00
y + = 10 ;
}
nCrawlY - - ;
}
while ( 1 )
{
2019-08-31 15:04:06 +00:00
HandleAsync ( ) ;
2019-08-31 07:47:15 +00:00
2019-12-25 23:21:04 +00:00
if ( inputState . CheckAllInput ( ) )
2019-11-24 12:59:36 +00:00
{
2019-08-31 07:47:15 +00:00
break ;
}
2020-03-10 00:38:33 +00:00
if ( nextclock < = ( int ) totalclock ) {
return true ;
2019-08-31 07:47:15 +00:00
}
}
}
2020-03-10 00:38:33 +00:00
return false ;
2019-08-26 03:59:14 +00:00
}
void DoCinemaText ( short nVal )
{
2019-08-31 07:47:15 +00:00
ReadyCinemaText ( nVal ) ;
2019-08-26 03:59:14 +00:00
2020-03-10 00:38:33 +00:00
bool bContinue = true ;
while ( bContinue )
2019-08-31 07:47:15 +00:00
{
2020-05-23 12:36:35 +00:00
overwritesprite ( 0 , 0 , cinematile , 0 , 2 , kPalNormal , currentCinemaPalette ) ;
2019-08-26 03:59:14 +00:00
2020-03-10 00:38:33 +00:00
bContinue = AdvanceCinemaText ( ) ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
WaitVBL ( ) ;
videoNextPage ( ) ;
}
2019-08-26 03:59:14 +00:00
}
void GoToTheCinema ( int nVal )
{
2019-08-31 07:47:15 +00:00
switch ( nVal - 1 )
{
default :
return ;
case 0 :
{
cinematile = 3454 ;
break ;
}
case 1 :
{
cinematile = 3452 ;
break ;
}
case 2 :
{
cinematile = 3449 ;
break ;
}
case 3 :
{
cinematile = 3445 ;
break ;
}
case 4 :
{
cinematile = 3451 ;
break ;
}
case 5 :
{
cinematile = 3448 ;
break ;
}
case 6 :
{
cinematile = 3446 ;
break ;
}
}
2020-05-23 12:36:35 +00:00
currentCinemaPalette = nVal ;
2019-08-31 07:47:15 +00:00
2020-08-18 08:28:19 +00:00
FadeOut ( false ) ;
2019-08-31 07:47:15 +00:00
StopAllSounds ( ) ;
NoClip ( ) ;
2020-05-23 12:36:35 +00:00
overwritesprite ( 0 , 0 , kMovieTile , 100 , 2 , kPalNormal , currentCinemaPalette ) ;
2019-08-31 07:47:15 +00:00
videoNextPage ( ) ;
2019-08-26 03:59:14 +00:00
2019-09-20 17:04:02 +00:00
// int386(16, (const union REGS *)&val, (union REGS *)&val)
2019-08-26 03:59:14 +00:00
2020-05-23 12:36:35 +00:00
overwritesprite ( 0 , 0 , cinematile , 0 , 2 , kPalNormal , currentCinemaPalette ) ;
2019-08-31 07:47:15 +00:00
videoNextPage ( ) ;
CinemaFadeIn ( ) ;
2020-01-01 10:35:47 +00:00
inputState . ClearAllInput ( ) ;
2019-08-31 07:47:15 +00:00
int ebx = - 1 ;
int edx = - 1 ;
switch ( nVal - 1 )
{
default :
WaitAnyKey ( 10 ) ;
break ;
case 0 :
ebx = 4 ;
edx = ebx ;
break ;
case 1 :
ebx = 0 ;
break ;
2019-11-20 16:21:32 +00:00
2019-08-31 07:47:15 +00:00
case 2 :
ebx = 2 ;
edx = ebx ;
break ;
case 3 :
ebx = 7 ;
break ;
case 4 :
ebx = 3 ;
edx = ebx ;
break ;
case 5 :
ebx = 8 ;
edx = ebx ;
break ;
case 6 :
ebx = 6 ;
edx = ebx ;
break ;
}
if ( ebx ! = - 1 )
{
if ( edx ! = - 1 )
{
2019-09-20 17:04:02 +00:00
if ( CDplaying ( ) ) {
2019-08-31 07:47:15 +00:00
fadecdaudio ( ) ;
}
2019-11-28 20:40:17 +00:00
playCDtrack ( edx + 2 , false ) ;
2019-08-31 07:47:15 +00:00
}
DoCinemaText ( ebx ) ;
}
2020-08-18 08:28:19 +00:00
FadeOut ( true ) ;
2019-08-31 07:47:15 +00:00
2020-05-23 12:36:35 +00:00
overwritesprite ( 0 , 0 , kMovieTile , 100 , 2 , kPalNormal , currentCinemaPalette ) ;
2019-08-31 07:47:15 +00:00
videoNextPage ( ) ;
GrabPalette ( ) ;
2019-12-14 00:33:26 +00:00
// quit the game if we've finished level 4 and displayed the advert text
if ( ISDEMOVER & & nVal = = 3 ) {
ExitGame ( ) ;
}
2019-08-26 03:59:14 +00:00
}
2019-11-01 22:05:32 +00:00
short nBeforeScene [ ] = { 0 , 0 , 0 , 0 , 0 , 3 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
2019-08-26 03:59:14 +00:00
void CheckBeforeScene ( int nLevel )
{
2019-08-31 07:47:15 +00:00
if ( nLevel = = kMap20 )
{
DoLastLevelCinema ( ) ;
return ;
}
2019-11-01 22:05:32 +00:00
short nScene = nBeforeScene [ nLevel ] ;
if ( nScene )
2019-08-31 07:47:15 +00:00
{
2019-11-01 22:05:32 +00:00
if ( ! nCinemaSeen [ nScene ] )
2019-08-31 07:47:15 +00:00
{
2019-11-01 22:05:32 +00:00
GoToTheCinema ( nScene ) ;
nCinemaSeen [ nScene ] = 1 ;
2019-08-31 07:47:15 +00:00
}
}
2019-08-26 03:59:14 +00:00
}
2020-08-21 20:30:51 +00:00
int SyncScreenJob ( ) ;
2019-08-26 03:59:14 +00:00
int showmap ( short nLevel , short nLevelNew , short nLevelBest )
{
2019-08-31 07:47:15 +00:00
FadeOut ( 0 ) ;
EraseScreen ( overscanindex ) ;
GrabPalette ( ) ;
BlackOut ( ) ;
2019-08-26 03:59:14 +00:00
2019-09-20 17:04:02 +00:00
if ( nLevelNew ! = 11 ) {
2019-08-31 07:47:15 +00:00
CheckBeforeScene ( nLevelNew ) ;
}
2019-08-26 03:59:14 +00:00
2020-08-21 20:30:51 +00:00
int selectedLevel ;
menu_DrawTheMap ( nLevel , nLevelNew , nLevelBest , [ & ] ( int lev ) {
gamestate = GS_LEVEL ;
selectedLevel = lev ;
} ) ;
SyncScreenJob ( ) ;
2019-09-20 17:04:02 +00:00
if ( selectedLevel = = 11 ) {
2019-08-31 07:47:15 +00:00
CheckBeforeScene ( selectedLevel ) ;
}
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
return selectedLevel ;
2019-08-26 03:59:14 +00:00
}
void DoAfterCinemaScene ( int nLevel )
{
2019-11-27 23:50:29 +00:00
short nAfterScene [ ] = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 5 , 0 , 0 , 0 , 0 , 7 , 0 , 0 , 0 , 0 , 6 } ;
2019-08-26 03:59:14 +00:00
2019-11-27 23:50:29 +00:00
if ( nAfterScene [ nLevel ] ) {
GoToTheCinema ( nAfterScene [ nLevel ] ) ;
2019-08-31 07:47:15 +00:00
}
2019-08-26 03:59:14 +00:00
}
void DoFailedFinalScene ( )
{
2019-08-31 07:47:15 +00:00
videoSetViewableArea ( 0 , 0 , xdim - 1 , ydim - 1 ) ;
2019-08-26 03:59:14 +00:00
2019-09-20 17:04:02 +00:00
if ( CDplaying ( ) ) {
2019-08-31 07:47:15 +00:00
fadecdaudio ( ) ;
}
2019-08-26 03:59:14 +00:00
2019-11-28 20:40:17 +00:00
playCDtrack ( 9 , false ) ;
2019-08-31 07:47:15 +00:00
FadeToWhite ( ) ;
2019-08-26 03:59:14 +00:00
2019-11-27 23:50:29 +00:00
GoToTheCinema ( 4 ) ;
2019-08-26 03:59:14 +00:00
}
int FindGString ( const char * str )
{
2019-08-31 07:47:15 +00:00
int i = 0 ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
while ( 1 )
{
if ( ! strcmp ( gString [ i ] , str ) )
return i + 1 ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
if ( ! strcmp ( gString [ i ] , " EOF " ) )
break ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
i + + ;
}
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
return - 1 ;
2019-08-26 03:59:14 +00:00
}
2019-08-31 07:47:15 +00:00
uint8_t CheckForEscape ( )
2019-08-26 03:59:14 +00:00
{
2020-01-01 10:35:47 +00:00
return inputState . CheckAllInput ( ) ;
2019-08-26 03:59:14 +00:00
}
void DoStatic ( int a , int b )
{
2019-09-20 17:04:02 +00:00
RandomLong ( ) ; // nothing done with the result of this?
2019-08-26 03:59:14 +00:00
2019-11-24 12:59:36 +00:00
auto pixels = TileFiles . tileMakeWritable ( kTileLoboLaptop ) ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
int v2 = 160 - a / 2 ;
2019-09-20 17:04:02 +00:00
int v4 = 81 - b / 2 ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
int var_18 = v2 + a ;
2019-09-20 17:04:02 +00:00
int v5 = v4 + b ;
2019-08-26 03:59:14 +00:00
2019-11-24 12:59:36 +00:00
auto pTile = ( pixels + ( 200 * v2 ) ) + v4 ;
2019-08-26 03:59:14 +00:00
2019-12-02 16:46:57 +00:00
tileInvalidate ( kTileLoboLaptop , - 1 , - 1 ) ;
2019-08-31 07:47:15 +00:00
while ( v2 < var_18 )
{
uint8_t * pStart = pTile ;
pTile + = 200 ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
int v7 = v4 ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
while ( v7 < v5 )
{
* pStart = RandomBit ( ) * 16 ;
2019-11-20 16:21:32 +00:00
2019-08-31 07:47:15 +00:00
v7 + + ;
pStart + + ;
}
v2 + + ;
}
2019-08-26 03:59:14 +00:00
2019-11-24 12:59:36 +00:00
tileInvalidate ( kTileLoboLaptop , 0 , 0 ) ;
2019-08-31 07:47:15 +00:00
overwritesprite ( 0 , 0 , kTileLoboLaptop , 0 , 2 , kPalNormal ) ;
videoNextPage ( ) ;
2019-08-26 03:59:14 +00:00
}
void DoLastLevelCinema ( )
{
2019-08-31 07:47:15 +00:00
FadeOut ( 0 ) ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
videoSetViewableArea ( 0 , 0 , xdim - 1 , ydim - 1 ) ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
EraseScreen ( - 1 ) ;
RestorePalette ( ) ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
int nString = FindGString ( " LASTLEVEL " ) ;
2019-08-26 03:59:14 +00:00
2020-02-23 19:40:45 +00:00
PlayLocalSound ( StaticSound [ kSound75 ] , 0 , false , CHANF_UI ) ;
2019-08-26 03:59:14 +00:00
2019-11-24 12:59:36 +00:00
auto pixels = TileFiles . tileMakeWritable ( kTileLoboLaptop ) ;
// uh, what?
//memcpy((void*)waloff[kTileLoboLaptop], (void*)waloff[kTileLoboLaptop], tilesiz[kTileLoboLaptop].x * tilesiz[kTileLoboLaptop].y);
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
int var_24 = 16 ;
int var_28 = 12 ;
2019-08-26 03:59:14 +00:00
2019-09-06 05:18:12 +00:00
int nEndTime = ( int ) totalclock + 240 ;
2019-08-26 03:59:14 +00:00
2019-11-24 12:59:36 +00:00
while ( inputState . keyBufferWaiting ( ) ) {
inputState . keyGetChar ( ) ;
2019-08-31 07:47:15 +00:00
}
2019-08-26 03:59:14 +00:00
2019-09-06 05:18:12 +00:00
while ( nEndTime > ( int ) totalclock )
2019-08-31 07:47:15 +00:00
{
2019-08-31 15:04:06 +00:00
HandleAsync ( ) ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
if ( var_24 > = 116 )
{
if ( var_28 < 192 )
var_28 + = 20 ;
}
else
{
var_24 + = 20 ;
}
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
DoStatic ( var_28 , var_24 ) ;
2019-12-02 14:05:37 +00:00
// WaitVBL();
int time = ( int ) totalclock + 4 ;
while ( ( int ) totalclock < time ) {
HandleAsync ( ) ;
}
2019-08-31 07:47:15 +00:00
}
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
// loc_3AD75
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
do
2019-12-02 14:05:37 +00:00
{
LABEL_11 :
2019-08-31 15:04:06 +00:00
HandleAsync ( ) ;
2019-12-02 14:05:37 +00:00
2019-08-31 07:47:15 +00:00
if ( strlen ( gString [ nString ] ) = = 0 )
break ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
int esi = nString ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
while ( strlen ( gString [ esi ] ) ! = 0 )
esi + + ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
int ebp = esi ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
ebp - = nString ;
2019-12-02 15:15:45 +00:00
ebp < < = 2 ;
ebp = 81 - ebp ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
int var_1C = esi - nString ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
// loc_3ADD7
while ( 1 )
{
2019-08-31 15:04:06 +00:00
HandleAsync ( ) ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
if ( strlen ( gString [ nString ] ) = = 0 )
break ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
int xPos = 70 ;
2019-11-20 16:21:32 +00:00
2019-08-31 07:47:15 +00:00
const char * nChar = gString [ nString ] ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
nString + + ;
2019-08-26 03:59:14 +00:00
2019-11-24 12:59:36 +00:00
TileFiles . tileMakeWritable ( kTileLoboLaptop ) ;
2019-08-31 07:47:15 +00:00
while ( * nChar )
{
2019-08-31 15:04:06 +00:00
HandleAsync ( ) ;
2019-08-26 03:59:14 +00:00
2019-09-20 17:04:02 +00:00
if ( * nChar ! = ' ' ) {
2020-02-23 19:40:45 +00:00
PlayLocalSound ( StaticSound [ kSound71 ] , 0 , false , CHANF_UI ) ;
2019-08-31 07:47:15 +00:00
}
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
xPos + = CopyCharToBitmap ( * nChar , kTileLoboLaptop , xPos , ebp ) ;
nChar + + ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
overwritesprite ( 0 , 0 , kTileLoboLaptop , 0 , 2 , kPalNormal ) ;
videoNextPage ( ) ;
2019-08-26 03:59:14 +00:00
2019-12-02 14:05:37 +00:00
// WaitVBL();
int time = ( int ) totalclock + 4 ;
while ( ( int ) totalclock < time ) {
HandleAsync ( ) ;
}
2019-08-31 07:47:15 +00:00
if ( CheckForEscape ( ) )
goto LABEL_28 ;
}
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
ebp + = 8 ;
}
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
nString + + ;
2019-08-26 03:59:14 +00:00
2020-01-01 10:35:47 +00:00
inputState . ClearAllInput ( ) ;
2019-08-26 03:59:14 +00:00
2019-12-02 14:05:37 +00:00
int v11 = ( kTimerTicks * ( var_1C + 2 ) ) + ( int ) totalclock ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
do
{
2019-08-31 15:04:06 +00:00
HandleAsync ( ) ;
2019-08-26 03:59:14 +00:00
2019-09-06 05:18:12 +00:00
if ( v11 < = ( int ) totalclock )
2019-08-31 07:47:15 +00:00
goto LABEL_11 ;
2019-11-24 12:59:36 +00:00
} while ( ! inputState . keyBufferWaiting ( ) ) ;
2019-11-20 16:21:32 +00:00
}
2019-11-24 12:59:36 +00:00
while ( inputState . keyGetChar ( ) ! = 27 ) ;
2019-08-26 03:59:14 +00:00
LABEL_28 :
2020-02-23 19:40:45 +00:00
PlayLocalSound ( StaticSound [ kSound75 ] , 0 , false , CHANF_UI ) ;
2019-08-26 03:59:14 +00:00
2019-12-02 14:05:37 +00:00
nEndTime = ( int ) totalclock + 240 ;
while ( nEndTime > ( int ) totalclock )
2019-08-31 07:47:15 +00:00
{
2019-08-31 15:04:06 +00:00
HandleAsync ( ) ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
DoStatic ( var_28 , var_24 ) ;
2019-08-26 03:59:14 +00:00
2019-12-02 14:05:37 +00:00
// WaitVBL();
int time = ( int ) totalclock + 4 ;
while ( ( int ) totalclock < time ) {
HandleAsync ( ) ;
}
2019-09-20 17:04:02 +00:00
if ( var_28 > 20 ) {
2019-08-31 07:47:15 +00:00
var_28 - = 20 ;
continue ;
}
2019-08-26 03:59:14 +00:00
2019-09-20 17:04:02 +00:00
if ( var_24 > 20 ) {
2019-08-31 07:47:15 +00:00
var_24 - = 20 ;
continue ;
}
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
break ;
}
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
EraseScreen ( - 1 ) ;
tileLoad ( kTileLoboLaptop ) ;
FadeOut ( 0 ) ;
2019-08-26 03:59:14 +00:00
}
2019-12-26 21:00:04 +00:00
static SavegameHelper sgh ( " menu " ,
SA ( nCinemaSeen ) ,
2019-12-27 09:52:40 +00:00
SA ( energytile ) ,
SV ( nButtonColor ) ,
SV ( word_9AB5B ) ,
2019-12-26 21:00:04 +00:00
nullptr ) ;
2019-11-22 23:11:37 +00:00
END_PS_NS