/* 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 3 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, see <http://www.gnu.org/licenses/>.
 *
 */

#define FORBIDDEN_SYMBOL_EXCEPTION_strcpy

#include "watchmaker/define.h"
#include "watchmaker/extraLS.h"
#include "watchmaker/game.h"
#include "watchmaker/globvar.h"
#include "watchmaker/init/nl_parse.h"
#include "watchmaker/ll/ll_system.h"
#include "watchmaker/types.h"

namespace Watchmaker {

char *TextBucket, cr = 0;                    //da rimpiazzare con la areatext allocata da fab
static char *CurText;
int SentenceNum = 1, SysSentNum = 1, TooltipSentNum = 1, ObjNameNum = 1, ExtraLSNum = 1;
int DlgItemNum = 1;

uint16 Credits_numRoles = 0;
uint16 Credits_numNames = 0;

#define DEFAULT_DEFINE_INPUT "src/define.h"

#define MAXFLAGS 360
#define MAXTOKENLEN 30

#define ANIM_MARKER   'a'
#define CREDIT_MARKER 'c'
#define DLG_MARKER    'd'
#define DIARY_MARKER  'e'
#define ATFDO_MARKER  'f'
#define ACT_MARKER    'h'
#define INV_MARKER    'i'
#define PDALOG_MARKER 'l'
#define MENU_MARKER   'm'
#define MUSIC_MARKER  'n'
#define OBJ_MARKER    'o'
#define ROOM_MARKER   'r'
#define DESC_MARKER   's'
#define ENV_MARKER    'v'
#define SOUND_MARKER  'w'

#define TOKEN_NOT_FOUND 0xffff

typedef struct {
	char  token[MAXTOKENLEN];
	unsigned int value;
} TOKEN;                                // 32 bytes

int SaveTextTable(const char *name);

#define AddSound2Room(inx,val)  \
	{   \
		\
		unsigned short j=0,err=0,*tab=_init.Room[inx].sounds.rawArray(); \
		while(*tab!=0)  \
		{   \
			\
			tab++;         \
			if(j++>=MAX_SOUNDS_IN_ROOM)   \
				err=1;       \
		}         \
		if(err)         \
			_parser->ParseError("Too many Sounds in room %s max is %d",_init.Room[inx].name,MAX_SOUNDS_IN_ROOM); \
		else         \
			*tab=val;        \
	}

#define AddAnim2Room(room,inx)  \
	{   \
		\
		room->anims[animcnt++]=inx;     \
		if(animcnt>=MAX_ANIMS_IN_ROOM)     \
			return _parser->ParseError("Too many Anims in room %s max is %d",s,MAX_ANIMS_IN_ROOM); \
	}

#define AddAct2Room(room,inx)   \
	{   \
		\
		room->actions[actcnt++]=inx;     \
		if(actcnt>=MAX_ACTIONS_IN_ROOM)     \
			return _parser->ParseError("Too many Acts in room %s max is %d",s,MAX_ACTIONS_IN_ROOM); \
	}

#define AddObject2Room(room,inx)    \
	{   \
		\
		room->objects[objcnt++]=inx;     \
		if(objcnt>=MAX_OBJS_IN_ROOM)     \
			return _parser->ParseError("Too many Objects in room %s max is %d",s,MAX_OBJS_IN_ROOM); \
	}

TOKEN *FlagToken = NULL;
TOKEN *RoomToken = NULL;
TOKEN *ObjToken = NULL;
TOKEN *AnimToken = NULL;
TOKEN *InvToken = NULL;
TOKEN *WaveToken = NULL;
TOKEN *DoToken = NULL;
TOKEN *DlgToken = NULL;
TOKEN *ActToken = NULL;
TOKEN *MenuToken = NULL;
TOKEN *DiaryToken = NULL;
TOKEN *EnvToken = NULL;
TOKEN *PDALogToken = NULL;
TOKEN *MusicToken = NULL;

const char *ShortName[] = {
	"???",
	"DAR",
	"VIC",
	"CUO",
	"DOM",
	"GIA",
	"CUS",
	"SER",
	"SUP",
	"MOG",
	"MOG",
	"CAC",
	"VEC",
	"CHI",
	"TRA",
	"ORO",
	"KRE",
	"DUK",
	"COR",
	"VAL",
	"NOT",
	"MOO",
	"DAR",
	"CAC",
	"MOO",
	"BOT",
	"***"
};
char csn = 0;


/* -----------------16/03/98 18.14-------------------
 *                  FreeDefineTable
 * --------------------------------------------------*/
void FreeDefineTable(void) {
	free(FlagToken);
	free(RoomToken);
	free(ObjToken);
	free(AnimToken);
	free(InvToken);
	free(WaveToken);
	free(DoToken);
	free(ActToken);
	free(MenuToken);
	free(DlgToken);
	free(DiaryToken);
	free(EnvToken);
	free(PDALogToken);
	free(MusicToken);

	FlagToken = RoomToken = DiaryToken = ObjToken = ActToken = MenuToken = PDALogToken = MusicToken = NULL;
	AnimToken = InvToken = WaveToken = DoToken = DlgToken = EnvToken = NULL;
}

/* -----------------16/03/98 18.14-------------------
 *                  BuildDefineTable
 * --------------------------------------------------*/
int BuildDefineTable(const char *name) {
	auto parser = NLParser::open(DEFAULT_DEFINE_INPUT);
	if (!parser) {
		parser = NLParser::open(name);
		if (!parser) {
			error("Error Opening File NL %s", name);
		}
	}
	parser->IfParseErrorDo(FreeDefineTable);

	char str[MAXTOKENLEN];
	int res, done = FALSE;
	TOKEN *token = NULL;
	int cur_dlg, cur_flag, cur_room, cur_obj, cur_anim, cur_inv, cur_wave, cur_do, cur_act, cur_menu, cur_diary, cur_env, cur_pdalog, cur_music;

	CurText = TextBucket = t3dCalloc<char>(TEXT_BUCKET_SIZE);
	if (TextBucket == nullptr)
		return parser->ParseError("Error Allocating TextBucket");

	FlagToken = t3dCalloc<TOKEN>(MAXFLAGS);
	RoomToken = t3dCalloc<TOKEN>(MAX_ROOMS);
	ObjToken  = t3dCalloc<TOKEN>(MAX_OBJS);
	AnimToken = t3dCalloc<TOKEN>(MAX_ANIMS);
	InvToken  = t3dCalloc<TOKEN>(MAX_ICONS);
	WaveToken = t3dCalloc<TOKEN>(MAX_SOUNDS);
	DoToken = t3dCalloc<TOKEN>(MAX_ATF_DO);
	ActToken = t3dCalloc<TOKEN>(MAX_ACTIONS);
	MenuToken = t3dCalloc<TOKEN>(MAX_DLG_MENUS);
	DiaryToken = t3dCalloc<TOKEN>(MAX_DIARIES);
	DlgToken = t3dCalloc<TOKEN>(MAX_DIALOGS);
	EnvToken = t3dCalloc<TOKEN>(MAX_ENVIRONMENTS);
	PDALogToken = t3dCalloc<TOKEN>(MAX_PDALOGS);
	MusicToken = t3dCalloc<TOKEN>(MAX_MUSICS);

	if (!DlgToken || !MenuToken || !ActToken || !RoomToken || !ObjToken || !AnimToken || !InvToken || !DiaryToken || !WaveToken || !DoToken || !EnvToken || !PDALogToken || !MusicToken)
		return parser->ParseError("Error Allocating Define Tables");

	cur_dlg = cur_act = cur_menu = cur_flag = cur_room = cur_obj = cur_anim = cur_inv = cur_wave = cur_do = cur_diary = cur_env = cur_pdalog = cur_music = 0;

	while (!done) {
		res = parser->ReadArgument(str);
		warning("Cur res: %d Cur str: '%s'", res, str);
		if (res == EOF_PARSED)break;
		if (scumm_stricmp("#define", str))
			return parser->ParseError("Match %s instead of %s", str, "#define");

		if (parser->ReadArgument(str) < 0)
			return parser->ParseError("Error reading a string in file %s at line %d", name, parser->getCurLine());
		warning("Argument: '%s'", str);
		switch (str[0]) {
		case ROOM_MARKER:
			token = &RoomToken[cur_room++];
			if (cur_room >= MAX_ROOMS)return parser->ParseError("Too many Rooms defined (MAX is %d)", MAX_ROOMS);
			break;
		case OBJ_MARKER:
			token = &ObjToken[cur_obj++];
			if (cur_obj >= MAX_OBJS)return parser->ParseError("Too many Objects defined (MAX is %d)", MAX_OBJS);
			break;
		case INV_MARKER:
			token = &InvToken[cur_inv++];
			if (cur_inv >= MAX_ICONS)return parser->ParseError("Too many Icons defined (MAX is %d)", MAX_ICONS);
			break;
		case ANIM_MARKER:
			token = &AnimToken[cur_anim++];
			if (cur_anim >= MAX_ANIMS)return parser->ParseError("Too many Anims defined (MAX is %d)", MAX_ANIMS);
			break;
		case SOUND_MARKER:
			token = &WaveToken[cur_wave++];
			if (cur_wave >= MAX_SOUNDS)return parser->ParseError("Too many Samples defined (MAX is %d)", MAX_SOUNDS);
			break;
		case ATFDO_MARKER:
			token = &DoToken[cur_do++];
			if (cur_do >= MAX_ATF_DO)return parser->ParseError("Too many AtfDo defined (MAX is %d)", MAX_ATF_DO);
			break;
		case ACT_MARKER:
			token = &ActToken[cur_act++];
			if (cur_act >= MAX_ACTIONS)return parser->ParseError("Too many Action defined (MAX is %d)", MAX_ACTIONS);
			break;
		case MENU_MARKER:
			token = &MenuToken[cur_menu++];
			if (cur_menu >= MAX_DLG_MENUS)return parser->ParseError("Too many Menus defined (MAX is %d)", MAX_DLG_MENUS);
			break;
		case DIARY_MARKER:
			token = &DiaryToken[cur_diary++];
			if (cur_diary >= MAX_DIARIES)return parser->ParseError("Too many Diaries defined (MAX is %d)", MAX_DIARIES);
			break;
		case DLG_MARKER:
			token = &DlgToken[cur_dlg++];
			if (cur_dlg >= MAX_DIALOGS)return parser->ParseError("Too many Dialogs defined (MAX is %d) ", MAX_DIALOGS);
			break;
		case ENV_MARKER:
			token = &EnvToken[cur_env++];
			if (cur_env >= MAX_ENVIRONMENTS)return parser->ParseError("Too many Environments defined (MAX is %d) ", MAX_ENVIRONMENTS);
			break;
		case PDALOG_MARKER:
			token = &PDALogToken[cur_pdalog++];
			if (cur_pdalog >= MAX_PDALOGS)return parser->ParseError("Too many PDALogs defined (MAX is %d) ", MAX_PDALOGS);
			break;
		case MUSIC_MARKER:
			token = &MusicToken[cur_music++];
			if (cur_music >= MAX_MUSICS)return parser->ParseError("Too many Musics defined (MAX is %d) ", MAX_MUSICS);
			break;

		default:
			if (cur_flag >= MAXFLAGS) {         //ne legge solo un po'
				parser->ReadNumber();
				token = NULL;
				break;
			}
			token = &FlagToken[cur_flag++];
			break;
		}
		if (token) {
			strcpy(token->token, str);
			token->value = parser->ReadNumber();
		}
	}
	parser.reset();
	return 1;
}

/*PELS: end DEFINE ***********************************/

#undef Match
#define Match(t) {if((_parser->ReadArgument(str)<0) || scumm_stricmp(str,t))return _parser->ParseError("Syntax Error! can't match '%s' but found '%s'",t,str);}

static const char *InitFile[] = {
	"Init.nl",
	"InitLev1.nl",
	"InitLev2.nl",
	"InitLev3.nl",
	"InitLev4.nl",
	"InitAnim.nl",
	"InitAnim1.nl",
	"InitAnim2.nl",
	"InitAnim3.nl",
	"InitAnim4.nl",
	"InitAnimRtv.nl",
	"InitBkg.nl",
	"InitText.nl",
	"InitIcon.nl",
	"InitDlg.nl",
	"InitRtv1.nl",
	"InitRtv2.nl",
	"InitRtv3.nl",
	"InitRtv4.nl",
	"InitSound.nl",
	"InitT2D.nl",
	"InitDiary.nl",
	"Credits.nl",
	NULL
};

class StructureInitializer {
	Common::SharedPtr<NLParser> _parser;
	Common::String _filename;
	Init &_init;
public:
	StructureInitializer(Common::SharedPtr<NLParser> &parser, const Common::String &filename, Init &init) : _parser(parser), _filename(filename), _init(init) {
	}
	static Common::SharedPtr<StructureInitializer> open(Common::String &path, Init &init) {
		// TODO: Hook up the table-freeing
		auto parser = NLParser::open(path);
		if (!parser) {
			return nullptr;
		}
		warning("Casting away constness");
		if (parser->SearchArgument((char *)path.c_str(), "NL.", NULL) < 0)
			parser->ParseError("%s is not a NL file", path.c_str());
		return Common::SharedPtr<StructureInitializer>(new StructureInitializer(parser, path, init));
	}

