scummvm/engines/cge/cge_main.cpp
2011-06-11 22:35:21 +02:00

2298 lines
43 KiB
C++
Raw Blame History

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 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.
*
*/
/*
* This code is based on original Soltys source code
* Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
*/
#include "cge/general.h"
#include "cge/boot.h"
#include "cge/ident.h"
#include "cge/sound.h"
#include "cge/startup.h"
#include "cge/config.h"
#include "cge/vga13h.h"
#include "cge/snail.h"
#include "cge/text.h"
#include "cge/game.h"
#include "cge/mouse.h"
#include "cge/keybd.h"
#include "cge/cfile.h"
#include "cge/vol.h"
#include "cge/talk.h"
#include "cge/vmenu.h"
#include "cge/gettext.h"
#include "cge/mixer.h"
#include "cge/cge_main.h"
//#include <alloc.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
//#include <dir.h>
#include <fcntl.h>
//#include <bios.h>
#include <io.h>
#include "common/str.h"
namespace CGE {
#define STACK_SIZ (K(2))
#define SVGCHKSUM (1956+Now+OldLev+Game+Music+DemoText)
#ifdef DEMO
#ifdef DEBUG
#define SVG0NAME ("{{INIT}}" SVG_EXT)
#else
#define SVG0NAME (ProgName(SVG_EXT))
#endif
#else
#define SVG0NAME ("{{INIT}}" SVG_EXT)
#endif
#ifdef DEBUG
#define SVG0FILE CFILE
#else
#define SVG0FILE INI_FILE
#endif
extern uint16 _stklen = (STACK_SIZ * 2);
// 0.75 - 17II95 - full sound support
// 0.76 - 18II95 - small MiniEMS in DEMO,
// unhide CavLight in SNLEVEL
// keyclick suppress in startup
// keyclick on key service in: SYSTEM, GET_TEXT
// 1.01 - 17VII95 - default savegame with sound ON
// coditionals EVA for 2-month evaluation version
/*
char Copr[] = "Common Game Engine "
#ifdef EVA
"<22>"
#else
#ifdef CD
"<22>"
#else
" "
#endif
#endif
" version 1.05 ["
#if sizeof(INI_FILE) == sizeof(VFILE)
"I"
#else
"i"
#endif
#if sizeof(PIC_FILE) == sizeof(VFILE)
"B"
#else
"b"
#endif
"]\n"
"Copyright (c) 1994 by Janusz B. Wi$niewski";
*/
char Copr[] = "To be fixed - Copr[]";
static char UsrFnam[15] = "\0ɱ%^<5E><>ȼ<EFBFBD><C8BC><EFBFBD><EFBFBD>";
static int OldLev = 0;
static int DemoText = DEMO_TEXT;
//--------------------------------------------------------------------------
bool JBW = false;
DAC *SysPal = farnew(DAC, PAL_CNT);
//-------------------------------------------------------------------------
SPRITE PocLight = LI;
SPRITE * Pocket[POCKET_NX]={ NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, };
int PocPtr = 0;
//-------------------------------------------------------------------------
//extern SPRITE * PocLight;
//extern SPRITE * Pocket[];
//extern int PocPtr;
//-------------------------------------------------------------------------
MOUSE Mouse;
static SPRITE * Sprite = NULL;
static SPRITE * MiniCave = NULL;
static SPRITE * Shadow = NULL;
static VGA Vga = M13H;
static EMS * Mini = MiniEmm.Alloc((uint16)MINI_EMM_SIZE);
static BMP_PTR * MiniShpList = NULL;
static BMP_PTR MiniShp[] = { NULL, NULL };
static KEYBOARD Keyboard;
static bool Finis = false;
static int Startup = 1;
static int OffUseCount = atoi(Text[OFF_USE_COUNT]);
uint16 *intStackPtr = false;
HXY HeroXY[CAVE_MAX] = {{0,0}};
BAR Barriers[1+CAVE_MAX] = { { 0xFF, 0xFF } };
extern int FindPocket (SPRITE *);
extern DAC StdPal[58];
#ifdef DEBUG
static SPRITE HorzLine = HL;
#endif
void FeedSnail (SPRITE * spr, SNLIST snq); // defined in SNAIL
//--------------------------------------------------------------------------
uint8 CLUSTER::Map[MAP_ZCNT][MAP_XCNT];
uint8 & CLUSTER::Cell (void)
{
return Map[B][A];
}
bool CLUSTER::Protected (void)
{
if (A == Barriers[Now].Vert || B == Barriers[Now].Horz) return true;
// TODO AsM
/*
_DX = (MAP_ZCNT << 8) + MAP_XCNT;
_BX = (uint16) this;
asm mov ax,1
asm mov cl,[bx].(COUPLE)A
asm mov ch,[bx].(COUPLE)B
asm test cx,0x8080 // (A < 0) || (B < 0)
asm jnz xit
asm cmp cl,dl
asm jge xit
asm cmp ch,dh
asm jge xit
// if (A < 0 || A >= MAP_XCNT || B < 0 || B >= MAP_ZCNT) return true;
asm mov al,dl
asm mul ch
asm xor ch,ch
asm add ax,cx
asm mov bx,ax
_BX += (uint16) Map;
//asm add bx,offset CLUSTER::Map
asm mov al,[bx]
asm and ax,0xFF
asm jz xit
asm mov ax,1
// return Map[B][A] != 0;
xit: return _AX;
*/
return TRUE;
}
CLUSTER XZ (int x, int y)
{
if (y < MAP_TOP) y = MAP_TOP;
if (y > MAP_TOP + MAP_HIG - MAP_ZGRID) y = MAP_TOP + MAP_HIG - MAP_ZGRID;
return CLUSTER(x / MAP_XGRID, (y-MAP_TOP) / MAP_ZGRID);
}
CLUSTER XZ (COUPLE xy)
{
signed char x, y;
xy.Split(x, y);
return XZ(x, y);
}
//--------------------------------------------------------------------------
int pocref[POCKET_NX];
uint8 volume[2];
struct SAVTAB { void * Ptr; int Len; uint8 Flg; } SavTab[] =
{{ &Now, sizeof(Now), 1 },
{ &OldLev, sizeof(OldLev), 1 },
{ &DemoText, sizeof(DemoText), 1 },
{ &Game, sizeof(Game), 1 },
{ &Game, sizeof(Game), 1 }, // spare 1
{ &Game, sizeof(Game), 1 }, // spare 2
{ &Game, sizeof(Game), 1 }, // spare 3
{ &Game, sizeof(Game), 1 }, // spare 4
{ &VGA::Mono, sizeof(VGA::Mono), 0 },
{ &Music, sizeof(Music), 1 },
{ volume, sizeof(volume), 1 },
{ Flag, sizeof(Flag), 1 },
{ HeroXY, sizeof(HeroXY), 1 },
{ Barriers, sizeof(Barriers), 1 },
{ pocref, sizeof(pocref), 1 },
{ NULL, 0, 0 } };
static void LoadGame (XFILE& file, bool tiny = false)
{
SAVTAB * st;
SPRITE * spr;
int i;
for (st = SavTab; st->Ptr; st ++)
{
if (file.Error) VGA::Exit("Bad SVG");
file.Read((uint8 *) ((tiny || st->Flg) ? st->Ptr : &i), st->Len);
}
file.Read((uint8 *) &i, sizeof(i));
if (i != SVGCHKSUM) VGA::Exit(BADSVG_TEXT);
if (STARTUP::Core < CORE_HIG) Music = false;
if (STARTUP::SoundOk == 1 && STARTUP::Mode == 0)
{
SNDDrvInfo.VOL2.D = volume[0];
SNDDrvInfo.VOL2.M = volume[1];
SNDSetVolume();
}
if (! tiny) // load sprites & pocket
{
while (! file.Error)
{
SPRITE S(NULL);
uint16 n = file.Read((uint8 *) &S, sizeof(S));
if (n != sizeof(S)) break;
S.Prev = S.Next = NULL;
spr = (scumm_stricmp(S.File+2, "MUCHA") == 0) ? new FLY(NULL)
: new SPRITE(NULL);
if (spr == NULL) VGA::Exit("No core");
*spr = S;
VGA::SpareQ.Append(spr);
}
for (i = 0; i < POCKET_NX; i ++)
{
register int r = pocref[i];
Pocket[i] = (r < 0) ? NULL : VGA::SpareQ.Locate(r);
}
}
}
static void SaveSound (void)
{
CFILE cfg(UsrPath(ProgName(CFG_EXT)), WRI);
if (! cfg.Error) cfg.Write(&SNDDrvInfo,sizeof(SNDDrvInfo)-sizeof(SNDDrvInfo.VOL2));
}
static void SaveGame (XFILE& file)
{
SAVTAB * st;
SPRITE * spr;
int i;
for (i = 0; i < POCKET_NX; i ++)
{
register SPRITE * s = Pocket[i];
pocref[i] = (s) ? s->Ref : -1;
}
volume[0] = SNDDrvInfo.VOL2.D;
volume[1] = SNDDrvInfo.VOL2.M;
for (st = SavTab; st->Ptr; st ++)
{
if (file.Error) VGA::Exit("Bad SVG");
file.Write((uint8 *) st->Ptr, st->Len);
}
file.Write((uint8 *) &(i = SVGCHKSUM), sizeof(i));
for (spr = VGA::SpareQ.First(); spr; spr = spr->Next)
if (spr->Ref >= 1000)
if (!file.Error) file.Write((uint8 *)spr, sizeof(*spr));
}
static void HeroCover (int cvr)
{
SNPOST(SNCOVER, 1, cvr, NULL);
}
static void Trouble (int seq, int txt)
{
Hero->Park();
SNPOST(SNWAIT, -1, -1, Hero);
SNPOST(SNSEQ, -1, seq, Hero);
SNPOST(SNSOUND, -1, 2, Hero);
SNPOST(SNWAIT, -1, -1, Hero);
SNPOST(SNSAY, 1, txt, Hero);
}
static void OffUse (void)
{
Trouble(OFF_USE, OFF_USE_TEXT+new_random(OffUseCount));
}
static void TooFar (void)
{
Trouble(TOO_FAR, TOO_FAR_TEXT);
}
static void NoWay (void)
{
Trouble(NO_WAY, NO_WAY_TEXT);
}
static void LoadHeroXY (void)
{
INI_FILE cf(ProgName(".HXY"));
memset(HeroXY, 0, sizeof(HeroXY));
if (! cf.Error) cf.CFREAD(&HeroXY);
}
static void LoadMapping (void)
{
if (Now <= CAVE_MAX)
{
INI_FILE cf(ProgName(".TAB"));
if (! cf.Error)
{
memset(CLUSTER::Map, 0, sizeof(CLUSTER::Map));
cf.Seek((Now - 1) * sizeof(CLUSTER::Map));
cf.Read((uint8 *) CLUSTER::Map, sizeof(CLUSTER::Map));
}
}
}
//--------------------------------------------------------------------------
CLUSTER Trace[MAX_FIND_LEVEL];
int FindLevel;
WALK::WALK (BMP_PTR * shpl)
: SPRITE(shpl), Dir(NO_DIR), TracePtr(-1)
{
}
void WALK::Tick (void)
{
if (Flags.Hide) return;
Here = XZ(X+W/2, Y+H);
if (Dir != NO_DIR)
{
SPRITE * spr;
SYSTEM::FunTouch();
for (spr = VGA::ShowQ.First(); spr; spr = spr->Next)
{
if (Distance(spr) < 2)
{
if (! spr->Flags.Near)
{
FeedSnail(spr, NEAR);
spr->Flags.Near = true;
}
}
else spr->Flags.Near = false;
}
}
if (Flags.Hold || TracePtr < 0) Park();
else
{
if (Here == Trace[TracePtr])
{
if (-- TracePtr < 0) Park();
}
else
{
signed char dx, dz;
(Trace[TracePtr] - Here).Split(dx, dz);
DIR d = (dx) ? ((dx > 0) ? EE : WW) : ((dz > 0) ? SS : NN);
Turn(d);
}
}
Step();
if ((Dir == WW && X <= 0) ||
(Dir == EE && X + W >= SCR_WID) ||
(Dir == SS && Y + W >= WORLD_HIG-2)) Park();
else
{
signed char x; // dummy var
Here.Split(x, Z); // take current Z position
SNPOST_(SNZTRIM, -1, 0, this); // update Hero's pos in show queue
}
}
int WALK::Distance (SPRITE * spr)
{
int dx, dz;
dx = spr->X - (X+W-WALKSIDE);
if (dx < 0) dx = (X+WALKSIDE) - (spr->X+spr->W);
if (dx < 0) dx = 0;
dx /= MAP_XGRID;
dz = spr->Z - Z;
if (dz < 0) dz = - dz;
dx = dx * dx + dz * dz;
for (dz = 1; dz * dz < dx; dz ++) ;
return dz-1;
}
void WALK::Turn (DIR d)
{
DIR dir = (Dir == NO_DIR) ? SS : Dir;
if (d != Dir)
{
Step((d == dir) ? (1 + dir + dir) : (9 + 4 * dir + d));
Dir = d;
}
}
void WALK::Park (void)
{
if (Time == 0) ++ Time;
if (Dir != NO_DIR)
{
Step(9 + 4 * Dir + Dir);
Dir = NO_DIR;
TracePtr = -1;
}
}
void WALK::FindWay (CLUSTER c)
{
// TODO : Find1Way in ASM
/*
bool Find1Way(void);
extern uint16 Target;
if (c != Here)
{
for (FindLevel = 1; FindLevel <= MAX_FIND_LEVEL; FindLevel ++)
{
signed char x, z;
Here.Split(x, z);
Target = (z << 8) | x;
c.Split(x, z);
_CX = (z << 8) | x;
if (Find1Way()) break;
}
TracePtr = (FindLevel > MAX_FIND_LEVEL) ? -1 : (FindLevel - 1);
if (TracePtr < 0) NoWay();
Time = 1;
}
*/
}
void WALK::FindWay (SPRITE * spr)
{
if (spr && spr != this)
{
int x = spr->X, z = spr->Z;
if (spr->Flags.East) x += spr->W + W/2 - WALKSIDE;
else x -= W/2 - WALKSIDE;
FindWay(CLUSTER((x/MAP_XGRID),
((z < MAP_ZCNT-MAX_DISTANCE) ? (z+1)
: (z-1))));
}
}
bool WALK::Lower (SPRITE * spr)
{
return (spr->Y > Y + (H * 3) / 5);
}
void WALK::Reach (SPRITE * spr, int mode)
{
if (spr)
{
Hero->FindWay(spr);
if (mode < 0)
{
mode = spr->Flags.East;
if (Lower(spr)) mode += 2;
}
}
// note: insert SNAIL commands in reverse order
SNINSERT(SNPAUSE, -1, 64, NULL);
SNINSERT(SNSEQ, -1, TSEQ + mode, this);
if (spr)
{
SNINSERT(SNWAIT, -1, -1, Hero); /////--------$$$$$$$
//SNINSERT(SNWALK, -1, -1, spr);
}
// sequence is not finished,
// now it is just at sprite appear (disappear) point
}
//--------------------------------------------------------------------------
#ifdef DEBUG
class SQUARE : public SPRITE
{
public:
SQUARE (void);
void Touch (uint16 mask, int x, int y);
};
SQUARE::SQUARE (void)
: SPRITE(MB)
{
Flags.Kill = true;
Flags.BDel = false;
}
void SQUARE::Touch (uint16 mask, int x, int y)
{
SPRITE::Touch(mask, x, y);
if (mask & L_UP)
{
XZ(X+x, Y+y).Cell() = 0;
SNPOST_(SNKILL, -1, 0, this);
}
}
static void SetMapBrick (int x, int z)
{
SQUARE * s = new SQUARE;
if (s)
{
static char n[] = "00:00";
s->Goto(x * MAP_XGRID, MAP_TOP + z * MAP_ZGRID);
wtom(x, n+0, 10, 2);
wtom(z, n+3, 10, 2);
CLUSTER::Map[z][x] = 1;
s->SetName(n);
VGA::ShowQ.Insert(s, VGA::ShowQ.First());
}
}
#endif
//--------------------------------------------------------------------------
void dummy (void) { }
static void SwitchMapping (void);
static void SwitchColorMode (void);
static void StartCountDown (void);
Debug(static void SwitchDebug (void); )
static void SwitchMusic (void);
static void KillSprite (void);
static void PushSprite (void);
static void PullSprite (void);
static void BackPaint (void);
static void NextStep (void);
static void SaveMapping (void);
WALK * Hero = NULL;
static INFO_LINE InfoLine = INFO_W;
static HEART Heart;
static SPRITE CavLight = PR;
static void KeyClick (void)
{
SNPOST_(SNSOUND, -1, 5, NULL);
}
static void ResetQSwitch (void)
{
SNPOST_(SNSEQ, 123, 0, NULL);
KeyClick();
}
static void Quit (void)
{
static CHOICE QuitMenu[]={ { NULL, StartCountDown },
{ NULL, ResetQSwitch },
{ NULL, dummy } };
if (Snail.Idle() && ! Hero->Flags.Hide)
{
if (VMENU::Addr)
{
SNPOST_(SNKILL, -1, 0, VMENU::Addr);
ResetQSwitch();
}
else
{
QuitMenu[0].Text = Text[QUIT_TEXT];
QuitMenu[1].Text = Text[NOQUIT_TEXT];
(new VMENU(QuitMenu, -1, -1))->SetName(Text[QUIT_TITLE]);
SNPOST_(SNSEQ, 123, 1, NULL);
KeyClick();
}
}
}
static void AltCtrlDel (void)
{
#if 0
//def DEBUG
if (KEYBOARD::Key[LSHIFT] || KEYBOARD::Key[RSHIFT])
{
PostFlag = 0x1234;
POST();
}
else
#endif
SNPOST_(SNSAY, -1, A_C_D_TEXT, Hero);
}
static void MiniStep (int stp)
{
if (stp < 0) MiniCave->Flags.Hide = true;
else
{
&*Mini;
*MiniShp[0] = *MiniShpList[stp];
if (Fx.Current) &*(Fx.Current->EAddr());
MiniCave->Flags.Hide = false;
}
}
static void PostMiniStep (int stp)
{
static int recent = -2;
//TODO Change the SNPOST message send to a special way to send function pointer
//if (MiniCave && stp != recent) SNPOST_(SNEXEC, -1, recent = stp, (void *)&MiniStep);
}
//--------------------------------------------------------------------------
int SYSTEM::FunDel = HEROFUN0;
void SYSTEM::SetPal (void)
{
int i;
DAC * p = SysPal + 256-ArrayCount(StdPal);
for (i = 0; i < ArrayCount(StdPal); i ++)
{
p[i].R = StdPal[i].R >> 2;
p[i].G = StdPal[i].G >> 2;
p[i].B = StdPal[i].B >> 2;
}
}
void SYSTEM::FunTouch (void)
{
uint16 n = (PAIN) ? HEROFUN1 : HEROFUN0;
if (Talk == NULL || n > FunDel) FunDel = n;
}
static void ShowBak (int ref)
{
SPRITE * spr = VGA::SpareQ.Locate(ref);
if (spr)
{
BITMAP::Pal = SysPal;
spr->Expand();
BITMAP::Pal = NULL;
spr->Show(2);
VGA::CopyPage(1, 2);
SYSTEM::SetPal();
spr->Contract();
}
}
static void CaveUp (void)
{
int BakRef = 1000 * Now;
if (Music) LoadMIDI(Now);
ShowBak(BakRef);
LoadMapping();
Text.Preload(BakRef, BakRef+1000);
SPRITE * spr = VGA::SpareQ.First();
while (spr)
{
SPRITE * n = spr->Next;
if (spr->Cave == Now || spr->Cave == 0)
if (spr->Ref != BakRef)
{
if (spr->Flags.Back) spr->BackShow();
else ExpandSprite(spr);
}
spr = n;
}
if (SNDDrvInfo.DDEV)
{
Sound.Stop();
Fx.Clear();
Fx.Preload(0);
Fx.Preload(BakRef);
}
if (Hero)
{
Hero->Goto(HeroXY[Now-1].X, HeroXY[Now-1].Y);
// following 2 lines trims Hero's Z position!
Hero->Tick();
Hero->Time = 1;
Hero->Flags.Hide = false;
}
if (! Dark) Vga.Sunset();
VGA::CopyPage(0, 1);
SelectPocket(-1);
if (Hero) VGA::ShowQ.Insert(VGA::ShowQ.Remove(Hero));
if (Shadow)
{
VGA::ShowQ.Remove(Shadow);
Shadow->MakeXlat(Glass(SysPal, 204, 204, 204));
VGA::ShowQ.Insert(Shadow, Hero);
Shadow->Z = Hero->Z;
}
FeedSnail(VGA::ShowQ.Locate(BakRef+999), TAKE);
Vga.Show();
Vga.CopyPage(1, 0);
Vga.Show();
Vga.Sunrise(SysPal);
Dark = false;
if (! Startup) Mouse.On();
HEART::Enable = true;
}
static void CaveDown (void)
{
SPRITE * spr;
Debug( if (! HorzLine.Flags.Hide) SwitchMapping(); )
for (spr = VGA::ShowQ.First(); spr; )
{
SPRITE * n = spr->Next;
if (spr->Ref >= 1000 /*&& spr->Cave*/)
{
if (spr->Ref % 1000 == 999) FeedSnail(spr, TAKE);
VGA::SpareQ.Append(VGA::ShowQ.Remove(spr));
}
spr = n;
}
Text.Clear(1000);
}
static void XCave (void)
{
CaveDown();
CaveUp();
}
static void QGame (void)
{
CaveDown();
OldLev = Lev;
SaveSound();
CFILE file = CFILE(UsrPath(UsrFnam), WRI, RCrypt);
SaveGame(file);
Vga.Sunset();
Finis = true;
}
void SwitchCave (int cav)
{
if (cav != Now)
{
HEART::Enable = false;
if (cav < 0)
{
SNPOST(SNLABEL, -1, 0, NULL); // wait for repaint
//TODO Change the SNPOST message send to a special way to send function pointer
//SNPOST(SNEXEC, -1, 0, (void *)&QGame); // switch cave
}
else
{
Now = cav;
Mouse.Off();
if (Hero)
{
Hero->Park();
Hero->Step(0);
#ifndef DEMO
///// protection: auto-destruction on! ----------------------
VGA::SpareQ.Show = STARTUP::Summa * (cav <= CAVE_MAX);
/////--------------------------------------------------------
#endif
}
CavLight.Goto(CAVE_X + ((Now-1) % CAVE_NX) * CAVE_DX + CAVE_SX,
CAVE_Y + ((Now-1) / CAVE_NX) * CAVE_DY + CAVE_SY);
KillText();
if (! Startup) KeyClick();
SNPOST(SNLABEL, -1, 0, NULL); // wait for repaint
//TODO Change the SNPOST message send to a special way to send function pointer
//SNPOST(SNEXEC, 0, 0, (void *)&XCave); // switch cave
}
}
}
void SYSTEM::Touch (uint16 mask, int x, int y)
{
static int pp = 0;
void SwitchCave (int cav);
int cav = 0;
FunTouch();
if (mask & KEYB)
{
int pp0;
KeyClick();
KillText();
if (Startup == 1)
{
SNPOST(SNCLEAR, -1, 0, NULL);
return;
}
pp0 = pp;
switch (x)
{
case Del : if (KEYBOARD::Key[ALT] &&
KEYBOARD::Key[CTRL]) AltCtrlDel();
Debug ( else KillSprite(); )
break;
case 'F' : if (KEYBOARD::Key[ALT])
{
SPRITE * m = VGA::ShowQ.Locate(17001);
if (m)
{
m->Step(1);
m->Time = 216; // 3s
}
}
break;
#ifdef DEBUG
case PgUp : PushSprite(); break;
case PgDn : PullSprite(); break;
case '+' : NextStep(); break;
case '`' : if (KEYBOARD::Key[ALT]) SaveMapping(); else SwitchMapping(); break;
case F1 : SwitchDebug(); break;
case F3 : Hero->Step(TSEQ + 4); break;
case F4 : Hero->Step(TSEQ + 5); break;
case F5 : Hero->Step(TSEQ + 0); break;
case F6 : Hero->Step(TSEQ + 1); break;
case F7 : Hero->Step(TSEQ + 2); break;
case F8 : Hero->Step(TSEQ + 3); break;
case F9 : SYSTEM::FunDel = 1; break;
case 'X' : if (KEYBOARD::Key[ALT]) Finis = true; break;
case '0' :
case '1' :
case '2' :
case '3' :
case '4' : if (KEYBOARD::Key[ALT]) { SNPOST(SNLEVEL, -1, x - '0', NULL); break; }
case '5' :
case '6' :
case '7' :
case '8' :
case '9' : if (Sprite) Sprite->Step(x - '0'); break;
#else
case '1' :
case '2' :
case '3' :
case '4' :
case '5' :
case '6' :
case '7' :
case '8' : SelectPocket(x - '1'); break;
#endif
case F10 : if (Snail.Idle() && ! Hero->Flags.Hide)
StartCountDown();
break;
case 'J' : if (pp == 0) ++ pp; break;
case 'B' : if (pp == 1) ++ pp; break;
case 'W' : if (pp == 2) JBW = !JBW; break;
}
if (pp == pp0) pp = 0;
}
else
{
if (Startup) return;
InfoLine.Update(NULL);
if (y >= WORLD_HIG)
{
if (x < BUTTON_X) // select cave?
{
if (y >= CAVE_Y && y < CAVE_Y + CAVE_NY * CAVE_DY &&
x >= CAVE_X && x < CAVE_X + CAVE_NX * CAVE_DX && ! Game)
{
cav = ((y-CAVE_Y) / CAVE_DY) * CAVE_NX + (x-CAVE_X) / CAVE_DX + 1;
if (cav > MaxCave) cav = 0;
}
else
{
cav = 0;
}
}
else if (mask & L_UP)
{
if (y >= POCKET_Y && y < POCKET_Y + POCKET_NY * POCKET_DY &&
x >= POCKET_X && x < POCKET_X + POCKET_NX * POCKET_DX)
{
int n = ((y-POCKET_Y) / POCKET_DY) * POCKET_NX + (x-POCKET_X) / POCKET_DX;
SelectPocket(n);
}
}
}
PostMiniStep(cav-1);
if (mask & L_UP)
{
if (cav && Snail.Idle() && Hero->TracePtr < 0)
{
SwitchCave(cav);
}
#ifdef DEBUG
if (! HorzLine.Flags.Hide)
{
if (y >= MAP_TOP && y < MAP_TOP+MAP_HIG)
{
signed char x1, z1;
XZ(x, y).Split(x1, z1);
CLUSTER::Map[z1][x1] = 1;
SetMapBrick(x1, z1);
}
}
else
#endif
{
if (! Talk && Snail.Idle() && Hero
&& y >= MAP_TOP && y < MAP_TOP+MAP_HIG && ! Game)
{
Hero->FindWay(XZ(x, y));
}
}
}
}
}
void SYSTEM::Tick (void)
{
if (! Startup) if (-- FunDel == 0)
{
KillText();
if (Snail.Idle())
{
if (PAIN) HeroCover(9);
else if (STARTUP::Core >= CORE_MID)
{
int n = new_random(100);
if (n > 96) HeroCover(6+(Hero->X+Hero->W/2 < SCR_WID/2));
else
{
if (n > 90) HeroCover(5);
else
{
if (n > 60) HeroCover(4);
else HeroCover(3);
}
}
}
}
FunTouch();
}
Time = SYSTIMERATE;
}
//--------------------------------------------------------------------------
/*
static void SpkOpen (void)
{
asm in al,0x61
asm or al,0x03
asm out 0x61,al
asm mov al,0x90
asm out 0x43,al
}
static void SpkClose (void)
{
asm in al,0x61
asm and al,0xFC
asm out 0x61,al
}
*/
static void SwitchColorMode (void)
{
SNPOST_(SNSEQ, 121, VGA::Mono = ! VGA::Mono, NULL);
KeyClick();
VGA::SetColors(SysPal, 64);
}
static void SwitchMusic (void)
{
if (KEYBOARD::Key[ALT])
{
if (VMENU::Addr) SNPOST_(SNKILL, -1, 0, VMENU::Addr);
else
{
SNPOST_(SNSEQ, 122, (Music = false), NULL);
//TODO Change the SNPOST message send to a special way to send function pointer
// SNPOST(SNEXEC, -1, 0, (void *)&SelectSound);
}
}
else
{
if (STARTUP::Core < CORE_HIG) SNPOST(SNINF, -1, NOMUSIC_TEXT, NULL);
else
{
SNPOST_(SNSEQ, 122, (Music = ! Music), NULL);
KeyClick();
}
}
if (Music) LoadMIDI(Now);
else KillMIDI();
}
static void StartCountDown (void)
{
//SNPOST(SNSEQ, 123, 0, NULL);
SwitchCave(-1);
}
#ifndef DEMO
static void TakeName (void)
{
if (GET_TEXT::Ptr) SNPOST_(SNKILL, -1, 0, GET_TEXT::Ptr);
else
{
GET_TEXT * tn = new GET_TEXT(Text[GETNAME_PROMPT], UsrFnam, 8, KeyClick);
if (tn)
{
tn->SetName(Text[GETNAME_TITLE]);
tn->Center();
tn->Goto(tn->X, tn->Y - 10);
tn->Z = 126;
VGA::ShowQ.Insert(tn);
}
}
}
#endif
#ifdef DEBUG
static void SwitchMapping (void)
{
if (HorzLine.Flags.Hide)
{
int i;
for (i = 0; i < MAP_ZCNT; i ++)
{
int j;
for (j = 0; j < MAP_XCNT; j ++)
{
if (CLUSTER::Map[i][j])
SetMapBrick(j, i);
}
}
}
else
{
SPRITE * s;
for (s = VGA::ShowQ.First(); s; s = s->Next)
if (s->W == MAP_XGRID && s->H == MAP_ZGRID)
SNPOST_(SNKILL, -1, 0, s);
}
HorzLine.Flags.Hide = ! HorzLine.Flags.Hide;
}
static void KillSprite (void)
{
Sprite->Flags.Kill = true;
Sprite->Flags.BDel = true;
SNPOST_(SNKILL, -1, 0, Sprite);
Sprite = NULL;
}
static void PushSprite (void)
{
SPRITE * spr = Sprite->Prev;
if (spr)
{
VGA::ShowQ.Insert(VGA::ShowQ.Remove(Sprite), spr);
while (Sprite->Z > Sprite->Next->Z) -- Sprite->Z;
}
else SNPOST_(SNSOUND, -1, 2, NULL);
}
static void PullSprite (void)
{
bool ok = false;
SPRITE * spr = Sprite->Next;
if (spr)
{
spr = spr->Next;
if (spr)
{
ok = (! spr->Flags.Slav);
}
}
if (ok)
{
VGA::ShowQ.Insert(VGA::ShowQ.Remove(Sprite), spr);
if (Sprite->Prev)
while (Sprite->Z < Sprite->Prev->Z) ++ Sprite->Z;
}
else SNPOST_(SNSOUND, -1, 2, NULL);
}
static void NextStep (void)
{
SNPOST_(SNSTEP, 0, 0, Sprite);
}
static void SaveMapping (void)
{
{
IOHAND cf(ProgName(".TAB"), UPD);
if (! cf.Error)
{
cf.Seek((Now-1) * sizeof(CLUSTER::Map));
cf.Write((uint8 *) CLUSTER::Map, sizeof(CLUSTER::Map));
}
}
{
IOHAND cf(ProgName(".HXY"), WRI);
if (! cf.Error)
{
HeroXY[Now-1].X = Hero->X;
HeroXY[Now-1].Y = Hero->Y;
cf.Write((uint8 *) HeroXY, sizeof(HeroXY));
}
}
}
#endif
//--------------------------------------------------------------------------
#ifdef DEBUG
// 1111111111222222222233333333 334444444444555555555566666666667777777777
// 01234567890123456789012345678901234567 890123456789012345678901234567890123456789
static char DebugText[] = " N=00000 F=000000 X=000 Y=000 FPS=0000\0S=00:00 000:000:000 000:000 00 ";
#define NFRE (DebugText + 3)
#define FFRE (DebugText + 11)
#define ABSX (DebugText + 20)
#define ABSY (DebugText + 26)
#define FRPS (DebugText + 34)
#define XSPR (DebugText + 38)
#define SP_N (DebugText + 41)
#define SP_S (DebugText + 44)
#define SP_X (DebugText + 47)
#define SP_Y (DebugText + 51)
#define SP_Z (DebugText + 55)
#define SP_W (DebugText + 59)
#define SP_H (DebugText + 63)
#define SP_F (DebugText + 67)
#define SP__ (DebugText + 70)
INFO_LINE DebugLine(SCR_WID);
static void SayDebug (void)
{
if (! DebugLine.Flags.Hide)
{
static long t = -1L;
long t1 = Timer();
if (t1 - t >= 18)
{
static uint32 old = 0L;
uint32 now = Vga.FrmCnt;
dwtom(now - old, FRPS, 10, 4);
old = now;
t = t1;
}
dwtom(Mouse.X, ABSX, 10, 3);
dwtom(Mouse.Y, ABSY, 10, 3);
dwtom(coreleft(), NFRE, 10, 5);
dwtom(farcoreleft(), FFRE, 10, 6);
// sprite queue size
uint16 n = 0;
SPRITE * spr;
for (spr = VGA::ShowQ.First(); spr; spr = spr->Next)
{
++ n;
if (spr == Sprite)
{
*XSPR = ' ';
dwtom(n, SP_N, 10, 2);
dwtom(Sprite->X, SP_X, 10, 3);
dwtom(Sprite->Y, SP_Y, 10, 3);
dwtom(Sprite->Z, SP_Z, 10, 3);
dwtom(Sprite->W, SP_W, 10, 3);
dwtom(Sprite->H, SP_H, 10, 3);
dwtom(*(uint16 *) (&Sprite->Flags), SP_F, 16, 2);
}
}
dwtom(n, SP_S, 10, 2);
*SP__ = (heapcheck() < 0) ? '!' : ' ';
DebugLine.Update(DebugText);
}
}
static void SwitchDebug (void)
{
DebugLine.Flags.Hide = ! DebugLine.Flags.Hide;
}
#endif
static void OptionTouch (int opt, uint16 mask)
{
switch (opt)
{
case 1 : if (mask & L_UP) SwitchColorMode(); break;
case 2 : if (mask & L_UP) SwitchMusic();
else
if (mask & R_UP)
if (! MIXER::Appear)
{
MIXER::Appear = true;
new MIXER(BUTTON_X, BUTTON_Y);
}
break;
case 3 : if (mask & L_UP) Quit(); break;
}
}
#pragma argsused
void SPRITE::Touch (uint16 mask, int x, int y)
{
SYSTEM::FunTouch();
if ((mask & ATTN) == 0)
{
InfoLine.Update(Name());
if (mask & (R_DN | L_DN)) Sprite = this; // DEBUG mode only?
if (Ref/10 == 12)
{
OptionTouch(Ref % 10, mask);
return;
}
if (Flags.Syst) return; // cannot access system sprites
if (Game) if (mask & L_UP) { mask &= ~L_UP; mask |= R_UP; }
if ((mask & R_UP) && Snail.Idle())
{
SPRITE * ps = (PocLight.SeqPtr) ? Pocket[PocPtr] : NULL;
if (ps)
{
if (Flags.Kept || Hero->Distance(this) < MAX_DISTANCE)
{
if (Works(ps))
{
FeedSnail(ps, TAKE);
}
else OffUse();
SelectPocket(-1);
}
else TooFar();
}
else
{
if (Flags.Kept) mask |= L_UP;
else
{
if (Hero->Distance(this) < MAX_DISTANCE)
{///
if (Flags.Port)
{
if (FindPocket(NULL) < 0) PocFul();
else
{
SNPOST(SNREACH, -1, -1, this);
SNPOST(SNKEEP, -1, -1, this);
Flags.Port = false;
}
}
else
{
if (TakePtr != NO_PTR)
{
if (SnList(TAKE)[TakePtr].Com == SNNEXT) OffUse();
else FeedSnail(this, TAKE);
}
else OffUse();
}
}///
else TooFar();
}
}
}
if ((mask & L_UP) && Snail.Idle())
{
if (Flags.Kept)
{
int n;
for (n = 0; n < POCKET_NX; n ++)
{
if (Pocket[n] == this)
{
SelectPocket(n);
break;
}
}
}
else SNPOST(SNWALK, -1, -1, this); // Hero->FindWay(this);
}
}
}
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
static void LoadSprite (const char *fname, int ref, int cav, int col = 0, int row = 0, int pos = 0)
{
static const char * Comd[] = { "Name", "Type", "Phase", "East",
"Left", "Right", "Top", "Bottom",
"Seq", "Near", "Take",
"Portable", "Transparent",
NULL };
static const char * Type[] = { "DEAD", "AUTO", "WALK", "NEWTON", "LISSAJOUS",
"FLY", NULL };
char line[LINE_MAX];
int shpcnt = 0;
int type = 0; // DEAD
bool east = false;
bool port = false;
bool tran = false;
int i, lcnt = 0;
uint16 len;
MergeExt(line, fname, SPR_EXT);
if (INI_FILE::Exist(line)) // sprite description file exist
{
INI_FILE sprf(line);
if (sprf.Error)
{
VGA::Exit("Bad SPR", line);
}
while ((len = sprf.Read((uint8*)line)) != 0)
{
++ lcnt;
if (len && line[len-1] == '\n') line[-- len] = '\0';
if (len == 0 || *line == '.') continue;
if ((i = TakeEnum(Comd, strtok(line, " =\t"))) < 0)
{
VGA::Exit(NumStr("Bad line ######", lcnt), fname);
}
switch (i)
{
case 0 : // Name - will be taken in Expand routine
break;
case 1 : // Type
if ((type = TakeEnum(Type, strtok(NULL, " \t,;/"))) < 0)
VGA::Exit(NumStr("Bad line ######", lcnt), fname);
break;
case 2 : // Phase
++ shpcnt;
break;
case 3 : // East
east = (atoi(strtok(NULL, " \t,;/")) != 0);
break;
case 11 : // Portable
port = (atoi(strtok(NULL, " \t,;/")) != 0);
break;
case 12 : // Transparent
tran = (atoi(strtok(NULL, " \t,;/")) != 0);
break;
}
}
if (! shpcnt)
{
VGA::Exit("No shapes", fname);
}
}
else // no sprite description: mono-shaped sprite with only .BMP file
{
++ shpcnt;
}
// make sprite of choosen type
switch (type)
{
case 1 : // AUTO
{
Sprite = new SPRITE(NULL);
if (Sprite)
{
Sprite->Goto(col, row);
//Sprite->Time = 1;//-----------$$$$$$$$$$$$$$$$
}
break;
}
case 2 : // WALK
{
WALK * w = new WALK(NULL);
if (w && ref == 1)
{
w->Goto(col, row);
if (Hero)
{
VGA::Exit("2nd HERO", fname);
}
Hero = w;
}
Sprite = w;
break;
}
/*
case 3 : // NEWTON
NEWTON * n = new NEWTON(NULL);
if (n)
{
n->Ay = (bottom-n->H);
n->By = 90;
n->Cy = 3;
n->Bx = 99;
n->Cx = 3;
n->Goto(col, row);
}
Sprite = n;
break;
*/
case 4 : // LISSAJOUS
{
VGA::Exit("Bad type", fname);
/*
LISSAJOUS * l = new LISSAJOUS(NULL);
if (l)
{
l->Ax = SCR_WID/2;
l->Ay = SCR_HIG/2;
l->Bx = 7;
l->By = 13;
l->Cx = 300;
l->Cy = 500;
* (long *) &l->Dx = 0; // movex * cnt
l->Goto(col, row);
}
Sprite = l;
*/
break;
}
case 5 : // FLY
{
FLY * f = new FLY(NULL);
Sprite = f;
//////Sprite->Time = 1;//-----------$$$$$$$$$$$$$$
break;
}
default: // DEAD
{
Sprite = new SPRITE(NULL);
if (Sprite) Sprite->Goto(col, row);
break;
}
}
if (Sprite)
{
Sprite->Ref = ref;
Sprite->Cave = cav;
Sprite->Z = pos;
Sprite->Flags.East = east;
Sprite->Flags.Port = port;
Sprite->Flags.Tran = tran;
Sprite->Flags.Kill = true;
Sprite->Flags.BDel = true;
// TODO : Get Filename from entire path
//fnsplit(fname, NULL, NULL, Sprite->File, NULL);
Sprite->ShpCnt = shpcnt;
VGA::SpareQ.Append(Sprite);
}
}
static void LoadScript (const char *fname)
{
char line[LINE_MAX];
char * SpN;
int SpI, SpA, SpX, SpY, SpZ;
bool BkG = false;
INI_FILE scrf(fname);
int lcnt = 0;
bool ok = true;
if (scrf.Error) return;
while (scrf.Read((uint8*)line) != 0)
{
char *p;
++ lcnt;
if (*line == 0 || *line == '\n' || *line == '.') continue;
ok = false; // not OK if break
// sprite ident number
if ((p = strtok(line, " \t\n")) == NULL) break;
SpI = atoi(p);
// sprite file name
if ((SpN = strtok(NULL, " ,;/\t\n")) == NULL) break;
// sprite cave
if ((p = strtok(NULL, " ,;/\t\n")) == NULL) break;
SpA = atoi(p);
// sprite column
if ((p = strtok(NULL, " ,;/\t\n")) == NULL) break;
SpX = atoi(p);
// sprite row
if ((p = strtok(NULL, " ,;/\t\n")) == NULL) break;
SpY = atoi(p);
// sprite Z pos
if ((p = strtok(NULL, " ,;/\t\n")) == NULL) break;
SpZ = atoi(p);
// sprite life
if ((p = strtok(NULL, " ,;/\t\n")) == NULL) break;
BkG = atoi(p) == 0;
ok = true; // no break: OK
Sprite = NULL;
LoadSprite(SpN, SpI, SpA, SpX, SpY, SpZ);
if (Sprite && BkG) Sprite->Flags.Back = true;
}
if (! ok)
{
VGA::Exit(NumStr("Bad INI line ######", lcnt), fname);
}
}
static void MainLoop (void)
{
#if 0
//def DEBUG
static VgaRegBlk Mode[] = {
{ 0x04, VGASEQ, 0x08, 0x04 }, // memory mode
{ 0x03, VGAGRA, 0xFF, 0x00 }, // data rotate = 0
{ 0x05, VGAGRA, 0x03, 0x00 }, // R/W mode = 0
{ 0x06, VGAGRA, 0x02, 0x00 }, // misc
{ 0x14, VGACRT, 0x40, 0x00 }, // underline
{ 0x13, VGACRT, 0xFF, 0x28 }, // screen width
{ 0x17, VGACRT, 0xFF, 0xC3 }, // mode control
{ 0x11, VGACRT, 0x80, 0x00 }, // vert retrace end
{ 0x09, VGACRT, 0xEF, 0x01 }, // max scan line
{ 0x30, VGAATR, 0x00, 0x20 }, // 256 color mode
// { 0x12, VGACRT, 0xFF, 0x6E }, // vert display end
// { 0x15, VGACRT, 0xFF, 0x7F }, // start vb
// { 0x10, VGACRT, 0xFF, 0x94 }, // start vr
{ 0x00 } };
Vga.Setup(Mode);
#endif
Debug( SayDebug(); )
#ifdef DEMO
#define TIM ((182L*6L) * 5L)
static uint32 tc = 0;
if (TimerCount - tc >= TIM && Talk == NULL && Snail.Idle())
{
if (Text[DemoText])
{
SNPOST(SNSOUND, -1, 4, NULL); // drumla
SNPOST(SNINF, -1, DemoText, NULL);
SNPOST(SNLABEL, -1, -1, NULL);
if (Text[++ DemoText] == NULL) DemoText = DEMO_TEXT + 1;
}
tc = TimerCount;
}
#undef TIM
#endif
Vga.Show();
Snail_.RunCom();
Snail.RunCom();
}
void LoadUser (void)
{
// set scene
if (STARTUP::Mode == 0) // user .SVG file found
{
CFILE cfile = CFILE(UsrPath(UsrFnam), REA, RCrypt);
LoadGame(cfile);
}
else
{
if (STARTUP::Mode == 1)
{
SVG0FILE file = SVG0FILE(SVG0NAME);
LoadGame(file);
}
else
{
LoadScript(ProgName(INI_EXT));
Music = true;
CFILE file = CFILE(SVG0NAME, WRI);
SaveGame(file);
VGA::Exit("Ok", SVG0NAME);
}
}
LoadScript(ProgName(IN0_EXT));
}
static void RunGame (void)
{
Text.Clear();
Text.Preload(100, 1000);
LoadHeroXY();
CavLight.Flags.Tran = true;
VGA::ShowQ.Append(&CavLight);
CavLight.Flags.Hide = true;
static SEQ PocSeq[] = { { 0, 0, 0, 0, 20 },
{ 1, 2, 0, 0, 4 },
{ 2, 3, 0, 0, 4 },
{ 3, 4, 0, 0, 16 },
{ 2, 5, 0, 0, 4 },
{ 1, 6, 0, 0, 4 },
{ 0, 1, 0, 0, 16 },
};
PocLight.SetSeq(PocSeq);
PocLight.Flags.Tran = true;
PocLight.Time = 1;
PocLight.Z = 120;
VGA::ShowQ.Append(&PocLight);
SelectPocket(-1);
VGA::ShowQ.Append(&Mouse);
// ___________
LoadUser();
// ~~~~~~~~~~~
if ((Sprite = VGA::SpareQ.Locate(121)) != NULL)
SNPOST_(SNSEQ, -1, VGA::Mono, Sprite);
if ((Sprite = VGA::SpareQ.Locate(122)) != NULL) Sprite->Step(Music);
SNPOST_(SNSEQ, -1, Music, Sprite);
if (! Music) KillMIDI();
if (Mini && INI_FILE::Exist("MINI.SPR"))
{
uint8 * ptr = (uint8 *) &*Mini;
if (ptr != NULL)
{
LoadSprite("MINI", -1, 0, MINI_X, MINI_Y);
ExpandSprite(MiniCave = Sprite); // NULL is ok
if (MiniCave)
{
MiniCave->Flags.Hide = true;
MiniCave->MoveShapes(ptr);
MiniShp[0] = new BITMAP(*MiniCave->Shp());
MiniShpList = MiniCave->SetShapeList(MiniShp);
PostMiniStep(-1);
}
}
}
if (Hero)
{
ExpandSprite(Hero);
Hero->Goto(HeroXY[Now-1].X, HeroXY[Now-1].Y);
if (INI_FILE::Exist("00SHADOW.SPR"))
{
LoadSprite("00SHADOW", -1, 0, Hero->X + 14, Hero->Y + 51);
if ((Shadow = Sprite) != NULL)
{
Shadow->Ref = 2;
Shadow->Flags.Tran = true;
Hero->Flags.Shad = true;
VGA::ShowQ.Insert(VGA::SpareQ.Remove(Shadow), Hero);
}
}
}
InfoLine.Goto(INFO_X, INFO_Y);
InfoLine.Flags.Tran = true;
InfoLine.Update(NULL);
VGA::ShowQ.Insert(&InfoLine);
#ifdef DEBUG
DebugLine.Z = 126;
VGA::ShowQ.Insert(&DebugLine);
HorzLine.Y = MAP_TOP - (MAP_TOP > 0);
HorzLine.Z = 126;
VGA::ShowQ.Insert(&HorzLine);
#endif
Mouse.Busy = VGA::SpareQ.Locate(BUSY_REF);
if (Mouse.Busy) ExpandSprite(Mouse.Busy);
Startup = 0;
SNPOST(SNLEVEL, -1, OldLev, &CavLight);
CavLight.Goto(CAVE_X + ((Now-1) % CAVE_NX) * CAVE_DX + CAVE_SX,
CAVE_Y + ((Now-1) / CAVE_NX) * CAVE_DY + CAVE_SY);
CaveUp();
KEYBOARD::SetClient(Sys);
// main loop
while (! Finis)
{
//TODO Change the SNPOST message send to a special way to send function pointer
// if (FINIS) SNPOST(SNEXEC, -1, 0, (void *)&QGame);
MainLoop();
}
KEYBOARD::SetClient(NULL);
HEART::Enable = false;
SNPOST(SNCLEAR, -1, 0, NULL);
SNPOST_(SNCLEAR, -1, 0, NULL);
Mouse.Off();
VGA::ShowQ.Clear();
VGA::SpareQ.Clear();
Hero = NULL;
Shadow = NULL;
}
void Movie (const char * ext)
{
const char * fn = ProgName(ext);
if (INI_FILE::Exist(fn))
{
LoadScript(fn);
ExpandSprite(VGA::SpareQ.Locate(999));
FeedSnail(VGA::ShowQ.Locate(999), TAKE);
VGA::ShowQ.Append(&Mouse);
HEART::Enable = true;
KEYBOARD::SetClient(Sys);
while (! Snail.Idle())
{
MainLoop();
}
KEYBOARD::SetClient(NULL);
HEART::Enable = false;
SNPOST(SNCLEAR, -1, 0, NULL);
SNPOST_(SNCLEAR, -1, 0, NULL);
VGA::ShowQ.Clear();
VGA::SpareQ.Clear();
}
}
bool ShowTitle (const char * name)
{
BITMAP::Pal = SysPal;
BMP_PTR LB[] = { new BITMAP(name), NULL };
BITMAP::Pal = NULL;
bool usr_ok = false;
SPRITE D(LB);
D.Flags.Kill = true;
D.Flags.BDel = true;
D.Center();
D.Show(2);
if (STARTUP::Mode == 2)
{
Inf(SVG0NAME);
Talk->Show(2);
}
Vga.Sunset();
VGA::CopyPage(1, 2);
VGA::CopyPage(0, 1);
SelectPocket(-1);
Vga.Sunrise(SysPal);
if (STARTUP::Mode < 2 && ! STARTUP::SoundOk)
{
VGA::CopyPage(1, 2);
VGA::CopyPage(0, 1);
VGA::ShowQ.Append(&Mouse);
HEART::Enable = true;
Mouse.On();
for (SelectSound(); ! Snail.Idle() || VMENU::Addr; ) MainLoop();
Mouse.Off();
HEART::Enable = false;
VGA::ShowQ.Clear();
VGA::CopyPage(0, 2);
STARTUP::SoundOk = 2;
if (Music) LoadMIDI(0);
}
if (STARTUP::Mode < 2)
{
#ifdef DEMO
strcpy(UsrFnam, ProgName(SVG_EXT));
usr_ok = true;
#else
//-----------------------------------------
#ifndef EVA
#ifdef CD
STARTUP::Summa |= (0xC0 + (DriveCD(0) << 6)) & 0xFF;
#else
// TODO : do good boot...
Boot * b = ReadBoot(0); //getdisk());
uint32 sn = (b->XSign == 0x29) ? b->Serial : b->lTotSecs;
free(b);
sn -= ((IDENT *)Copr)->disk;
STARTUP::Summa |= Lo(sn) | Hi(sn);
#endif
#endif
//-----------------------------------------
Movie("X00"); // paylist
VGA::CopyPage(1, 2);
VGA::CopyPage(0, 1);
VGA::ShowQ.Append(&Mouse);
//Mouse.On();
HEART::Enable = true;
for (TakeName(); GET_TEXT::Ptr; ) MainLoop();
HEART::Enable = false;
if (KEYBOARD::Last() == Enter && *UsrFnam) usr_ok = true;
if (usr_ok) strcat(UsrFnam, SVG_EXT);
//Mouse.Off();
VGA::ShowQ.Clear();
VGA::CopyPage(0, 2);
#endif
if (usr_ok && STARTUP::Mode == 0)
{
const char *n = UsrPath(UsrFnam);
if (CFILE::Exist(n))
{
CFILE file = CFILE(n, REA, RCrypt);
LoadGame(file, true); // only system vars
VGA::SetColors(SysPal, 64);
Vga.Update();
if (FINIS)
{
++ STARTUP::Mode;
FINIS = false;
}
}
else ++ STARTUP::Mode;
}
}
if (STARTUP::Mode < 2) Movie("X01"); // wink
VGA::CopyPage(0, 2);
#ifdef DEMO
return true;
#else
return (STARTUP::Mode == 2 || usr_ok);
#endif
}
/*
#ifdef DEBUG
void StkDump (void)
{
CFILE f("!STACK.DMP", BFW);
f.Write((uint8 *) (intStackPtr-STACK_SIZ/2), STACK_SIZ*2);
}
#endif
*/
void cge_main (void)
{
uint16 intStack[STACK_SIZ/2];
intStackPtr = intStack;
//Debug( memset((void *) (-K(2)), 0, K(1)); )
//Debug( memset((void *) (-K(4)), 0, K(1)); )
memset(Barriers, 0xFF, sizeof(Barriers));
if (! Mouse.Exist) VGA::Exit(NO_MOUSE_TEXT);
if (! SVG0FILE::Exist(SVG0NAME)) STARTUP::Mode = 2;
Debug( DebugLine.Flags.Hide = true; )
Debug( HorzLine.Flags.Hide = true; )
//srand((uint16) Timer());
Sys = new SYSTEM;
if (Music && STARTUP::SoundOk) LoadMIDI(0);
if (STARTUP::Mode < 2) Movie(LGO_EXT);
if (ShowTitle("WELCOME"))
{
#ifndef DEMO
if (STARTUP::Mode == 1) Movie("X02"); // intro
#endif
RunGame();
Startup = 2;
if (FINIS) Movie("X03");
}
else Vga.Sunset();
VGA::Exit(EXIT_OK_TEXT+FINIS);
}
} // End of namespace CGE