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"
2019-09-20 17:04:02 +00:00
# include "typedefs.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 "random.h"
# include "sound.h"
# include "names.h"
# include "init.h"
2019-11-24 09:03:19 +00:00
# include "ps_input.h"
2019-09-20 17:04:02 +00:00
# include "gun.h"
2019-08-26 03:59:14 +00:00
# include "view.h"
2019-09-20 17:04:02 +00:00
# include "object.h"
# include "light.h"
# include "cd.h"
2020-02-23 19:40:45 +00:00
# include "s_soundinternal.h"
2019-12-14 11:39:18 +00:00
# include "menu/menu.h"
2020-01-05 09:48:44 +00:00
# include "v_2ddrawer.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 ] ;
// this might be static within the DoPlasma function?
2019-11-24 15:34:23 +00:00
uint8_t * PlasmaBuffer ;
2019-08-26 03:59:14 +00:00
2019-11-18 22:15:48 +00:00
uint8_t energytile [ 66 * 66 ] = { 0 } ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
uint8_t cinemapal [ 768 ] ;
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
unsigned int nSmokeBottom ;
unsigned int nSmokeRight ;
unsigned int nSmokeTop ;
unsigned int nSmokeLeft ;
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
int plasma_A [ 5 ] = { 0 } ;
int plasma_B [ 5 ] = { 0 } ;
int plasma_C [ 5 ] = { 0 } ;
2019-08-26 03:59:14 +00:00
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
}
int menu_RandomLong2 ( )
{
2019-08-31 07:47:15 +00:00
int randLong = 0 ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
for ( int i = 0 ; i < 32 ; i + + )
{
int val = menu_RandomBit2 ( ) ;
randLong * = 2 ;
randLong | = val ;
}
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
return randLong ;
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 nPlasmaTile = kTile4092 ;
2019-11-20 18:46:57 +00:00
int nLogoTile ;
2019-08-26 03:59:14 +00:00
2019-09-20 17:04:02 +00:00
# define kPlasmaWidth 320
# define kPlasmaHeight 80
2019-08-26 03:59:14 +00:00
2019-12-25 17:57:08 +00:00
int nextPlasmaTic ;
2019-08-26 03:59:14 +00:00
void menu_DoPlasma ( )
{
2019-12-25 17:57:08 +00:00
int ptile = nPlasmaTile ;
if ( totalclock > = nextPlasmaTic | | ! PlasmaBuffer )
2019-11-24 15:34:23 +00:00
{
2019-12-25 17:57:08 +00:00
nextPlasmaTic = ( int ) totalclock + 4 ;
2019-08-26 03:59:14 +00:00
2019-12-25 17:57:08 +00:00
if ( ! nLogoTile )
nLogoTile = EXHUMED ? kExhumedLogo : kPowerslaveLogo ;
2019-08-26 03:59:14 +00:00
2019-12-25 17:57:08 +00:00
if ( ! PlasmaBuffer )
{
auto pixels = TileFiles . tileCreate ( kTile4092 , kPlasmaWidth , kPlasmaHeight ) ;
memset ( pixels , 96 , kPlasmaWidth * kPlasmaHeight ) ;
2019-08-26 03:59:14 +00:00
2019-12-25 17:57:08 +00:00
PlasmaBuffer = TileFiles . tileCreate ( kTile4093 , kPlasmaWidth , kPlasmaHeight ) ;
memset ( PlasmaBuffer , 96 , kPlasmaWidth * kPlasmaHeight ) ;
2019-08-26 03:59:14 +00:00
2019-12-25 17:57:08 +00:00
nSmokeLeft = 160 - tilesiz [ nLogoTile ] . x / 2 ;
nSmokeRight = nSmokeLeft + tilesiz [ nLogoTile ] . x ;
2019-08-26 03:59:14 +00:00
2019-12-25 17:57:08 +00:00
nSmokeTop = 40 - tilesiz [ nLogoTile ] . y / 2 ;
nSmokeBottom = nSmokeTop + tilesiz [ nLogoTile ] . y - 1 ;
2019-08-26 03:59:14 +00:00
2019-12-25 17:57:08 +00:00
//uint32_t t = time(0) << 16;
//uint32_t t2 = time(0) | t;
2019-12-29 21:47:40 +00:00
nRandom = timerGetTicksU64 ( ) ;
2019-12-25 17:57:08 +00:00
for ( int i = 0 ; i < 5 ; i + + )
{
int logoWidth = tilesiz [ nLogoTile ] . x ;
plasma_C [ i ] = ( nSmokeLeft + rand ( ) % logoWidth ) < < 16 ;
plasma_B [ i ] = ( menu_RandomLong2 ( ) % 327680 ) + 0x10000 ;
2019-08-26 03:59:14 +00:00
2019-12-25 17:57:08 +00:00
if ( menu_RandomBit2 ( ) ) {
plasma_B [ i ] = - plasma_B [ i ] ;
}
plasma_A [ i ] = menu_RandomBit2 ( ) ;
}
2019-08-31 07:47:15 +00:00
}
2019-08-26 03:59:14 +00:00
2019-12-25 17:57:08 +00:00
videoClearScreen ( overscanindex ) ;
2019-08-26 03:59:14 +00:00
2019-11-24 15:34:23 +00:00
2019-12-25 17:57:08 +00:00
uint8_t * plasmapix = const_cast < uint8_t * > ( tilePtr ( nPlasmaTile ) ) ;
uint8_t * r_ebx = plasmapix + 81 ;
const uint8_t * r_edx = tilePtr ( nPlasmaTile ^ 1 ) + 81 ; // flip between value of 4092 and 4093 with xor
2019-08-26 03:59:14 +00:00
2019-12-25 17:57:08 +00:00
for ( int x = 0 ; x < kPlasmaWidth - 2 ; x + + )
// for (int x = 1; x < 318; x++)
2019-08-31 07:47:15 +00:00
{
2019-12-25 17:57:08 +00:00
// for (int y = 1; y < 79; y++)
for ( int y = 0 ; y < kPlasmaHeight - 2 ; y + + )
2019-08-31 07:47:15 +00:00
{
2019-12-25 17:57:08 +00:00
uint8_t al = * r_edx ;
if ( al ! = 96 )
{
if ( al > 158 ) {
* r_ebx = al - 1 ;
}
else {
* r_ebx = 96 ;
}
2019-08-31 07:47:15 +00:00
}
else
{
2019-12-25 17:57:08 +00:00
if ( menu_RandomBit2 ( ) ) {
* r_ebx = * r_edx ;
2019-08-31 07:47:15 +00:00
}
2019-12-25 17:57:08 +00:00
else
{
uint8_t al = * ( r_edx + 1 ) ;
uint8_t cl = * ( r_edx - 1 ) ;
2019-08-31 07:47:15 +00:00
2019-12-25 17:57:08 +00:00
if ( al < = cl ) {
al = cl ;
}
2019-08-31 07:47:15 +00:00
cl = al ;
2019-12-25 17:57:08 +00:00
al = * ( r_edx - 80 ) ;
if ( cl < = al ) {
cl = al ;
}
2019-08-31 07:47:15 +00:00
2019-12-25 17:57:08 +00:00
al = * ( r_edx + 80 ) ;
if ( cl < = al ) {
cl = al ;
}
2019-08-31 07:47:15 +00:00
2019-12-25 17:57:08 +00:00
al = * ( r_edx + 80 ) ;
if ( cl < = al ) {
cl = al ;
}
2019-08-31 07:47:15 +00:00
2019-12-25 17:57:08 +00:00
al = * ( r_edx + 80 ) ;
if ( cl < = al ) {
cl = al ;
}
2019-08-31 07:47:15 +00:00
2019-12-25 17:57:08 +00:00
al = * ( r_edx - 79 ) ;
if ( cl > al ) {
al = cl ;
}
2019-08-31 07:47:15 +00:00
2019-12-25 17:57:08 +00:00
cl = * ( r_edx - 81 ) ;
if ( al < = cl ) {
al = cl ;
}
2019-08-31 07:47:15 +00:00
2019-12-25 17:57:08 +00:00
cl = al ;
if ( al < = 159 ) {
* r_ebx = 96 ;
2019-08-31 07:47:15 +00:00
}
2019-12-25 17:57:08 +00:00
else
{
if ( ! menu_RandomBit2 ( ) ) {
cl - - ;
}
2019-08-31 07:47:15 +00:00
2019-12-25 17:57:08 +00:00
* r_ebx = cl ;
}
2019-08-31 07:47:15 +00:00
}
}
2019-12-25 17:57:08 +00:00
// before restarting inner loop
r_edx + + ;
r_ebx + + ;
2019-08-31 07:47:15 +00:00
}
2019-12-25 17:57:08 +00:00
// before restarting outer loop
r_edx + = 2 ;
r_ebx + = 2 ;
2019-08-31 07:47:15 +00:00
}
2019-12-25 17:57:08 +00:00
auto logopix = tilePtr ( nLogoTile ) ;
2019-08-31 07:47:15 +00:00
2019-12-25 17:57:08 +00:00
for ( int j = 0 ; j < 5 ; j + + )
{
int pB = plasma_B [ j ] ;
int pC = plasma_C [ j ] ;
int badOffset = ( pC > > 16 ) < nSmokeLeft | | ( pC > > 16 ) > = nSmokeRight ;
2019-08-31 07:47:15 +00:00
2019-12-25 17:57:08 +00:00
const uint8_t * ptr3 = ( logopix + ( ( pC > > 16 ) - nSmokeLeft ) * tilesiz [ nLogoTile ] . y ) ;
2019-08-31 07:47:15 +00:00
2019-12-25 17:57:08 +00:00
plasma_C [ j ] + = plasma_B [ j ] ;
2019-08-31 07:47:15 +00:00
2019-12-25 17:57:08 +00:00
if ( ( pB > 0 & & ( plasma_C [ j ] > > 16 ) > = nSmokeRight ) | | ( pB < 0 & & ( plasma_C [ j ] > > 16 ) < = nSmokeLeft ) )
{
int esi = plasma_A [ j ] ;
plasma_B [ j ] = - plasma_B [ j ] ;
plasma_A [ j ] = esi = = 0 ;
}
2019-08-31 07:47:15 +00:00
2019-12-25 17:57:08 +00:00
if ( badOffset )
continue ;
2019-08-31 15:04:06 +00:00
2019-12-25 17:57:08 +00:00
unsigned int nSmokeOffset = 0 ;
2019-11-20 16:21:32 +00:00
2019-12-25 17:57:08 +00:00
if ( plasma_A [ j ] )
{
nSmokeOffset = nSmokeTop ;
2019-08-31 07:47:15 +00:00
2019-12-25 17:57:08 +00:00
while ( nSmokeOffset < nSmokeBottom )
{
uint8_t al = * ptr3 ;
2020-04-11 22:04:02 +00:00
if ( al ! = TRANSPARENT_INDEX & & al ! = 96 ) {
2019-12-25 17:57:08 +00:00
break ;
}
2019-08-31 07:47:15 +00:00
2019-12-25 17:57:08 +00:00
nSmokeOffset + + ;
ptr3 + + ;
2019-08-31 07:47:15 +00:00
}
}
2019-12-25 17:57:08 +00:00
else
{
nSmokeOffset = nSmokeBottom ;
2019-08-31 07:47:15 +00:00
2019-12-25 17:57:08 +00:00
ptr3 + = tilesiz [ nLogoTile ] . y - 1 ;
2019-08-31 07:47:15 +00:00
2019-12-25 17:57:08 +00:00
while ( nSmokeOffset > nSmokeTop )
{
uint8_t al = * ptr3 ;
2020-04-11 22:04:02 +00:00
if ( al ! = TRANSPARENT_INDEX & & al ! = 96 ) {
2019-12-25 17:57:08 +00:00
break ;
}
2019-08-31 07:47:15 +00:00
2019-12-25 17:57:08 +00:00
nSmokeOffset - - ;
ptr3 - - ;
}
2019-08-31 07:47:15 +00:00
}
2019-12-25 17:57:08 +00:00
uint8_t * v28 = plasmapix + ( 80 * ( plasma_C [ j ] > > 16 ) ) ;
v28 [ nSmokeOffset ] = 175 ;
}
2019-08-31 15:04:06 +00:00
2019-12-25 17:57:08 +00:00
tileInvalidate ( nPlasmaTile , - 1 , - 1 ) ;
2019-11-20 16:21:32 +00:00
2019-12-25 17:57:08 +00:00
// flip between tile 4092 and 4093
if ( nPlasmaTile = = kTile4092 ) {
nPlasmaTile = kTile4093 ;
}
else if ( nPlasmaTile = = kTile4093 ) {
nPlasmaTile = kTile4092 ;
}
2019-08-31 07:47:15 +00:00
}
2019-12-25 17:57:08 +00:00
overwritesprite ( 0 , 0 , ptile , 0 , 2 , kPalNormal ) ;
overwritesprite ( 160 , 40 , nLogoTile , 0 , 3 , kPalNormal ) ;
2019-08-31 07:47:15 +00:00
// draw the fire urn/lamp thingies
2019-09-20 17:04:02 +00:00
int dword_9AB5F = ( ( int ) totalclock / 16 ) & 3 ;
2019-08-31 07:47:15 +00:00
2019-09-20 17:04:02 +00:00
overwritesprite ( 50 , 150 , kTile3512 + dword_9AB5F , 0 , 3 , kPalNormal ) ;
2019-08-26 03:59:14 +00:00
overwritesprite ( 270 , 150 , kTile3512 + ( ( dword_9AB5F + 2 ) & 3 ) , 0 , 3 , kPalNormal ) ;
}
2019-10-14 22:28:17 +00:00
int8_t MapLevelOffsets [ ] = { 0 , 50 , 10 , 20 , 0 , 45 , - 20 , 20 , 5 , 0 , - 10 , 10 , 30 , - 20 , 0 , 20 , 0 , 0 , 0 , 0 } ;
2019-08-26 03:59:14 +00:00
struct TILEFRAMEDEF
{
2019-08-31 07:47:15 +00:00
short nTile ;
short xOffs ;
short yOffs ;
2019-08-26 03:59:14 +00:00
} ;
// 22 bytes
struct MapNamePlaque
{
2019-09-20 17:04:02 +00:00
short xPos ;
short yPos ;
2019-08-31 07:47:15 +00:00
TILEFRAMEDEF tiles [ 2 ] ;
TILEFRAMEDEF text ;
2019-08-26 03:59:14 +00:00
} ;
2019-09-20 17:04:02 +00:00
MapNamePlaque mapNamePlaques [ ] = {
2019-10-14 22:28:17 +00:00
{ 100 , 170 , kTile3376 , 0 , 0 , kTile3377 , 0 , 0 , kTile3411 , 18 , 6 } ,
{ 230 , 10 , kTile3378 , 0 , 0 , kTile3379 , 0 , 0 , kTile3414 , 18 , 6 } , // DENDUR (level 2)
{ 180 , 125 , kTile3380 , 0 , 0 , kTile3381 , 0 , 0 , kTile3417 , 18 , 6 } , // Kalabash
{ 10 , 95 , kTile3382 , 0 , 0 , kTile3383 , 0 , 0 , kTile3420 , 18 , 6 } ,
{ 210 , 160 , kTile3384 , 0 , 0 , kTile3385 , 0 , 0 , kTile3423 , 18 , 6 } ,
{ 10 , 110 , kTile3371 , 0 , 0 , kTile3386 , 0 , 0 , kTile3426 , 18 , 6 } ,
{ 10 , 50 , kTile3387 , 0 , 0 , kTile3388 , 0 , 0 , kTile3429 , 18 , 6 } ,
{ 140 , 0 , kTile3389 , 0 , 0 , kTile3390 , 0 , 0 , kTile3432 , 18 , 6 } ,
{ 30 , 20 , kTile3391 , 0 , 0 , kTile3392 , 0 , 0 , kTile3435 , 18 , 6 } ,
{ 200 , 150 , kTile3409 , 0 , 0 , kTile3410 , 0 , 0 , kTile3418 , 20 , 4 } ,
{ 145 , 170 , kTile3393 , 0 , 0 , kTile3394 , 0 , 0 , kTile3438 , 18 , 6 } ,
{ 80 , 80 , kTile3395 , 0 , 0 , kTile3396 , 0 , 0 , kTile3441 , 18 , 6 } ,
{ 15 , 0 , kTile3397 , 0 , 0 , kTile3398 , 0 , 0 , kTile3444 , 18 , 5 } ,
{ 220 , 35 , kTile3399 , 0 , 0 , kTile3400 , 0 , 0 , kTile3447 , 18 , 6 } ,
{ 190 , 40 , kTile3401 , 0 , 0 , kTile3402 , 0 , 0 , kTile3450 , 18 , 6 } ,
{ 20 , 130 , kTile3403 , 0 , 0 , kTile3404 , 0 , 0 , kTile3453 , 19 , 6 } ,
{ 220 , 160 , kTile3405 , 0 , 0 , kTile3406 , 0 , 0 , kTile3456 , 18 , 6 } ,
{ 20 , 10 , kTile3407 , 0 , 0 , kTile3408 , 0 , 0 , kTile3459 , 18 , 6 } ,
{ 200 , 10 , kTile3412 , 0 , 0 , kTile3413 , 0 , 0 , kTile3419 , 18 , 5 } ,
{ 20 , 10 , kTile3415 , 0 , 0 , kTile3416 , 0 , 0 , kTile3421 , 19 , 4 }
2019-09-20 17:04:02 +00:00
} ;
2019-08-26 03:59:14 +00:00
// 3 different types of fire, each with 4 frames
2019-09-20 17:04:02 +00:00
TILEFRAMEDEF FireTiles [ 3 ] [ 4 ] = {
2019-10-14 22:28:17 +00:00
{ { kTile3484 , 0 , 3 } , { kTile3485 , 0 , 0 } , { kTile3486 , 0 , 3 } , { kTile3487 , 0 , 0 } } ,
{ { kTile3488 , 1 , 0 } , { kTile3489 , 1 , 0 } , { kTile3490 , 0 , 1 } , { kTile3491 , 1 , 1 } } ,
{ { kTile3492 , 1 , 2 } , { kTile3493 , 1 , 0 } , { kTile3494 , 1 , 2 } , { kTile3495 , 1 , 0 } }
2019-09-20 17:04:02 +00:00
} ;
2019-08-26 03:59:14 +00:00
struct Fire
{
2019-08-31 07:47:15 +00:00
short nFireType ;
short xPos ;
short yPos ;
2019-08-26 03:59:14 +00:00
} ;
// 20 bytes
struct MapFire
{
2019-08-31 07:47:15 +00:00
short nFires ;
2019-09-20 17:04:02 +00:00
Fire fires [ 3 ] ;
2019-08-26 03:59:14 +00:00
} ;
/*
level 1 - 3 fires
level 2 - 3 fires
level 3 - 1 fire
*/
2019-09-20 17:04:02 +00:00
MapFire MapLevelFires [ ] = {
3 , { { 0 , 107 , 95 } , { 1 , 58 , 140 } , { 2 , 28 , 38 } } ,
3 , { { 2 , 240 , 0 } , { 0 , 237 , 32 } , { 1 , 200 , 30 } } ,
2 , { { 2 , 250 , 57 } , { 0 , 250 , 43 } , { 2 , 200 , 70 } } ,
2 , { { 1 , 82 , 59 } , { 2 , 84 , 16 } , { 0 , 10 , 95 } } ,
2 , { { 2 , 237 , 50 } , { 1 , 215 , 42 } , { 1 , 210 , 50 } } ,
3 , { { 0 , 40 , 7 } , { 1 , 75 , 6 } , { 2 , 100 , 10 } } ,
3 , { { 0 , 58 , 61 } , { 1 , 85 , 80 } , { 2 , 111 , 63 } } ,
3 , { { 0 , 260 , 65 } , { 1 , 228 , 0 } , { 2 , 259 , 15 } } ,
2 , { { 0 , 81 , 38 } , { 2 , 58 , 38 } , { 2 , 30 , 20 } } ,
3 , { { 0 , 259 , 49 } , { 1 , 248 , 76 } , { 2 , 290 , 65 } } ,
3 , { { 2 , 227 , 66 } , { 0 , 224 , 98 } , { 1 , 277 , 30 } } ,
2 , { { 0 , 100 , 10 } , { 2 , 48 , 76 } , { 2 , 80 , 80 } } ,
3 , { { 0 , 17 , 2 } , { 1 , 29 , 49 } , { 2 , 53 , 28 } } ,
3 , { { 0 , 266 , 42 } , { 1 , 283 , 99 } , { 2 , 243 , 108 } } ,
2 , { { 0 , 238 , 19 } , { 2 , 240 , 92 } , { 2 , 190 , 40 } } ,
2 , { { 0 , 27 , 0 } , { 1 , 70 , 40 } , { 0 , 20 , 130 } } ,
3 , { { 0 , 275 , 65 } , { 1 , 235 , 8 } , { 2 , 274 , 6 } } ,
3 , { { 0 , 75 , 45 } , { 1 , 152 , 105 } , { 2 , 24 , 68 } } ,
3 , { { 0 , 290 , 25 } , { 1 , 225 , 63 } , { 2 , 260 , 110 } } ,
0 , { { 1 , 20 , 10 } , { 1 , 20 , 10 } , { 1 , 20 , 10 } }
} ;
2019-08-26 03:59:14 +00:00
int menu_DrawTheMap ( int nLevel , int nLevelNew , int nLevelBest )
{
2019-08-31 07:47:15 +00:00
int i ;
2019-09-20 17:04:02 +00:00
int x = 0 ;
int var_2C = 0 ;
2019-10-14 22:28:17 +00:00
int nIdleSeconds = 0 ;
2019-08-31 07:47:15 +00:00
int bFadeDone = kFalse ;
2019-08-26 03:59:14 +00:00
2019-09-06 05:18:12 +00:00
int startTime = ( int ) totalclock ;
2019-08-26 03:59:14 +00:00
2020-01-01 10:35:47 +00:00
inputState . ClearAllInput ( ) ;
2019-08-31 07:47:15 +00:00
UnMaskStatus ( ) ;
videoSetViewableArea ( 0 , 0 , xdim - 1 , ydim - 1 ) ;
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
// 0-offset the level numbers
nLevel - - ;
nLevelNew - - ;
nLevelBest - - ;
2019-08-26 03:59:14 +00:00
2019-10-14 22:28:17 +00:00
if ( nLevel > = kMap20 ) { // max single player levels
2019-08-31 07:47:15 +00:00
return - 1 ;
}
2019-08-26 03:59:14 +00:00
2019-10-14 22:28:17 +00:00
if ( nLevelNew > = kMap20 ) {
2019-08-31 07:47:15 +00:00
return - 1 ;
}
2019-09-20 17:04:02 +00:00
if ( nLevel < 0 ) {
2019-08-31 07:47:15 +00:00
nLevel = 0 ;
}
2019-09-20 17:04:02 +00:00
if ( nLevelNew < 0 ) {
2019-08-31 07:47:15 +00:00
nLevelNew = nLevel ;
}
2019-10-14 22:28:17 +00:00
int curYPos = MapLevelOffsets [ nLevel ] + ( 200 * ( nLevel / 2 ) ) ;
int destYPos = MapLevelOffsets [ nLevelNew ] + ( 200 * ( nLevelNew / 2 ) ) ;
2019-08-31 07:47:15 +00:00
2019-10-14 22:28:17 +00:00
if ( curYPos < destYPos ) {
2019-08-31 07:47:15 +00:00
var_2C = 2 ;
}
2019-10-14 22:28:17 +00:00
if ( curYPos > destYPos ) {
2019-08-31 07:47:15 +00:00
var_2C = - 2 ;
}
2019-10-14 22:28:17 +00:00
int runtimer = ( int ) totalclock ;
2020-01-06 20:07:41 +00:00
// Trim smoke in widescreen
vec2_t mapwinxy1 = windowxy1 , mapwinxy2 = windowxy2 ;
int32_t width = mapwinxy2 . x - mapwinxy1 . x + 1 , height = mapwinxy2 . y - mapwinxy1 . y + 1 ;
if ( 3 * width > 4 * height )
{
mapwinxy1 . x + = ( width - 4 * height / 3 ) / 2 ;
mapwinxy2 . x - = ( width - 4 * height / 3 ) / 2 ;
}
2019-10-14 22:28:17 +00:00
// User has 12 seconds to do something on the map screen before loading the current level
while ( nIdleSeconds < 12 )
2019-08-31 07:47:15 +00:00
{
2019-08-31 15:04:06 +00:00
HandleAsync ( ) ;
2020-01-05 09:48:44 +00:00
twod - > ClearScreen ( ) ;
2019-08-31 07:47:15 +00:00
2019-09-06 05:18:12 +00:00
if ( ( ( int ) totalclock - startTime ) / kTimerTicks )
2019-08-31 07:47:15 +00:00
{
2019-10-14 22:28:17 +00:00
nIdleSeconds + + ;
2019-09-06 05:18:12 +00:00
startTime = ( int ) totalclock ;
2019-08-31 07:47:15 +00:00
}
2019-10-14 22:28:17 +00:00
int tileY = curYPos ;
2019-08-31 07:47:15 +00:00
// Draw the background screens
for ( i = 0 ; i < 10 ; i + + )
{
overwritesprite ( x , tileY , kTile3353 + i , 0 , 2 , kPalNormal ) ;
tileY - = 200 ;
}
// for each level - drawing the 'level completed' on-fire smoke markers
for ( i = 0 ; i < kMap20 ; i + + )
{
int screenY = ( i > > 1 ) * - 200 ;
2019-09-20 17:04:02 +00:00
if ( nLevelBest > = i ) // check if the player has finished this level
2019-08-31 07:47:15 +00:00
{
for ( int j = 0 ; j < MapLevelFires [ i ] . nFires ; j + + )
{
2019-09-06 05:18:12 +00:00
int nFireFrame = ( ( ( int ) totalclock > > 4 ) & 3 ) ;
2019-08-31 07:47:15 +00:00
assert ( nFireFrame > = 0 & & nFireFrame < 4 ) ;
int nFireType = MapLevelFires [ i ] . fires [ j ] . nFireType ;
assert ( nFireType > = 0 & & nFireType < 3 ) ;
2019-09-20 17:04:02 +00:00
int nTile = FireTiles [ nFireType ] [ nFireFrame ] . nTile ;
2019-08-31 07:47:15 +00:00
int smokeX = MapLevelFires [ i ] . fires [ j ] . xPos + FireTiles [ nFireType ] [ nFireFrame ] . xOffs ;
2019-10-14 22:28:17 +00:00
int smokeY = MapLevelFires [ i ] . fires [ j ] . yPos + FireTiles [ nFireType ] [ nFireFrame ] . yOffs + curYPos + screenY ;
2019-08-31 07:47:15 +00:00
2020-01-06 20:07:41 +00:00
// Use rotatesprite to trim smoke in widescreen
rotatesprite ( smokeX < < 16 , smokeY < < 16 , 65536L , 0 ,
nTile , 0 , kPalNormal , 16 + 2 , mapwinxy1 . x , mapwinxy1 . y , mapwinxy2 . x , mapwinxy2 . y ) ;
// overwritesprite(smokeX, smokeY, nTile, 0, 2, kPalNormal);
2019-08-31 07:47:15 +00:00
}
}
2019-09-06 05:18:12 +00:00
int t = ( ( ( ( int ) totalclock & 16 ) > > 4 ) ) ;
2019-08-31 07:47:15 +00:00
int nTile = mapNamePlaques [ i ] . tiles [ t ] . nTile ;
int nameX = mapNamePlaques [ i ] . xPos + mapNamePlaques [ i ] . tiles [ t ] . xOffs ;
2019-10-14 22:28:17 +00:00
int nameY = mapNamePlaques [ i ] . yPos + mapNamePlaques [ i ] . tiles [ t ] . yOffs + curYPos + screenY ;
2019-08-31 07:47:15 +00:00
// Draw level name plaque
overwritesprite ( nameX , nameY , nTile , 0 , 2 , kPalNormal ) ;
int8_t shade = 96 ;
if ( nLevelNew = = i )
{
2019-09-06 05:18:12 +00:00
shade = ( Sin ( 16 * ( int ) totalclock ) + 31 ) > > 8 ;
2019-08-31 07:47:15 +00:00
}
else if ( nLevelBest > = i )
{
shade = 31 ;
}
2019-10-14 22:28:17 +00:00
int textY = mapNamePlaques [ i ] . yPos + mapNamePlaques [ i ] . text . yOffs + curYPos + screenY ;
2019-08-31 07:47:15 +00:00
int textX = mapNamePlaques [ i ] . xPos + mapNamePlaques [ i ] . text . xOffs ;
2019-09-20 17:04:02 +00:00
nTile = mapNamePlaques [ i ] . text . nTile ;
2019-08-31 07:47:15 +00:00
// draw the text, alternating between red and black
overwritesprite ( textX , textY , nTile , shade , 2 , kPalNormal ) ;
}
videoNextPage ( ) ;
if ( ! bFadeDone )
{
bFadeDone = kTrue ;
FadeIn ( ) ;
}
2019-10-14 22:28:17 +00:00
if ( curYPos = = destYPos )
2019-08-31 07:47:15 +00:00
{
2019-12-13 23:20:03 +00:00
if ( inputState . GetKeyStatus ( sc_UpArrow ) )
2019-08-31 07:47:15 +00:00
{
2019-12-13 20:13:42 +00:00
inputState . ClearKeyStatus ( sc_UpArrow ) ;
2019-08-31 07:47:15 +00:00
if ( nLevelNew < = nLevelBest )
{
nLevelNew + + ;
2019-10-14 22:28:17 +00:00
assert ( nLevelNew < 20 ) ;
2019-08-31 07:47:15 +00:00
2019-10-14 22:28:17 +00:00
destYPos = MapLevelOffsets [ nLevelNew ] + ( 200 * ( nLevelNew / 2 ) ) ;
2019-08-31 07:47:15 +00:00
2019-10-14 22:28:17 +00:00
if ( curYPos < = destYPos ) {
2019-08-31 07:47:15 +00:00
var_2C = 2 ;
}
2019-09-20 17:04:02 +00:00
else {
2019-08-31 07:47:15 +00:00
var_2C = - 2 ;
}
2019-10-14 22:28:17 +00:00
nIdleSeconds = 0 ;
2019-08-31 07:47:15 +00:00
}
}
2019-12-13 23:20:03 +00:00
if ( inputState . GetKeyStatus ( sc_DownArrow ) )
2019-12-13 20:13:42 +00:00
{
inputState . ClearKeyStatus ( sc_DownArrow ) ;
2019-08-31 07:47:15 +00:00
if ( nLevelNew > 0 )
{
nLevelNew - - ;
2019-10-14 22:28:17 +00:00
assert ( nLevelNew > = 0 ) ;
2019-08-31 07:47:15 +00:00
2019-10-14 22:28:17 +00:00
destYPos = MapLevelOffsets [ nLevelNew ] + ( 200 * ( nLevelNew / 2 ) ) ;
2019-08-31 07:47:15 +00:00
2019-10-14 22:28:17 +00:00
if ( curYPos < = destYPos ) {
2019-08-31 07:47:15 +00:00
var_2C = 2 ;
}
2019-09-20 17:04:02 +00:00
else {
2019-08-31 07:47:15 +00:00
var_2C = - 2 ;
}
2019-10-14 22:28:17 +00:00
nIdleSeconds = 0 ;
2019-08-31 07:47:15 +00:00
}
}
2019-12-25 23:21:04 +00:00
if ( inputState . CheckAllInput ( ) )
2019-08-31 07:47:15 +00:00
{
return nLevelNew + 1 ;
}
}
else
{
2019-10-14 22:28:17 +00:00
// scroll the map every couple of ms
if ( totalclock - runtimer > = ( kTimerTicks / 32 ) ) {
curYPos + = var_2C ;
runtimer = ( int ) totalclock ;
}
2019-12-25 23:21:04 +00:00
if ( inputState . CheckAllInput ( ) )
2019-11-24 12:59:36 +00:00
{
if ( var_2C < 8 ) {
2019-08-31 07:47:15 +00:00
var_2C * = 2 ;
}
}
2019-10-14 22:28:17 +00:00
if ( curYPos > destYPos & & var_2C > 0 ) {
curYPos = destYPos ;
2019-08-31 07:47:15 +00:00
}
2019-10-14 22:28:17 +00:00
if ( curYPos < destYPos & & var_2C < 0 ) {
curYPos = destYPos ;
2019-08-31 07:47:15 +00:00
}
2019-10-14 22:28:17 +00:00
nIdleSeconds = 0 ;
2019-08-31 07:47:15 +00:00
}
}
MySetView ( nViewLeft , nViewTop , nViewRight , nViewBottom ) ;
return nLevelNew + 1 ;
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 ;
// TODO - moveme
int LoadCinemaPalette ( int nPal )
{
2019-08-31 07:47:15 +00:00
nPal - - ;
2019-08-26 03:59:14 +00:00
2019-09-20 17:04:02 +00:00
if ( nPal < 0 | | nPal > = kMaxCinemaPals ) {
2019-08-31 07:47:15 +00:00
return - 2 ;
}
2019-08-26 03:59:14 +00:00
2019-08-31 07:47:15 +00:00
// original code strcpy'd into a buffer first...
2019-08-26 03:59:14 +00:00
2020-04-11 21:54:33 +00:00
auto hFile = fileSystem . OpenFileReader ( cinpalfname [ nPal ] ) ;
2019-11-24 12:59:36 +00:00
if ( ! hFile . isOpen ( ) ) {
2019-08-31 07:47:15 +00:00
return - 2 ;
}
2019-08-26 03:59:14 +00:00
2019-11-24 12:59:36 +00:00
hFile . Read ( cinemapal , sizeof ( cinemapal ) ) ;
2019-11-03 04:00:08 +00:00
for ( auto & c : cinemapal )
c < < = 2 ;
2019-08-31 07:47:15 +00:00
return nPal ;
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
paletteSetColorTable ( ANIMPAL , cinemapal ) ;
2020-01-26 09:58:00 +00:00
videoSetPalette ( 0 , ANIMPAL , Pal_Fullscreen ) ;
2019-10-12 21:09:55 +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-03-10 00:38:33 +00:00
myprintext ( nLeft [ i ] , y , gString [ line + i ] , 0 ) ;
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
{
overwritesprite ( 0 , 0 , cinematile , 0 , 2 , kPalNormal ) ;
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
UnMaskStatus ( ) ;
switch ( nVal - 1 )
{
default :
return ;
case 0 :
{
LoadCinemaPalette ( 1 ) ;
cinematile = 3454 ;
break ;
}
case 1 :
{
LoadCinemaPalette ( 2 ) ;
cinematile = 3452 ;
break ;
}
case 2 :
{
LoadCinemaPalette ( 3 ) ;
cinematile = 3449 ;
break ;
}
case 3 :
{
LoadCinemaPalette ( 4 ) ;
cinematile = 3445 ;
break ;
}
case 4 :
{
LoadCinemaPalette ( 5 ) ;
cinematile = 3451 ;
break ;
}
case 5 :
{
LoadCinemaPalette ( 6 ) ;
cinematile = 3448 ;
break ;
}
case 6 :
{
LoadCinemaPalette ( 7 ) ;
cinematile = 3446 ;
break ;
}
}
2019-12-14 11:39:18 +00:00
#if 0
2019-12-14 00:33:26 +00:00
if ( ISDEMOVER ) {
2019-12-14 11:39:18 +00:00
//???
if ( tilesiz [ cinematile ] . x * tilesiz [ cinematile ] . y = = 0 )
TileFiles . tileCreate ( cinematile , 320 , 200 ) ;
2019-12-14 00:33:26 +00:00
}
2019-12-14 11:39:18 +00:00
# endif
2019-12-14 00:33:26 +00:00
2019-08-31 07:47:15 +00:00
FadeOut ( kFalse ) ;
StopAllSounds ( ) ;
NoClip ( ) ;
2019-11-01 22:05:32 +00:00
overwritesprite ( 0 , 0 , kMovieTile , 100 , 2 , kPalNormal ) ;
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
2019-08-31 07:47:15 +00:00
overwritesprite ( 0 , 0 , cinematile , 0 , 2 , kPalNormal ) ;
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 ) ;
}
FadeOut ( kTrue ) ;
2019-11-28 20:40:17 +00:00
overwritesprite ( 0 , 0 , kMovieTile , 100 , 2 , kPalNormal ) ;
2019-08-31 07:47:15 +00:00
videoNextPage ( ) ;
GrabPalette ( ) ;
Clip ( ) ;
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
}
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
2019-08-31 07:47:15 +00:00
int selectedLevel = menu_DrawTheMap ( nLevel , nLevelNew , nLevelBest ) ;
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 ) ;
UnMaskStatus ( ) ;
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 ) ;
MySetView ( nViewLeft , nViewTop , nViewRight , nViewBottom ) ;
MaskStatus ( ) ;
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