	int parseLoop() {
		int res = 1;
		while (true) {
			char  str[J_MAXSTRLEN];
			if (_parser->ReadArgument(str) < 0) {
				if (!scumm_stricmp(str, "end."))break;
				else if ((toupper(str[0]) == 'E') && (toupper(str[1]) == 'N') &&
				         (toupper(str[2]) == 'D') && (toupper(str[3]) == '.'))
					break;
				else
					return _parser->ParseError("Error Reading File %s -%s-", _filename.c_str(), str);
			}
			if (!scumm_stricmp(str, "end."))break;
			if ((toupper(str[0]) == 'E') && (toupper(str[1]) == 'N') &&
			        (toupper(str[2]) == 'D') && (toupper(str[3]) == '.'))
				break;

			res = 0;
			switch (str[0]) {
			case OBJ_MARKER:
				res = ParseObject(str);
				break;
			case ROOM_MARKER:
				res = ParseRoom(str);
				break;
			case ANIM_MARKER:
				res = ParseAnim(str);
				break;
			case INV_MARKER:
				res = ParseInv(str);
				break;
			case SOUND_MARKER:
				res = ParseSound(str);
				break;
			case DLG_MARKER:
				res = ParseDialog(str);
				break;
			case DIARY_MARKER:
				res = ParseDiary(str);
				break;
			case MENU_MARKER:
				res = ParseMenu(str);
				break;
			case PDALOG_MARKER:
				res = ParsePDALog(str);
				break;
			case MUSIC_MARKER:
				res = ParseMusic(str);
				break;
			case CREDIT_MARKER:
				res = ParseCredits(str);
				break;
			}
			if (!res)
				error("Some parse error occurred");
		}
		return 1;
	}

