HYPNO: parsing of data structure used for arcade sequences and refactoring

This commit is contained in:
neuromancer 2021-08-01 19:13:52 +02:00 committed by Eugene Sandulenko
parent 104a141840
commit e868e7bde8
8 changed files with 408 additions and 83 deletions

View File

@ -119,15 +119,30 @@ class Global : public Action {
Common::String command;
};
class Shoot {
public:
Common::String animation;
};
typedef Common::List<Shoot> Shoots;
class ArcadeShooting {
public:
Common::String background;
Common::String player;
Shoots shoots;
};
class Level {
public:
Hotspots hots;
Movies intros;
ArcadeShooting arcade;
};
typedef Common::HashMap<Common::String, Level> Levels;
extern Hotspots *g_parsedHots;
//extern Settings g_settings;
extern ArcadeShooting g_parsedArc;
} // End of namespace Hypno

View File

@ -42,6 +42,7 @@
namespace Hypno {
Hotspots *g_parsedHots;
ArcadeShooting g_parsedArc;
//Settings g_settings;
const static char* levelVariables[] = {
@ -74,7 +75,8 @@ const static char* levelVariables[] = {
NULL
};
extern int parse(const char *);
extern int parse_mis(const char *);
extern int parse_arc(const char *);
HypnoEngine::HypnoEngine(OSystem *syst, const ADGameDescription *gd)
: Engine(syst), _gameDescription(gd), _image(nullptr), _videoDecoder(nullptr),
@ -103,7 +105,7 @@ void HypnoEngine::loadMis(Common::String filename) {
char *buf = (char *)malloc(fileSize + 1);
test->read(buf, fileSize);
buf[fileSize] = '\0';
parse(buf);
parse_mis(buf);
Level level;
level.hots = *g_parsedHots;
_levels[filename] = level;
@ -170,52 +172,76 @@ bool HypnoEngine::checkLevelCompleted() {
return _levelState["GS_LEVELCOMPLETE"];
}
Common::Error HypnoEngine::run() {
_language = Common::parseLanguage(ConfMan.get("language"));
_platform = Common::parsePlatform(ConfMan.get("platform"));
void HypnoEngine::loadAssets() {
LibData files = loadLib("C_MISC/MISSIONS.LIB");
/*uint32 i = 0;
uint32 i = 0;
uint32 j = 0;
uint32 k = 0;
Common::String mis;
debug("file: %s",files.filenames[j].c_str());
for (i = 0; i < files.data.size(); i++) {
debugN("%c", files.data[i]);
mis += files.data[i];
//debugN("%x/%c, ", files.data[i], files.data[i]);
if (files.data[i] == 'X') {
if (j == files.filenames.size()-1) {
debug("Finished at %d from %d", i, files.data.size());
for (k = i; k < files.data.size(); k++)
debugN("%c", files.data[k]);
break;
}
break;
//if (j == files.filenames.size()-1) {
// debug("Finished at %d from %d", i, files.data.size());
// for (k = i; k < files.data.size(); k++)
// debugN("%c", files.data[k]);
// break;
//}
j++;
//j++;
debugN("\n************file: %s**************",files.filenames[j].c_str());
}
}
*/
parse_arc(mis.c_str());
{
Level level;
level.arcade = g_parsedArc;
_levels[files.filenames[0]] = level;
debug("%s", level.arcade.background.c_str());
}
{ // quit level
Hotspot q;
q.type = MakeMenu;
Action *a = new Quit();
q.actions.push_back(a);
Level level;
Hotspots quit;
quit.push_back(q);
level.hots = quit;
_levels["mis/quit.mis"] = level;
}
Hotspot q;
q.type = MakeMenu;
Action *a = new Quit();
q.actions.push_back(a);
Level level;
Hotspots quit;
quit.push_back(q);
level.hots = quit;
_levels["mis/quit.mis"] = level;
// Read assets from mis files
loadMis("mis/demo.mis");
_levels["mis/demo.mis"].intros.push_back("demo/dcine1.smk");
_levels["mis/demo.mis"].intros.push_back("demo/dcine2.smk");
_levels["mis/demo.mis"].hots[1].setting = "C1.MI_";
_levels["mis/demo.mis"].hots[2].setting = "mis/alley.mis";
_levels["mis/demo.mis"].hots[5].setting = "mis/order.mis";
loadMis("mis/order.mis");
_levels["mis/order.mis"].hots[1].setting = "mis/quit.mis";
loadMis("mis/alley.mis");
_levels["mis/alley.mis"].intros.push_back("demo/aleyc01s.smk");
//loadMis("MIS/SHOCTALK.MIS");
//loadMis("mis/shoctalk.mis");
}
Common::Error HypnoEngine::run() {
_language = Common::parseLanguage(ConfMan.get("language"));
_platform = Common::parsePlatform(ConfMan.get("platform"));
//return Common::kNoError;
// Initialize graphics
initGraphics(_screenW, _screenH, nullptr);
@ -240,7 +266,7 @@ Common::Error HypnoEngine::run() {
} else {
_nextSetting = getGoIntroSetting();
}*/
loadAssets();
_nextSetting = "mis/demo.mis";
while (!shouldQuit()) {
resetLevelState();
@ -248,22 +274,102 @@ Common::Error HypnoEngine::run() {
debug("Executing setting %s", _nextSetting.c_str());
_currentSetting = _nextSetting;
_nextSetting = "";
runMis(_currentSetting);
runLevel(_currentSetting);
}
}
return Common::kNoError;
}
void HypnoEngine::runLevel(Common::String name) {
assert(_levels.contains(name));
if (_levels[name].hots.size() == 0)
runArcade(_levels[name].arcade);
else
runScene(_levels[name].hots, _levels[name].intros);
void HypnoEngine::runMis(Common::String name) {
}
void HypnoEngine::runArcade(ArcadeShooting arc) {
Common::Event event;
Common::Point mousePos;
_nextMoviesToPlay.push_back(arc.background);
_nextMoviesPositions.push_back(Common::Point(0, 0));
_nextMoviesScales.push_back(true);
changeCursor("mouse/cursor1.smk", 0);
while (!shouldQuit()) {
while (g_system->getEventManager()->pollEvent(event)) {
mousePos = g_system->getEventManager()->getMousePos();
// Events
switch (event.type) {
case Common::EVENT_QUIT:
case Common::EVENT_RETURN_TO_LAUNCHER:
break;
case Common::EVENT_LBUTTONDOWN:
//if (!_nextHotsToAdd || !_nextHotsToRemove)
// clickedHotspot(mousePos);
break;
case Common::EVENT_MOUSEMOVE:
break;
default:
break;
}
}
// Movies
if (_nextMoviesToPlay.size() > 0 && _currentMovie.empty()) {
debug("start playing %s", _nextMoviesToPlay.front().c_str());
//removeTimer();
assert(_nextMoviesToPlay.size() == _nextMoviesPositions.size());
_videoDecoder = new Video::SmackerDecoder();
_currentMovie = _nextMoviesToPlay.front();
_moviePosition = _nextMoviesPositions.front();
_movieScale = _nextMoviesScales.front();
playVideo(_currentMovie);
_nextMoviesToPlay.pop_front();
_nextMoviesPositions.pop_front();
_nextMoviesScales.pop_front();
continue;
}
if (_videoDecoder && !_videoDecoder->isPaused()) {
if (_videoDecoder->getCurFrame() == 0)
stopSound(true);
if (_videoDecoder->endOfVideo()) {
debug("video still playing");
_videoDecoder->close();
delete _videoDecoder;
_videoDecoder = nullptr;
_currentMovie = "";
} else if (_videoDecoder->needsUpdate()) {
debug("updating screen");
drawScreen();
g_system->delayMillis(10);
}
continue;
}
g_system->updateScreen();
g_system->delayMillis(10);
}
}
void HypnoEngine::runScene(Hotspots hots, Movies intros) {
Common::Event event;
Common::Point mousePos;
stack.clear();
assert(_levels.contains(name));
_nextHotsToAdd = &_levels[name].hots;
_nextMoviesToPlay = _levels[name].intros;
_nextHotsToAdd = &hots;
_nextMoviesToPlay = intros;
for (uint32 i = 0; i < _nextMoviesToPlay.size(); i++) {
_nextMoviesPositions.push_back(Common::Point(0, 0));
_nextMoviesScales.push_back(true);

View File

@ -85,13 +85,17 @@ public:
Common::HashMap<Common::String, int> _levelState;
void resetLevelState();
bool checkLevelCompleted();
void runMis(Common::String name);
void runLevel(Common::String name);
void runScene(Hotspots hots, Movies intros);
void runArcade(ArcadeShooting arc);
void restartGame();
void clearAreas();
void initializePath(const Common::FSNode &gamePath) override;
void loadAssets();
void loadMis(Common::String filename);
LibData loadLib(char *filename);
Common::HashMap<Common::String, Common::String> _assets;
// User input
void clickedHotspot(Common::Point);
@ -119,7 +123,6 @@ public:
void playVideo(const Common::String &);
void skipVideo();
Graphics::Surface *decodeImage(const Common::String &file);
Graphics::Surface *decodeFrame(const Common::String &name, int frame, bool convert = true);
void loadImage(const Common::String &file, int x, int y);

View File

@ -3,8 +3,10 @@ MODULE := engines/hypno
MODULE_OBJS := \
cursors.o \
metaengine.o \
lexer.o \
grammar.o \
spider/lexer_mis.o \
spider/grammar_mis.o \
spider/lexer_arc.o \
spider/grammar_arc.o \
hypno.o
MODULE_DIRS += \

View File

@ -0,0 +1,137 @@
/* 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.
*
*/
%require "3.0"
%defines "engines/hypno/spider/tokens_arc.h"
%output "engines/hypno/spider/grammar_arc.cpp"
%define api.prefix {HYPNO_ARC_}
%{
#include "common/array.h"
#include "hypno/grammar.h"
#include <stdio.h>
#undef yyerror
#define yyerror HYPNO_ARC_xerror
Hypno::Shoot *shoot;
extern int HYPNO_ARC_lex();
extern int HYPNO_ARC_parse();
extern int yylineno;
void HYPNO_ARC_xerror(const char *str) {
debug("ERROR: %s", str);
}
int HYPNO_ARC_wrap() {
return 1;
}
using namespace Hypno;
%}
%union {
char *s; /* string value */
int i; /* integer value */
}
%token<s> NAME FILENAME
%token<i> NUM
// header
%token CTOK DTOK HTOK HETOK RETTOK QTOK ENCTOK
%token PTOK ATOK VTOK OTOK NTOK RTOK ITOK SNTOK ZTOK
// body
%token F0TOK A0TOK B0TOK K0TOK P0TOK WTOK
// end
%token XTOK
// bytes??
%token CB3TOK C02TOK
%%
start: header body
;
header: hline RETTOK header
| hline
| RETTOK header
;
hline: CTOK NUM { debug("C %d", $2); }
| DTOK NUM { debug("D %d", $2); }
| PTOK NUM NUM { debug("P %d %d", $2, $3); }
| ATOK NUM NUM { debug("A %d %d", $2, $3); }
| VTOK NUM NUM { debug("V %d %d", $2, $3); }
| OTOK NUM NUM { debug("O %d %d", $2, $3); }
| NTOK FILENAME {
g_parsedArc.background = $2;
debug("N %s", $2);
}
| RTOK FILENAME { debug("R %s", $2); }
| ITOK FILENAME {
g_parsedArc.player = $2;
debug("I %s", $2);
}
| QTOK NUM NUM { debug("Q %d %d", $2, $3); }
| SNTOK FILENAME enc { debug("SN %s", $2); }
| HETOK C02TOK NUM NUM { debug("HE %d %d", $3, $4); }
| HTOK CB3TOK NUM NUM { debug("H %d %d", $3, $4); }
| ZTOK RETTOK { debug("Z"); }
;
enc: ENCTOK
| /* nothing */
;
body: bline RETTOK body
| bline RETTOK XTOK
bline: F0TOK FILENAME {
shoot = new Shoot();
shoot->animation = $2;
debug("F0 %s", $2);
}
| ITOK NAME { debug("I %s", $2); }
| A0TOK NUM NUM { debug("A0 %d %d", $2, $3); }
| B0TOK NUM NUM { debug("B0 %d %d", $2, $3); }
| K0TOK NUM NUM { debug("K0 %d %d", $2, $3); }
| P0TOK NUM NUM { debug("P0 %d %d", $2, $3); }
| OTOK NUM NUM { debug("O %d %d", $2, $3); }
| CTOK NUM { debug("C %d", $2); }
| HTOK NUM { debug("H %d", $2); }
| WTOK NUM { debug("W %d", $2); }
| DTOK NUM { debug("D %d", $2); }
| SNTOK FILENAME enc { debug("SN %s", $2); }
| ZTOK {
g_parsedArc.shoots.push_back(*shoot);
delete shoot;
shoot = nullptr;
debug("Z");
}
;

View File

@ -20,56 +20,32 @@
*
*/
// Heavily inspired by hoc
// Copyright (C) AT&T 1995
// All Rights Reserved
//
// Permission to use, copy, modify, and distribute this software and
// its documentation for any purpose and without fee is hereby
// granted, provided that the above copyright notice appear in all
// copies and that both that the copyright notice and this
// permission notice and warranty disclaimer appear in supporting
// documentation, and that the name of AT&T or any of its entities
// not be used in advertising or publicity pertaining to
// distribution of the software without specific, written prior
// permission.
//
// AT&T DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
// INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
// IN NO EVENT SHALL AT&T OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
// SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
// IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
// ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
// THIS SOFTWARE.
%require "3.0"
%defines "engines/hypno/tokens.h"
%output "engines/hypno/grammar.cpp"
%define api.prefix {HYPNO_}
%defines "engines/hypno/spider/tokens_mis.h"
%output "engines/hypno/spider/grammar_mis.cpp"
%define api.prefix {HYPNO_MIS_}
%{
//#include "private/private.h"
#include "common/array.h"
#include "hypno/grammar.h"
#include <stdio.h>
#undef yyerror
#define yyerror HYPNO_xerror
#define yyerror HYPNO_MIS_xerror
extern int HYPNO_lex();
extern int HYPNO_parse();
extern int HYPNO_MIS_lex();
extern int HYPNO_MIS_parse();
extern int yylineno;
Common::Array<uint32> smenu_idx;
Hypno::HotspotsStack stack;
void HYPNO_xerror(const char *str) {
void HYPNO_MIS_xerror(const char *str) {
debug("ERROR: %s", str);
}
int HYPNO_wrap() {
int HYPNO_MIS_wrap() {
return 1;
}
@ -78,8 +54,8 @@ using namespace Hypno;
%}
%union {
char *s; /* string value */
int i; /* integer value */
char *s; /* string value */
int i; /* integer value */
}
%token<s> NAME FILENAME FLAG COMMENT GSSWITCH COMMAND
@ -152,8 +128,8 @@ line: MENUTOK NAME mflag {
Hotspot *hot = &cur->back();
hot->actions.push_back(a);
debug("ESC SUBMENU"); }
| TIMETOK NUM { debug("TIME %d", $2); }
| BACKTOK FILENAME NUM NUM gsswitch flag {
| TIMETOK NUM { debug("TIME %d", $2); }
| BACKTOK FILENAME NUM NUM gsswitch flag {
Background *a = new Background();
a->path = $2;
a->origin = Common::Point($3, $4);
@ -189,7 +165,7 @@ line: MENUTOK NAME mflag {
Hotspot *hot = &cur->back();
hot->actions.push_back(a);
}
| PALETOK FILENAME {
| PALETOK FILENAME {
Palette *a = new Palette();
a->path = $2;
Hotspots *cur = stack.back();

View File

@ -0,0 +1,86 @@
/* 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.
*
*/
%option noyywrap
%option noinput
%option yylineno
%option never-interactive
%option outfile="engines/hypno/spider/lexer_arc.cpp"
%option prefix="HYPNO_ARC_"
%{
#define YY_NO_UNISTD_H
#define FORBIDDEN_SYMBOL_ALLOW_ALL
#include "hypno/hypno.h"
#include "hypno/grammar.h"
#include "hypno/spider/tokens_arc.h"
%}
%%
C return CTOK;
D return DTOK;
HE return HETOK;
H return HTOK;
P return PTOK;
A return ATOK;
V return VTOK;
O return OTOK;
N return NTOK;
R return RTOK;
I return ITOK;
Q return QTOK;
Z return ZTOK;
W return WTOK;
X return XTOK;
F0 return F0TOK;
S[0-9] return SNTOK;
A0 return A0TOK;
B0 return B0TOK;
K0 return K0TOK;
P0 return P0TOK;
22[k|K] return ENCTOK;
[A-Za-z_][A-Za-z_0-9]* HYPNO_ARC_lval.s = scumm_strdup(HYPNO_ARC_text); return NAME;
[A-Za-z][A-Za-z_0-9\\\.]* HYPNO_ARC_lval.s = scumm_strdup(HYPNO_ARC_text); return FILENAME;
[\-]?[0-9]+ HYPNO_ARC_lval.i = atoi(HYPNO_ARC_text); return NUM;
\n return RETTOK;
\xb3 return CB3TOK;
\x02 return C02TOK;
[ \t]+ /* ignore whitespace */;
. debug("notparsed: 0x%d",*yytext); return *yytext;
%%
namespace Hypno {
int parse_arc(const char *code) {
YY_BUFFER_STATE bp;
yy_delete_buffer(YY_CURRENT_BUFFER);
bp = yy_scan_string(code);
yy_switch_to_buffer(bp);
HYPNO_ARC_parse();
yy_delete_buffer(bp);
return 0;
}
} // End of namespace Hypno

View File

@ -25,8 +25,8 @@
%option yylineno
%option never-interactive
%option outfile="engines/hypno/lexer.cpp"
%option prefix="HYPNO_"
%option outfile="engines/hypno/spider/lexer_mis.cpp"
%option prefix="HYPNO_MIS_"
%{
#define YY_NO_UNISTD_H
@ -34,7 +34,7 @@
#include "hypno/hypno.h"
#include "hypno/grammar.h"
#include "hypno/tokens.h"
#include "hypno/spider/tokens_mis.h"
%}
@ -55,12 +55,12 @@ SMEN return SMENTOK;
ESCP return ESCPTOK;
PLAY return PLAYTOK;
NO_RETURN return NRTOK;
GS_[A-Z_0-9]+ HYPNO_lval.s = scumm_strdup(HYPNO_text); return GSSWITCH;
GS_[A-Z_0-9]+ HYPNO_MIS_lval.s = scumm_strdup(HYPNO_MIS_text); return GSSWITCH;
\/BBOX\= return BBOXTOK;
\/[A-Za-z_0-9]* HYPNO_lval.s = scumm_strdup(HYPNO_text); return FLAG;
[A-Za-z_][A-Za-z_0-9]* HYPNO_lval.s = scumm_strdup(HYPNO_text); return NAME;
[A-Za-z][A-Za-z_0-9\\\.]* HYPNO_lval.s = scumm_strdup(HYPNO_text); return FILENAME;
[\-]?[0-9]+ HYPNO_lval.i = atoi(HYPNO_text); return NUM;
\/[A-Za-z_0-9]* HYPNO_MIS_lval.s = scumm_strdup(HYPNO_MIS_text); return FLAG;
[A-Za-z_][A-Za-z_0-9]* HYPNO_MIS_lval.s = scumm_strdup(HYPNO_MIS_text); return NAME;
[A-Za-z][A-Za-z_0-9\\\.]* HYPNO_MIS_lval.s = scumm_strdup(HYPNO_MIS_text); return FILENAME;
[\-]?[0-9]+ HYPNO_MIS_lval.i = atoi(HYPNO_MIS_text); return NUM;
\r\n return RETTOK;
[ \t]+ /* ignore whitespace */;
. debug("<no match>"); return *yytext;
@ -68,12 +68,12 @@ GS_[A-Z_0-9]+ HYPNO_lval.s = scumm_strdup(HYPNO_text); return GSSWITC
namespace Hypno {
int parse(const char *code) {
int parse_mis(const char *code) {
YY_BUFFER_STATE bp;
yy_delete_buffer(YY_CURRENT_BUFFER);
bp = yy_scan_string(code);
yy_switch_to_buffer(bp);
HYPNO_parse();
HYPNO_MIS_parse();
yy_delete_buffer(bp);
return 0;
}