	/* -----------------16/03/98 18.13-------------------
	 *                  GetTokenValue
	 * --------------------------------------------------*/
	unsigned int GetTokenValue(TOKEN *where, char *what) {
		if (!scumm_stricmp("none", what))return 0;
		while (where->token[0] != 0) {
			if (!strcmp(where->token, what))
				return where->value;
			where++;
		}
		_parser->ParseError("Can't find token %s", what);
		return TOKEN_NOT_FOUND;
	}

	/* -----------------16/03/98 18.13-------------------
	 *              GetTokenValueDefault
	 * --------------------------------------------------*/
	unsigned short GetTokenValueDefault(TOKEN *where, char *what) {
		if (!scumm_stricmp("none", what))return 0;
		while (where->token[0] != 0) {
			if (!strcmp(where->token, what))
				return where->value;
			where++;
		}
		return TOKEN_NOT_FOUND;
	}

	/* -----------------16/03/98 17.48-------------------
	 *                  ReadSentence
	 * --------------------------------------------------*/
	int ReadSentence(void) {
		int a;
		if ((a = _parser->ReadArgument(CurText)) < 0)
			_parser->ParseError("Error Reading a string in ReadSentence");
		Sentence[SentenceNum++] = CurText;
		switch (SentenceNum - 1) {
		case 2:
		case 3:
		case 6:
		case 8:
		case 10:
		case 12:
		case 13:
		case 15:
			csn = ocVECCHIO;
			break;
		case 4:
		case 5:
		case 7:
		case 9:
		case 11:
			csn = ocCHIRURGO;
			break;
		case 14:
			csn = ocTRADUTTORE;
			break;
		case 1:
			csn = ocOROLOGIAIO;
			break;
		}
		debug("%s s%04d %s\n", ShortName[(uint)csn], SentenceNum - 1, CurText);
		CurText += a;
		return (SentenceNum - 1);
	}

	/* -----------------16/03/98 17.48-------------------
	 *                  ReadSysSent
	 * --------------------------------------------------*/
	int ReadSysSent(void) {
		int a;
		if ((a = _parser->ReadArgument(CurText)) < 0)
			_parser->ParseError("Error Reading a string in ReadSysSent");
		SysSent[SysSentNum++] = CurText;
		csn = ocNOTRANS;
		debug("%s y%04d %s\n", ShortName[(uint)csn], SysSentNum - 1, CurText);
		CurText += a;
		return (SysSentNum - 1);
	}

	/* -----------------19/01/99 10.34-------------------
	 *                  ReadTooltipSent
	 * --------------------------------------------------*/
	int ReadTooltipSent(void) {
		int a;
		if ((a = _parser->ReadArgument(CurText)) < 0)
			_parser->ParseError("Error Reading a string in ReadTooltipSent");
		TooltipSent[TooltipSentNum++] = CurText;
		csn = ocNOTRANS;
		debug("%s t%04d %s\n", ShortName[(uint)csn], TooltipSentNum - 1, CurText);
		CurText += a;
		return (TooltipSentNum - 1);
	}


	/* -----------------21/03/01 09.40-------------------
	 *                  ReadExtraLS
	 * --------------------------------------------------*/
	int ReadExtraLS(void) {
		int a;
		if ((a = _parser->ReadArgument(CurText)) < 0)
			_parser->ParseError("Error Reading a string in ReadExtraLS");
		ExtraLS[ExtraLSNum++] = CurText;
		csn = ocNOTRANS;
		debug("%s e%04d %s\n", ShortName[(uint)csn], ExtraLSNum - 1, CurText);
		CurText += a;
		return (ExtraLSNum - 1);
	}

	/* -----------------16/03/98 17.47-------------------
	 *                  ReadObjName
	 * --------------------------------------------------*/
	int ReadObjName(void) {
		int a;
		if ((a = _parser->ReadArgument(CurText)) < 0)
			_parser->ParseError("Error Reading a string in ReadObjName");
		ObjName[ObjNameNum++] = CurText;
		csn = ocNOTRANS;
		debug("%s n%04d %s\n", ShortName[(uint)csn], ObjNameNum - 1, CurText);
		CurText += a;
		return (ObjNameNum - 1);
	}

	/* -----------------16/03/98 17.47-------------------
	 *                  ReadIndex
	 * --------------------------------------------------*/
	int ReadIndex() {
		char str[J_MAXSTRLEN];
		int inx;
		if (_parser->ReadArgument(str) <= 0)
			_parser->ParseError("Error Reading a string in ReadIndex");
		if ((inx = GetTokenValueDefault(WaveToken, str)) != TOKEN_NOT_FOUND)
			return inx;
		if ((inx = GetTokenValueDefault(ObjToken, str)) != TOKEN_NOT_FOUND)
			return inx;
		if ((inx = GetTokenValueDefault(DoToken, str)) != TOKEN_NOT_FOUND)
			return inx;
		if ((inx = GetTokenValueDefault(RoomToken, str)) != TOKEN_NOT_FOUND)
			return inx;
		if ((inx = GetTokenValueDefault(AnimToken, str)) != TOKEN_NOT_FOUND)
			return inx;
		if ((inx = GetTokenValueDefault(InvToken, str)) != TOKEN_NOT_FOUND)
			return inx;
		if ((inx = GetTokenValueDefault(MenuToken, str)) != TOKEN_NOT_FOUND)
			return inx;
		if ((inx = GetTokenValueDefault(DiaryToken, str)) != TOKEN_NOT_FOUND)
			return inx;
		if ((inx = GetTokenValueDefault(DlgToken, str)) != TOKEN_NOT_FOUND)
			return inx;
		if ((inx = GetTokenValueDefault(FlagToken, str)) != TOKEN_NOT_FOUND)
			return inx;
		if ((inx = GetTokenValueDefault(EnvToken, str)) != TOKEN_NOT_FOUND)
			return inx;
		if ((inx = GetTokenValueDefault(PDALogToken, str)) != TOKEN_NOT_FOUND)
			return inx;
		if ((inx = GetTokenValueDefault(MusicToken, str)) != TOKEN_NOT_FOUND)
			return inx;

		return atoi(str);
	}

	/* -----------------16/03/98 17.47-------------------
	 *                  ReadFlags
	 * --------------------------------------------------*/
	int ReadFlags() {
		int val = 0;
		char str[J_MAXSTRLEN];
		while (_parser->ReadArgumentEOL(str) > 0) {
			val |= GetTokenValue(FlagToken, str);
		}
		return val;
	}

	float ReadFloat(void) {
		char str[J_MAXSTRLEN];
		if (_parser->ReadArgument(str) < 0)
			return 0;
		return (float)atof(str);
	}


	/* -----------------16/03/98 17.47-------------------
	 *                  AssignSound
	 * --------------------------------------------------*/
	void AssignSound(int val) {
		int inx;
		char str[J_MAXSTRLEN];
		while (_parser->ReadArgumentEOL(str) > 0) {
			if ((inx = GetTokenValue(RoomToken, str)) != TOKEN_NOT_FOUND)
				AddSound2Room(inx, val);
		}
	}


	int ParseInv(char *s);
	int ParseRoom(char *s);
	int ParseAnim(char *s);
	int ParseObject(char *s);
	int ParseSound(char *s);
	int ParseItem(int d);
	int ParseDialog(char *s);
	int ParseDiary(char *s);
	int ParseMenu(char *s);
	int ParsePDALog(char *s);
	int ParseMusic(char *s);
	int ParseCredits(char *s);
};

int InitStructures(WGame &game) {
	const char **filelist = InitFile;

	if (!BuildDefineTable(game.workDirs._define.c_str()))
		return 0;

	SaveTextTable("SentUK.txt");

	for (; *filelist != NULL; filelist++) {
		Common::String path = game.workDirs._initDir + *filelist;
		auto initializer = StructureInitializer::open(path, game.init);
		if (!initializer)
			error("Error Opening File NL %s", path.c_str());

		initializer->parseLoop();

		initializer.reset();
	}

	FreeDefineTable();
	if ((CurText - TextBucket) > TEXT_BUCKET_SIZE)
		error("TextBucket OverFlow in %s by %ld", *filelist, (CurText - TextBucket));

	{
		debug("\n// ROOMS DESCRIPTIONS\n");
		for (int i = 0; i < MAX_ROOMS; i++)
			debug("*** d%04d %s\n", i, game.init.Room[i].desc);
	}

//	tapullo perchè mancava il nome della porta in inittext
	game.init.Obj[o2MBp2ME].name = game.init.Obj[o2MFp2MB].name;
	game.init.Obj[0] = SObject();

	return 1;
}


/* -----------------24/08/00 9.31--------------------
 *                  LoadExternalText
 * --------------------------------------------------*/
int LoadExternalText(Init *init, char *et) {
	char line[1000];
	int len, num;

	if (!et) return false;
	if (et[0] == '\0') return true;

	auto stream = openFile(et);
	if (!stream)
		return false;

	CurText = TextBucket;
	memset(TextBucket, 0, TEXT_BUCKET_SIZE);
	SentenceNum = SysSentNum = TooltipSentNum = ObjNameNum = ExtraLSNum = 1;

	while (stream->readLine(line, 1000) != nullptr) {
		if ((line[0] == '/') && (line[1] == '/')) continue;

		if ((len = strlen(line)) > 260)
			error("ExternalText: line too long! curlen %d (MAX 250)\n%s", len - 10, line);

		if (len < 2) continue;

		if (sscanf(&line[5], "%d", &num) < 1)
			error("ExternalText: sentence number not found in line:\n%s", line);

		switch (line[4]) {
		case 's':
			Sentence[num] = CurText;
			SentenceNum ++;
			break;
		case 'y':
			SysSent[num] = CurText;
			SysSentNum ++;
			break;
		case 't':
			TooltipSent[num] = CurText;
			TooltipSentNum ++;
			break;
		case 'e':
			ExtraLS[num] = CurText;
			ExtraLSNum ++;
			break;
		case 'n':
			ObjName[num] = CurText;
			ObjNameNum ++;
			break;
		case 'd':
			break;
		default:
			error("ExternalText: unknown paramenters in line:\n%s", line);
		}

		if ((len - 10 - 1) > 0) {
			memcpy(CurText, &line[10], len - 10 - 1);

			switch (line[4]) {
			case 'd':
				strcpy(init->Room[num].desc, CurText);
				break;
			}

			CurText += (len - 10);
		} else {
			switch (line[4]) {
			case 'd':
				strcpy(init->Room[num].desc, "");
				break;
			}

			CurText ++;
		}
	}

	return true;
}

/* -----------------16/03/98 17.46-------------------
 *                  ParseObject
 * --------------------------------------------------*/
int StructureInitializer::ParseObject(char *s) {
	int inx = GetTokenValue(ObjToken, s);
	int done = FALSE, arg, a, len;
	struct SObject *obj;
	char str[J_MAXSTRLEN];
	if (inx == TOKEN_NOT_FOUND)return _parser->ParseError("Object %s doesn't exist!", s);
	obj = &_init.Obj[inx];
	obj->room = cr;
	Match("{");
	while (!done) {
		if ((arg = _parser->SearchArgument(str, "}",
		                                   "name:", "examine:", "examined:", "examinev:", "action:", "actiond:", "actionv:",
		                                   "anim:", "animd:", "animv:", "goroom:", "godlg:", "ninv:", "flags:", "pos:", "meshlink:",
		                                   "text:", "log:", "sys:", "tooltip:", "anim2:", "anim2d:", "anim2v:", "log2:", "extrals:",
		                                   NULL)) < 0)return _parser->ParseError("Keyword %s Unknown in %s", str, s);
		switch (arg) {
		case 0:
			done = TRUE;
			break;
		case 1:
			debug("\n// %s\n", s);
			obj->name = ReadObjName();
			break;
		case 2:
			csn = ocBOTH;
			obj->examine[DARRELL] = ReadSentence();
			obj->examine[VICTORIA] = obj->examine[DARRELL];
			break;
		case 3:
			csn = ocDARRELL;
			obj->examine[DARRELL] = ReadSentence();
			break;
		case 4:
			csn = ocVICTORIA;
			obj->examine[VICTORIA] = ReadSentence();
			break;
		case 5:
			csn = ocBOTH;
			obj->action[DARRELL] = ReadSentence();
			obj->action[VICTORIA] = obj->action[DARRELL];
			break;
		case 6:
			csn = ocDARRELL;
			obj->action[DARRELL] = ReadSentence();
			break;
		case 7:
			csn = ocVICTORIA;
			obj->action[VICTORIA] = ReadSentence();
			break;
		case 8:
			_parser->ReadArgument(str);
			obj->anim[DARRELL] = GetTokenValue(AnimToken, str);
			obj->anim[VICTORIA] = obj->anim[DARRELL];
			break;
		case 9:
			_parser->ReadArgument(str);
			obj->anim[DARRELL] = GetTokenValue(AnimToken, str);
			break;
		case 10:
			_parser->ReadArgument(str);
			obj->anim[VICTORIA] = GetTokenValue(AnimToken, str);
			break;
		case 11:
			_parser->ReadArgument(str);
			obj->goroom = (uint8)GetTokenValue(RoomToken, str);
			break;
		case 12:
			_parser->ReadArgument(str);
			obj->goroom = (uint8)GetTokenValue(DlgToken, str);
			break;
		case 13:
			_parser->ReadArgument(str);
			obj->ninv = (uint8)GetTokenValue(InvToken, str);
			break;
		case 14:
			obj->flags = ReadFlags();
			break;
		case 15:
			obj->pos = _parser->ReadNumber();
			break;
		case 16:
			for (a = 0; a < MAX_OBJ_MESHLINKS; a++) if (obj->meshLinkIsEmpty(a)) break;
			if (a < MAX_OBJ_MESHLINKS)
				if ((len = _parser->ReadArgument(str)) < 0 || len > MAX_MESHLINK_SIZE)return _parser->ParseError("Error reading meshlink %s in %s", str, s);
				else obj->setMeshLink(a, str);
			else _parser->ParseError("Too many Meshlink in Obj %s %d max is %d", s, a, MAX_OBJ_MESHLINKS);
			break;
		case 17:
			for (a = 0; a < MAX_OBJ_USER_SENTS; a++) if (!obj->text[a]) break;
			csn = ocBOTH;
			if (a < MAX_OBJ_USER_SENTS) obj->text[a] = ReadSentence();
			else _parser->ParseError("Too many UserText in Obj %s %d max is %d", s, a, MAX_OBJ_USER_SENTS);
			break;
		case 18:
			_parser->ReadArgument(str);
			debug("\n// %s\n", str);
			break;
		case 19:
			ReadSysSent();
			break;
		case 20:
			ReadTooltipSent();
			break;
		case 21:
			_parser->ReadArgument(str);
			obj->anim2[DARRELL] = GetTokenValue(AnimToken, str);
			obj->anim2[VICTORIA] = obj->anim2[DARRELL];
			break;
		case 22:
			_parser->ReadArgument(str);
			obj->anim2[DARRELL] = GetTokenValue(AnimToken, str);
			break;
		case 23:
			_parser->ReadArgument(str);
			obj->anim2[VICTORIA] = GetTokenValue(AnimToken, str);
			break;
		case 24:
			_parser->ReadArgument(str);
			debug("// %s\n", str);
			break;
		case 25:
			ReadExtraLS();
			break;
		}
	}
	return TRUE;
}

/* -----------------16/03/98 17.50-------------------
 *                      ParseRoom
 * --------------------------------------------------*/
int StructureInitializer::ParseRoom(char *s) {
	int inx = GetTokenValue(RoomToken, s);
	int a, done = FALSE, res = TRUE, objcnt = 0, animcnt = 0, actcnt = 0;
	char str[J_MAXSTRLEN];
	struct SRoom *room;
	if (inx == TOKEN_NOT_FOUND)return _parser->ParseError("Room %s doesn't exist!", s);
	room = &_init.Room[inx];

	a = _parser->ReadArgument(str);
	if (a < 0 || (size_t)a > sizeof(room->name))return _parser->ParseError("Error reading basename in room %s", s);
	strcpy((char *)room->name, str);

	cr = inx;
	Match("{");
	while (!done) {
		if (_parser->ReadArgument(str) < 0)
			return _parser->ParseError("Error Reading room %s at line %d", s, _parser->getCurLine());
		if (!scumm_stricmp(str, "}"))break;
		switch (str[0]) {
		case OBJ_MARKER:
			inx = GetTokenValue(ObjToken, str);
			if (inx == TOKEN_NOT_FOUND)return _parser->ParseError("Can't process %s", str);
			AddObject2Room(room, inx);
			res = ParseObject(str);
			break;
		case ANIM_MARKER:
			inx = GetTokenValue(AnimToken, str);
			if (inx == TOKEN_NOT_FOUND)return _parser->ParseError("Can't process %s", str);
			AddAnim2Room(room, inx);
			//res=ParseAnim(str);
			break;
		case ACT_MARKER:
			inx = GetTokenValue(ActToken, str);
			if (inx == TOKEN_NOT_FOUND)return _parser->ParseError("Can't process %s", str);
			AddAct2Room(room, inx);
			break;
		case ENV_MARKER:
			inx = GetTokenValue(EnvToken, str);
			if (inx == TOKEN_NOT_FOUND)return _parser->ParseError("Can't process %s", str);
			room->env = inx;
			break;
		case DESC_MARKER:
			Match("{");
			_parser->ReadArgument(str);
			strncpy(room->desc, str, 62);
			Match("}");
			break;
		default:
			return _parser->ParseError("Can't process word %s", str);
		}
		if (!res)
			return _parser->ParseError("Error Parsing room %s", s);
	}
	cr = 0;

	return TRUE;
}

/* -----------------16/03/98 18.01-------------------
 *                  ParseAnim
 * --------------------------------------------------*/
int StructureInitializer::ParseAnim(char *s) {
	int inx = GetTokenValue(AnimToken, s);
	int done = FALSE, arg, a, j, len;
	struct SAnim *anim;
	char str[J_MAXSTRLEN];
	if (inx == TOKEN_NOT_FOUND)return _parser->ParseError("Anim %s doesn't exist!", s);
	anim = &_init.Anim[inx];
	/*  a=_parser->ReadArgument(str);
	    if(a<0 || a>sizeof(anim->name))return _parser->ParseError("Error reading name in anim %s",s);
	    strcpy(anim->name,str);
	*/  a = 0;

	Match("{");
	while (!done) {
		if ((arg = _parser->SearchArgument(str, "}", "flags:", "name:", "objlink:", "meshlink:", "roomname:", "portallink:", "pos:",
		                                   "camera:", "obj:", "atframe:", NULL)) < 0)return _parser->ParseError("Keyword %s Unknown in %s", str, s);
		switch (arg) {
		case 0:
			done = TRUE;
			break;
		case 1:
			anim->flags = ReadFlags();
			break;
		case 2:
			for (a = 0; a < MAX_SUBANIMS; a++) if (anim->meshLinkIsEmpty(a)) break;
			if ((a < MAX_SUBANIMS) && (--a >= 0))
				if ((len = _parser->ReadArgument(str)) < 0 || (long unsigned int)len > sizeof(anim->name[a])) return _parser->ParseError("Error reading animname %s in %s", str, s);
				else strcpy((char*)anim->name[a].rawArray(), str);
			else return _parser->ParseError("Too many subanim in Anim %s sub %d max is %d", str, a, MAX_SUBANIMS);
			break;
		case 3:
			for (a = 0; a < MAX_SUBANIMS; a++) if (anim->meshLinkIsEmpty(a)) break;
			if ((a < MAX_SUBANIMS) && (len = _parser->ReadArgument(str)))
				anim->setMeshLink(a, _init.Obj[GetTokenValue(ObjToken, str)].getMeshLink(0));
			else return _parser->ParseError("Too many Objlinks in Anim %s sub %d max is %d", str, a, MAX_SUBANIMS);
			break;
		case 4:
			for (a = 0; a < MAX_SUBANIMS; a++) if (anim->meshLinkIsEmpty(a)) break;
			if (a < MAX_SUBANIMS)
				if ((len = _parser->ReadArgument(str)) < 0 || len > MAX_MESHLINK_SIZE) return _parser->ParseError("Error reading meshlink %s in %s", str, s);
				else anim->setMeshLink(a, str);
			else return _parser->ParseError("Too many Meshlinks in Anim %s sub %d max is %d", str, a, MAX_SUBANIMS);
			break;
		case 5:
			if ((len = _parser->ReadArgument(str)) < 0 || (size_t)len > sizeof(anim->RoomName)) return _parser->ParseError("Error reading RoomName %s in %s", str, s);
			else strcpy((char*)anim->RoomName.rawArray(), str);
			break;
		case 6:
			if ((len = _parser->ReadArgument(str)) < 0 || (size_t)len > sizeof(anim->RoomName)) return _parser->ParseError("Error reading PortalLink %s in %s", str, s);
			else strcpy((char*)anim->RoomName.rawArray(), str);
			break;
		case 7:
			anim->pos = _parser->ReadNumber();
			break;
		case 8:
			anim->cam = _parser->ReadNumber();
			break;
		case 9:
			_parser->ReadArgument(str);
			anim->obj = GetTokenValue(ObjToken, str);
			break;
		case 10:
			while (_parser->ReadArgumentEOL(str) > 0) {
				j = 0;
				while (anim->atframe[j].type != 0)
					if (j++ >= MAX_ATFRAMES) return _parser->ParseError("Too many ATFrame in Anim %s max is %d", anim->name[a].rawArray(), MAX_ATFRAMES);
				anim->atframe[j].nframe = atoi(str);
				if ((anim->atframe[j].nframe > 1) && (anim->atframe[j].nframe < 9000))
					anim->atframe[j].nframe *= 3;
				anim->atframe[j].anim = _parser->ReadNumber();
				_parser->ReadArgument(str);
				anim->atframe[j].type = (uint8)GetTokenValue(FlagToken, str);
				anim->atframe[j].index = ReadIndex();
			}
			break;
		}
	}

//	for(a=0;a<MAX_SUBANIMS;a++)
//		DebugFile("Anim |%s| |%s| |%s|",s,anim->meshlink[a],anim->name[a]);

	return TRUE;
}

/* -----------------16/03/98 18.06-------------------
 *                  ParseInv
 * --------------------------------------------------*/
int StructureInitializer::ParseInv(char *s) {
	int inx = GetTokenValue(InvToken, s);
	int done = FALSE, arg, a, len;
	char str[J_MAXSTRLEN];
	struct SInvObject *inv;
	if (inx == TOKEN_NOT_FOUND)return _parser->ParseError("Inv %s doesn't exist!", s);
	inv = &_init.InvObj[inx];
	Match("{");
	while (!done) {
		if ((arg = _parser->SearchArgument(str, "}", "name:", "examine:", "examined:", "examinev:", "action:", "actiond:", "actionv:",
		                                   "meshlink:", "flags:", "text:", "log:", "uwobj:", "anim:", "animd:", "animv:", "anim2:", "anim2d:", "anim2v:",
		                                   NULL)) < 0)return _parser->ParseError("Keyword %s Unknown in %s", str, s);
		switch (arg) {
		case 0:
			done = TRUE;
			break;
		case 1:
			debug("\n// %s\n", s);
			inv->name = ReadObjName();
			break;
		case 2:
			csn = ocBOTH;
			inv->examine[DARRELL] = ReadSentence();
			inv->examine[VICTORIA] = inv->examine[DARRELL];
			break;
		case 3:
			csn = ocDARRELL;
			inv->examine[DARRELL] = ReadSentence();
			break;
		case 4:
			csn = ocVICTORIA;
			inv->examine[VICTORIA] = ReadSentence();
			break;
		case 5:
			csn = ocBOTH;
			inv->action[DARRELL] = ReadSentence();
			inv->action[VICTORIA] = inv->action[DARRELL];
			break;
		case 6:
			csn = ocDARRELL;
			inv->action[DARRELL] = ReadSentence();
			break;
		case 7:
			csn = ocVICTORIA;
			inv->action[VICTORIA] = ReadSentence();
			break;
		case 8:
			if ((len = _parser->ReadArgument(str)) < 0 || (size_t)len > sizeof(inv->meshlink)) return _parser->ParseError("Error reading meshlink %s in %s", str, s);
			else strcpy((char*)inv->meshlink.rawArray(), str);
			break;
		case 9:
			inv->flags = ReadFlags();
			break;
		case 10:
			for (a = 0; a < MAX_ICON_USER_SENTS; a++) if (!inv->text[a]) break;
			csn = ocBOTH;
			if (a < MAX_ICON_USER_SENTS) inv->text[a] = ReadSentence();
			else _parser->ParseError("Too many UserText in Inv %s %d max is %d", str, a, MAX_ICON_USER_SENTS);
			break;
		case 11:
			_parser->ReadArgument(str);
			debug("\n// %s\n", str);
			break;
		case 12:
			_parser->ReadArgument(str);
			inv->uwobj = GetTokenValue(ObjToken, str);
			break;
		case 13:
			_parser->ReadArgument(str);
			inv->anim[DARRELL] = GetTokenValue(AnimToken, str);
			inv->anim[VICTORIA] = inv->anim[DARRELL];
			break;
		case 14:
			_parser->ReadArgument(str);
			inv->anim[DARRELL] = GetTokenValue(AnimToken, str);
			break;
		case 15:
			_parser->ReadArgument(str);
			inv->anim[VICTORIA] = GetTokenValue(AnimToken, str);
			break;
		case 16:
			_parser->ReadArgument(str);
			inv->anim2[DARRELL] = GetTokenValue(AnimToken, str);
			inv->anim2[VICTORIA] = inv->anim2[DARRELL];
			break;
		case 17:
			_parser->ReadArgument(str);
			inv->anim2[DARRELL] = GetTokenValue(AnimToken, str);
			break;
		case 18:
			_parser->ReadArgument(str);
			inv->anim2[VICTORIA] = GetTokenValue(AnimToken, str);
			break;
		}
	}
	return TRUE;
}

/* -----------------16/03/98 18.11-------------------
 *                  ParseSound
 * --------------------------------------------------*/
int StructureInitializer::ParseSound(char *s) {
	int inx = GetTokenValue(WaveToken, s);
	int done = FALSE, arg, len, a;
	char str[J_MAXSTRLEN];
	struct SSound *sound;
	if (inx == TOKEN_NOT_FOUND)return _parser->ParseError("Sound %s doesn't exist!", s);
	sound = &_init.Sound[inx];
	Match("{");
	while (!done) {
		if ((arg = _parser->SearchArgument(str, "}", "name:", "flags:", "room:", "meshlink:", "cone:", "dist:", "angle:",
		                                   NULL)) < 0)return _parser->ParseError("Keyword %s Unknown in %s", str, s);
		switch (arg) {
		case 0:
			done = TRUE;
			break;
		case 1:
			len = _parser->ReadArgument(str);
			if (len < 0 || (size_t)len > sizeof(sound->name))return _parser->ParseError("Error reading sound 'filename' %s in %s", str, s);
			strcpy(sound->name, str);
			break;
		case 2:
			sound->flags = ReadFlags();
			break;
		case 3:
			AssignSound(inx);
			break;
		case 4:
			for (a = 0; a < MAX_SOUND_MESHLINKS; a++) if (sound->meshlink[a][0] == 0) break;
			if (a < MAX_SOUND_MESHLINKS)
				if ((len = _parser->ReadArgument(str)) < 0 || (size_t)len > sizeof(sound->meshlink[a]))return _parser->ParseError("Error reading meshlink %s in %s", str, s);
				else strcpy((char*)sound->meshlink[a].rawArray(), str);
			else _parser->ParseError("Too many Meshlink in Sound %s %d max is %d", s, a, MAX_SOUND_MESHLINKS);
			break;
		case 5:
			sound->ConeInside = _parser->ReadNumber();
			sound->ConeOutside = _parser->ReadNumber();
			sound->ConeOutsideVolume = _parser->ReadNumber();
			break;
		case 6:
			sound->MinDist = ReadFloat();
			sound->MaxDist = ReadFloat();
			break;
		case 7:
			sound->Angle = _parser->ReadNumber();
			break;
		}
	}
	return TRUE;
}

/* -----------------01/06/98 10.02-------------------
 *                  ParseItem
 * --------------------------------------------------*/
int StructureInitializer::ParseItem(int d) {
	char str[J_MAXSTRLEN];
	int done = FALSE, arg, a, cp = ocBOTH, i1, i2;
	struct SItemCommand *ic[MAX_PLAYERS];
	unsigned short com, p1, p2;

	_parser->ReadArgument(str);
	debug("\n// %s\n", str);
	a = GetTokenValue(MenuToken, str);
	if (a >= MAX_DLG_MENUS)
		return _parser->ParseError("Troppi Menu nel Dialogo %d MAX = %d", d, MAX_DLG_MENUS);

	_init.Dialog[d].ItemIndex[a] = DlgItemNum;
	DlgItemNum ++;
	if (DlgItemNum >= MAX_DLG_ITEMS)
		return _parser->ParseError("Troppi DlgItem nel Dialogo %d MAX = %d", d, MAX_DLG_ITEMS);

	ic[0] = (struct SItemCommand *)&_init.DlgItem[DlgItemNum - 1].item[0];
	ic[1] = (struct SItemCommand *)&_init.DlgItem[DlgItemNum - 1].item[1];

	for (i1 = 0; i1 < MAX_IC_PER_DLG_ITEM; i1++) if (!ic[DARRELL][i1].com) break;
	for (i2 = 0; i2 < MAX_IC_PER_DLG_ITEM; i2++) if (!ic[VICTORIA][i2].com) break;

	Match("{");
	while (!done) {
		if ((arg = _parser->SearchArgument(str, "}", "setplayer:", "anim:", "setcamera:", "movecamerato:", "settarget:",
		                                   "setchar:", "walkchar:", "runchar:", "backchar:", "hidechar:", "unhidechar:", "changeroom:",
		                                   "expression:", "changeplayer:", "debug:", "item:", "setflags:", "clrflags:", "atframe:", "nextdlg:", "setchar2:",
		                                   "introt1:", "introt2:",
		                                   "tanim:", "tanim2:", "twalkchar:", "trunchar:", "tbackchar:", "twaitcamera:", "twait:", "tfadout:", NULL)) < 0)
			return _parser->ParseError("ParseItem %d %d error %s", d, a, str);
		com = arg;
		p1 = 0;
		p2 = 0;
		switch (arg) {
		case IC_NULL:
			done = TRUE;
			break;
		case IC_SET_PLAYER:
			_parser->ReadArgument(str);
			cp = GetTokenValue(ObjToken, str);
			break;
		case IC_TIME_ANIM2:
		case IC_ANIM:
			_parser->ReadArgument(str);
			p1 = GetTokenValue(AnimToken, str);
			break;
		case IC_SET_CAMERA:
		case IC_TIME_WAIT_CAMERA:
		case IC_MOVE_CAMERA_TO:
			p1 = _parser->ReadNumber();
			break;
		case IC_CHANGE_PLAYER:
		case IC_HIDE_CHAR:
		case IC_UNHIDE_CHAR:
			_parser->ReadArgument(str);
			p1 = GetTokenValue(ObjToken, str);
			break;
		case IC_CHANGE_ROOM:
			_parser->ReadArgument(str);
			p1 = GetTokenValue(RoomToken, str);
			break;
		case IC_SET_TARGET:
		case IC_SET_CHAR2:
		case IC_SET_CHAR:
		case IC_WALK_CHAR:
		case IC_RUN_CHAR:
		case IC_BACK_CHAR:
		case IC_TIME_WALK_CHAR:
		case IC_TIME_RUN_CHAR:
		case IC_TIME_BACK_CHAR:
			_parser->ReadArgument(str);
			p1 = GetTokenValue(ObjToken, str);
			p2 = _parser->ReadNumber();
			break;
		case IC_TIME_ANIM:
			_parser->ReadArgument(str);
			p1 = GetTokenValue(AnimToken, str);
			csn = _init.Anim[p1].obj;
			if (csn > ocBOTH) csn = oNULL;
			p2 = ReadSentence();
			if (strlen(Sentence[SentenceNum - 1]) < 2) {
				p2 = 0;
				SentenceNum--;
			}
			break;
		case IC_TIME_FADOUT:
		case IC_TIME_WAIT:
			p1 = (unsigned short)(ReadFloat() * FRAME_PER_SECOND);
			break;
		case IC_EXPRESSION:
			_parser->ReadArgument(str);
			p1 = GetTokenValue(ObjToken, str);
			p2 = ReadFlags();
			break;
		case IC_DEBUG:
			csn = ocNOTRANS;
			p1 = ReadSentence();
			break;
		case IC_ITEM:
			_parser->ReadArgument(str);
			p1 = GetTokenValue(MenuToken, str);
			p2 = _parser->ReadNumber();
			break;
		case IC_SET_FLAGS:
		case IC_CLR_FLAGS:
			_parser->ReadArgument(str);
			p1 = GetTokenValue(DlgToken, str);
			p2 = ReadFlags();
			break;
		case IC_NEXT_DLG:
			_parser->ReadArgument(str);
			p1 = GetTokenValue(DlgToken, str);
			break;
		case IC_ATFRAME:
			_parser->ReadArgument(str);
			p1 = (uint8)GetTokenValue(FlagToken, str);
			p2 = ReadIndex();
			break;
		case IC_INTRO_TEXT1:
		case IC_INTRO_TEXT2:
			p1 = _parser->ReadNumber();
			p2 = ReadSysSent();
			if (strlen(SysSent[SysSentNum - 1]) < 2) {
				p2 = 0;
				SysSentNum--;
			}
			break;
		}
		if ((i1 >= MAX_IC_PER_DLG_ITEM) || (i2 >= MAX_IC_PER_DLG_ITEM))
			return _parser->ParseError("Troppi ItemCommands nel Dialogo %d item %d,%d MAX = %d", d, i1, i2, MAX_IC_PER_DLG_ITEM);
		if (cp == ocBOTH) {
			ic[DARRELL][i1].com = ic[VICTORIA][i2].com = (uint8)com;
			ic[DARRELL][i1].param1 = ic[VICTORIA][i2].param1 = p1;
			ic[DARRELL][i1++].param2 = ic[VICTORIA][i2++].param2 = p2;
		} else if (cp == ocVICTORIA) {
			ic[VICTORIA][i2].com = (uint8)com;
			ic[VICTORIA][i2].param1 = p1;
			ic[VICTORIA][i2++].param2 = p2;
		} else {
			ic[DARRELL][i1].com = (uint8)com;
			ic[DARRELL][i1].param1 = p1;
			ic[DARRELL][i1++].param2 = p2;
		}
	}
	return TRUE;
}

/* -----------------01/06/98 9.55--------------------
 *                  ParseDialog
 * --------------------------------------------------*/
int StructureInitializer::ParseDialog(char *s) {
	int inx = GetTokenValue(DlgToken, s);
	int arg, done = FALSE, a, alt;
	char str[J_MAXSTRLEN];
	struct SDialog *d;
	if (inx == TOKEN_NOT_FOUND)return _parser->ParseError("Dialog %s doesn't exist!", s);
	d = &_init.Dialog[inx];
	debug("\n// %s\n", s);
	Match("{");

	while (!done) {
		if ((arg = _parser->SearchArgument(str, "}", "flags:", "item:", "alt1pos:", "alt2pos:", "alt3pos:",
		                                   "alt1cam:", "alt2cam:", "alt3cam:", "alt1an:", "alt2an:", "alt3an:", "obj:", "log:",
		                                   NULL)) < 0) return _parser->ParseError("Keyword %s Unknown in %s", str, s);
		switch (arg) {
		case 0:
			done = TRUE;
			break;
		case 1:
			d->flags = ReadFlags();
			break;
		case 2:
			if (!ParseItem(inx)) return FALSE;
			break;

		case 3:
		case 4:
		case 5:
			d->AltPosSco[arg - 3] = _parser->ReadNumber();
			break;
		case 6:
		case 7:
		case 8:
			d->AltCamSco[arg - 6] = _parser->ReadNumber();
			break;
		case 9:
		case 10:
		case 11:
			for (a = 0, alt = arg - 9; a < MAX_ALT_ANIMS; a++)
				if (d->AltAnims[alt][a][0] == aNULL)
					break;
			if (a >= MAX_ALT_ANIMS)
				return _parser->ParseError("Too many Alternate Anims defined in Dialog %d max is %d", inx, MAX_ALT_ANIMS);
			_parser->ReadArgument(str);
			d->AltAnims[alt][a][0] = GetTokenValue(AnimToken, str);
			_parser->ReadArgument(str);
			d->AltAnims[alt][a][1] = GetTokenValue(AnimToken, str);
			break;
		case 12:
			_parser->ReadArgument(str);
			d->obj = GetTokenValue(ObjToken, str);
			break;
		case 13:
			_parser->ReadArgument(str);
			debug("\n// %s\n", str);
			break;
		}
	}
	return TRUE;
}

/* -----------------02/06/98 16.15-------------------
 *                  ParseDiary
 * --------------------------------------------------*/
int StructureInitializer::ParseDiary(char *s) {
	int inx = GetTokenValue(DiaryToken, s);
	int done = FALSE, arg, i, j;
	struct SDiary *e;
	char str[J_MAXSTRLEN];

	if (inx == TOKEN_NOT_FOUND)return _parser->ParseError("Diary %s doesn't exist!", s);

	e = &_init.Diary[inx];
	e->startt = _parser->ReadNumber();
	e->endt = _parser->ReadNumber();

	Match("{");
	while (!done) {
		if ((arg = _parser->SearchArgument(str, "}", "room:", "obj:", "rand:", "end_hideobj:", NULL)) < 0) return _parser->ParseError("Keyword %s Unknown in %s", str, s);
		switch (arg) {
		case 0:
			done = TRUE;
			break;
		case 1:
			_parser->ReadArgument(str);
			e->room = GetTokenValue(RoomToken, str);
			break;
		case 2:
			_parser->ReadArgument(str);
			e->obj = GetTokenValue(ObjToken, str);
			break;
		case 3:
			i = 0;
			while (e->item[i].anim[0] != aNULL)
				if (i++ >= MAX_DIARY_ITEMS)
					return _parser->ParseError("Too many DiaryItem in Diary %d max is %d", inx, MAX_DIARY_ITEMS);
			e->item[i].rand = _parser->ReadNumber();
			e->item[i].loop = _parser->ReadNumber();
			e->item[i].bnd = _parser->ReadNumber();

			while (_parser->ReadArgumentEOL(str) > 0) {
				j = 0;
				while (e->item[i].anim[j] != aNULL)
					if (j++ >= MAX_ANIMS_PER_DIARY_ITEM)
						return _parser->ParseError("Too many Anims per DiaryItem in Diary %d max is %d", inx, MAX_ANIMS_PER_DIARY_ITEM);
				e->item[i].anim[j] = GetTokenValue(AnimToken, str);
			}
			break;
		case 4:
			_parser->ReadArgument(str);
			e->end_hideobj = GetTokenValue(ObjToken, str);
			break;
		}
	}
	return TRUE;
}

/* -----------------04/06/98 10.04--------------------
 *                  ParseMenu
 * --------------------------------------------------*/
int StructureInitializer::ParseMenu(char *s) {
	int inx = GetTokenValue(MenuToken, s);
	char str[J_MAXSTRLEN];
	struct SDlgMenu *m;
	if (inx == TOKEN_NOT_FOUND)return _parser->ParseError("Menu %s doesn't exist!", s);
	m = &_init.DlgMenu[inx];

	csn = ocNOTRANS;
	m->titolo = ReadSentence();
	_parser->ReadArgument(str);
	m->parent = (uint8)GetTokenValue(MenuToken, str);
	m->on = _parser->ReadNumber();

	return TRUE;
}

/* -----------------26/04/00 16.36-------------------
 *                  ParsePDALog
 * --------------------------------------------------*/
int StructureInitializer::ParsePDALog(char *s) {
	int done = FALSE, arg, a;
	int inx = GetTokenValue(PDALogToken, s);
	char str[J_MAXSTRLEN];
	struct SPDALog *l;
	if (inx == TOKEN_NOT_FOUND)return _parser->ParseError("PDALog %s doesn't exist!", s);
	l = &_init.PDALog[inx];


	Match("{");
	while (!done) {
		if ((arg = _parser->SearchArgument(str, "}", "flags:", "time:", "menu_appartenenza:", "menu_creato:", "text:", NULL)) < 0) return _parser->ParseError("Keyword %s Unknown in %s", str, s);

		switch (arg) {
		case 0:
			done = TRUE;
			break;
		case 1:
			l->flags = ReadFlags();
			break;
		case 2:
			l->time = _parser->ReadNumber();
			break;
		case 3:
			l->menu_appartenenza = _parser->ReadNumber();
			break;
		case 4:
			l->menu_creato = _parser->ReadNumber();
			break;
		case 5:
			csn = ocNOTRANS;
			for (a = 0; a < MAX_PDA_INFO; a++)
				if (l->text[a] == 0)
					break;
			if (a >= MAX_PDA_INFO) return _parser->ParseError("Too many Info in PDALog item %s: cur %d (MAX %d)", s, a, MAX_PDA_INFO);
			l->text[a] = ReadSentence();
			break;
		}
	}

	return TRUE;
}

/* -----------------23/06/00 16.46-------------------
 *                  ParseMusic
 * --------------------------------------------------*/
int StructureInitializer::ParseMusic(char *s) {
	int done = FALSE, arg;
	int inx = GetTokenValue(MusicToken, s), len;
	char str[J_MAXSTRLEN];
	struct SMusic *n;
	if (inx == TOKEN_NOT_FOUND)return _parser->ParseError("Music %s doesn't exist!", s);
	n = &_init.Music[inx];

	Match("{");
	while (!done) {
		if ((arg = _parser->SearchArgument(str, "}", "sub0:", "sub1:", "sub2:", "sub3:", "sub4:", "sub5:", "sub6:", "sub7:", "sub8:", "sub9:", "room:",
		                                   NULL)) < 0) return _parser->ParseError("Keyword %s Unknown in %s", str, s);
		switch (arg) {
		case 0:
			done = TRUE;
			break;
		case 1:
		case 2:
		case 3:
		case 4:
		case 5:
		case 6:
		case 7:
		case 8:
		case 9:
		case 10:
			len = _parser->ReadArgument(str);
			if (len < 0 || (size_t)len > sizeof(n->name[arg - 1]))return _parser->ParseError("Error reading music 'filename' %s in %s", str, s);
			strcpy(n->name[arg - 1], str);
			n->vol[arg - 1] = _parser->ReadNumber();
			break;
		case 11:
			_parser->ReadArgument(str);
			_init.Room[GetTokenValue(RoomToken, str)].music = inx;
			break;
		}
	}

	return TRUE;
}

/* -----------------22/11/00 15.16-------------------
 *                  ParseCredits
 * --------------------------------------------------*/
int StructureInitializer::ParseCredits(char *s) {
	char str[J_MAXSTRLEN];
	int done, arg, len;
	uint8 curflags;

	curflags = 0;
	done = FALSE;
	Match("{");
	while (!done) {
		if ((arg = _parser->SearchArgument(str, "}",
		                                   "role:", "name:", "flags:",
		                                   NULL)) < 0)return _parser->ParseError("Keyword %s Unknown in %s", str, s);
		switch (arg) {
		case 0:
			done = TRUE;
			break;
		case 1:
			_init._creditsRoles = SerializableDynamicArray<SCreditsRole>((Credits_numRoles + 1));

			len = _parser->ReadArgument(str);
			if (len) {
				if (len >= 48) return _parser->ParseError("Credits role string too long (max is 47)");
				strcpy(_init._creditsRoles[Credits_numRoles].role, str);
			} else
				strcpy(_init._creditsRoles[Credits_numRoles].role, "");
			_init._creditsRoles[Credits_numRoles].flags = curflags;

			Credits_numRoles ++;

			if (!(curflags & CF_STATIC))    curflags = CF_NULL;
			break;
		case 2:
			_init._creditsNames = SerializableDynamicArray<SCreditsName>((Credits_numNames + 1));

			len = _parser->ReadArgument(str);
			if (len) {
				if (len >= 64) return _parser->ParseError("Credits name string too long (max is 31)");
				strcpy(_init._creditsNames[Credits_numNames].name, str);
			} else
				strcpy(_init._creditsNames[Credits_numNames].name, "");
			_init._creditsNames[Credits_numNames].role = Credits_numRoles - 1;
			_init._creditsNames[Credits_numNames].flags = curflags;

			Credits_numNames ++;

			if (!(curflags & CF_STATIC))    curflags = CF_NULL;
			break;
		case 3:
			curflags = (uint8)ReadFlags();
			break;
		}
	}

	return TRUE;
}

int SaveTextTable(const char *name) {
	warning("TODO: Implement SaveTextTable(%s)", name);
	return 0;
}


} // End of namespace Watchmaker
