[Scummvm-cvs-logs] CVS: scummvm/sword1 collision.h,NONE,1.1 debug.cpp,NONE,1.1 debug.h,NONE,1.1 eventman.cpp,NONE,1.1 eventman.h,NONE,1.1 logic.cpp,NONE,1.1 logic.h,NONE,1.1 memman.cpp,NONE,1.1 memman.h,NONE,1.1 menu.cpp,NONE,1.1 menu.h,NONE,1.1 mouse.cpp,NONE,1.1 mouse.h,NONE,1.1 music.cpp,NONE,1.1 music.h,NONE,1.1 object.h,NONE,1.1 objectman.cpp,NONE,1.1 objectman.h,NONE,1.1 resman.cpp,NONE,1.1 resman.h,NONE,1.1 router.cpp,NONE,1.1 router.h,NONE,1.1 screen.cpp,NONE,1.1 screen.h,NONE,1.1 sound.cpp,NONE,1.1 sound.h,NONE,1.1 staticres.cpp,NONE,1.1 sword1.cpp,NONE,1.1 sword1.h,NONE,1.1 sworddefs.h,NONE,1.1 swordres.h,NONE,1.1 text.cpp,NONE,1.1 text.h,NONE,1.1

Robert G?ffringmann lavosspawn at users.sourceforge.net
Mon Dec 15 18:10:01 CET 2003


Update of /cvsroot/scummvm/scummvm/sword1
In directory sc8-pr-cvs1:/tmp/cvs-serv18926/sword1

Added Files:
	collision.h debug.cpp debug.h eventman.cpp eventman.h 
	logic.cpp logic.h memman.cpp memman.h menu.cpp menu.h 
	mouse.cpp mouse.h music.cpp music.h object.h objectman.cpp 
	objectman.h resman.cpp resman.h router.cpp router.h screen.cpp 
	screen.h sound.cpp sound.h staticres.cpp sword1.cpp sword1.h 
	sworddefs.h swordres.h text.cpp text.h 
Log Message:
Broken Sword 1: initial import

--- NEW FILE: collision.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/collision.h,v 1.1 2003/12/16 02:09:24 lavosspawn Exp $
 *
 */

#ifndef BSCOLLISION_H
#define BSCOLLISION_H

/*#include "objectman.h"

class SwordLogic;

class SwordCollision {
public:
	SwordCollision(ObjectMan *pObjMan, SwordLogic *pLogic);
	~SwordCollision(void);
	void checkCollisions(void);
	void fnBumpOff(void);
	void fnBumpOn(void);
private:
	int32 getIntersect(int32 x0, int32 y0, int32 x1, int32 y1, int32 x2, int32 y2, int32 x3, int32 y3);
	int noCol;
	ObjectMan *_objMan;
	SwordLogic *_logic; // for CFN_preset_script
};*/
// maybe it's better to make this part of SwordRouter

#endif // BSCOLLISION_H

--- NEW FILE: debug.cpp ---
#include "stdafx.h"
#include "debug.h"
#include "common/util.h"

void SwordDebug::interpretScript(uint32 id, uint32 level, uint32 script, uint32 pc) {
	debug(8, "\nInterpreting %d@%d: script %X from %X", id, level, script, pc);
}

void SwordDebug::callMCode(uint32 mcodeNum, uint32 paramCount, int32 a, int32 b, int32 c, int32 d, int32 e, int32 f) {
	debug(9, "mcode: %s(%d, %d, %d, %d, %d, %d) [%d]", _mCodeNames[mcodeNum], a, b, c, d, e, f, paramCount);
}

const char SwordDebug::_mCodeNames[100][35] = {
	"fnBackground",
	"fnForeground",
	"fnSort",
	"fnNoSprite",
	"fnMegaSet",
	"fnAnim",
	"fnSetFrame",
	"fnFullAnim",
	"fnFullSetFrame",
	"fnFadeDown",
	"fnFadeUp",
	"fnCheckFade",
	"fnSetSpritePalette",
	"fnSetWholePalette",
	"fnSetFadeTargetPalette",
	"fnSetPaletteToFade",
	"fnSetPaletteToCut",
	"fnPlaySequence",
	"fnIdle",
	"fnPause",
	"fnPauseSeconds",
	"fnQuit",
	"fnKillId",
	"fnSuicide",
	"fnNewScript",
	"fnSubScript",
	"fnRestartScript",
	"fnSetBookmark",
	"fnGotoBookmark",
	"fnSendSync",
	"fnWaitSync",
	"cfnClickInteract",
	"cfnSetScript",
	"cfnPresetScript",
	"fnInteract",
	"fnIssueEvent",
	"fnCheckForEvent",
	"fnWipeHands",
	"fnISpeak",
	"fnTheyDo",
	"fnTheyDoWeWait",
	"fnWeWait",
	"fnChangeSpeechText",
	"fnTalkError",
	"fnStartTalk",
	"fnCheckForTextLine",
	"fnAddTalkWaitStatusBit",
	"fnRemoveTalkWaitStatusBit",
	"fnNoHuman",
	"fnAddHuman",
	"fnBlankMouse",
	"fnNormalMouse",
	"fnLockMouse",
	"fnUnlockMouse",
	"fnSetMousePointer",
	"fnSetMouseLuggage",
	"fnMouseOn",
	"fnMouseOff",
	"fnChooser",
	"fnEndChooser",
	"fnStartMenu",
	"fnEndMenu",
	"cfnReleaseMenu",
	"fnAddSubject",
	"fnAddObject",
	"fnRemoveObject",
	"fnEnterSection",
	"fnLeaveSection",
	"fnChangeFloor",
	"fnWalk",
	"fnTurn",
	"fnStand",
	"fnStandAt",
	"fnFace",
	"fnFaceXy",
	"fnIsFacing",
	"fnGetTo",
	"fnGetToError",
	"fnGetPos",
	"fnGetGamepadXy",
	"fnPlayFx",
	"fnStopFx",
	"fnPlayMusic",
	"fnStopMusic",
	"fnInnerSpace",
	"fnRandom",
	"fnSetScreen",
	"fnPreload",
	"fnCheckCD",
	"fnRestartGame",
	"fnQuitGame",
	"fnDeathScreen",
	"fnSetParallax",
	"fnTdebug",
	"fnRedFlash",
	"fnBlueFlash",
	"fnYellow",
	"fnGreen",
	"fnPurple",
	"fnBlack"
};
--- NEW FILE: debug.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/debug.h,v 1.1 2003/12/16 02:09:24 lavosspawn Exp $
 *
 */

#ifndef BSDEBUG_H
#define BSDEBUG_H

#include "scummsys.h"

class SwordDebug {
public:
    static void interpretScript(uint32 id, uint32 level, uint32 script, uint32 pc);
	static void callMCode(uint32 mcodeNum, uint32 paramCount, int32 a, int32 b, int32 c, int32 d, int32 e, int32 f);

private:
	static const char _mCodeNames[100][35];
};

#endif // BSDEBUG_H


--- NEW FILE: eventman.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/eventman.cpp,v 1.1 2003/12/16 02:09:24 lavosspawn Exp $
 *
 */

#include "stdafx.h"
#include "eventman.h"
#include "sworddefs.h"
#include "common/util.h"

EventManager::EventManager(void) {
	for (uint8 cnt = 0; cnt < TOTAL_EVENT_SLOTS; cnt++)
		_eventPendingList[cnt].delay = _eventPendingList[cnt].eventNumber = 0;
}

void EventManager::serviceGlobalEventList(void) {
	for (uint8 slot = 0; slot < TOTAL_EVENT_SLOTS; slot++)
		if (_eventPendingList[slot].delay)
			_eventPendingList[slot].delay--;
}

void EventManager::checkForEvent(BsObject *compact) {
	for (uint8 objCnt = 0; objCnt < O_TOTAL_EVENTS; objCnt++) {
		if (compact->o_event_list[objCnt].o_event)
			for (uint8 globCnt = 0; globCnt < TOTAL_EVENT_SLOTS; globCnt++) {
				if (_eventPendingList[globCnt].delay &&
					(_eventPendingList[globCnt].eventNumber == compact->o_event_list[objCnt].o_event)) {
						compact->o_logic = LOGIC_script;      //force into script mode
						_eventPendingList[globCnt].delay = 0; //started, so remove from queue
						compact->o_tree.o_script_level++;
						compact->o_tree.o_script_id[compact->o_tree.o_script_level] = 
							compact->o_event_list[objCnt].o_event_script;
						compact->o_tree.o_script_pc[compact->o_tree.o_script_level] = 
							compact->o_event_list[objCnt].o_event_script;
				}
			}
	}
}

bool EventManager::eventValid(int32 event) {
	for (uint8 slot = 0; slot < TOTAL_EVENT_SLOTS; slot++)
		if ((_eventPendingList[slot].eventNumber == event) &&
			(_eventPendingList[slot].delay))
			return true;
	return false;
}

int EventManager::fnCheckForEvent(BsObject *cpt, int32 id, int32 pause) {
	if (pause) {
		cpt->o_pause = pause;
		cpt->o_logic = LOGIC_pause_for_event;
        return SCRIPT_STOP;
	}

	for (uint8 objCnt = 0; objCnt < O_TOTAL_EVENTS; objCnt++) {
		if (cpt->o_event_list[objCnt].o_event)
			for (uint8 globCnt = 0; globCnt < TOTAL_EVENT_SLOTS; globCnt++) {
				if (_eventPendingList[globCnt].delay &&
					(_eventPendingList[globCnt].eventNumber == cpt->o_event_list[objCnt].o_event)) {
						cpt->o_logic = LOGIC_script;      //force into script mode
						_eventPendingList[globCnt].delay = 0; //started, so remove from queue
						cpt->o_tree.o_script_level++;
						cpt->o_tree.o_script_id[cpt->o_tree.o_script_level] = 
							cpt->o_event_list[objCnt].o_event_script;
						cpt->o_tree.o_script_pc[cpt->o_tree.o_script_level] = 
							cpt->o_event_list[objCnt].o_event_script;
						return SCRIPT_STOP;
				}
			}
	}
	return SCRIPT_CONT;
}

void EventManager::fnIssueEvent(BsObject *compact, int32 id, int32 event, int32 delay) {
	uint8 evSlot = 0;
	while (_eventPendingList[evSlot].delay)
		evSlot++;
	if (evSlot >= TOTAL_EVENT_SLOTS)
		error("EventManager ran out of event slots!");
	_eventPendingList[evSlot].delay = delay;
	_eventPendingList[evSlot].eventNumber = event;
}


--- NEW FILE: eventman.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/eventman.h,v 1.1 2003/12/16 02:09:24 lavosspawn Exp $
 *
 */

#ifndef BSEVENTMAN_H
#define BSEVENTMAN_H

#include "object.h"

#define TOTAL_EVENT_SLOTS 20

struct GlobalEvent {
	int32 eventNumber;
	int32 delay;
};

class EventManager {
public:
	EventManager(void);
	void serviceGlobalEventList(void);
	void checkForEvent(BsObject *compact);
	int fnCheckForEvent(BsObject *cpt, int32 id, int32 pause);
	void fnIssueEvent(BsObject *compact, int32 id, int32 event, int32 delay);
	bool eventValid(int32 event);
private:
	GlobalEvent _eventPendingList[TOTAL_EVENT_SLOTS];
};

#endif // BSEVENTMAN_H

--- NEW FILE: logic.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/logic.cpp,v 1.1 2003/12/16 02:09:24 lavosspawn Exp $
 *
[...1595 lines suppressed...]
}

const uint32 SwordLogic::_scriptVarInit[NON_ZERO_SCRIPT_VARS][2] = {
	{  42,  448}, {  43,  378}, {  51,    1}, {  92,    1}, { 147,   71}, { 201,   1},
	{ 209,    1}, { 215,    1}, { 242,    2}, { 244,    1}, { 246,    3}, { 247,   1},
	{ 253,    1}, { 297,    1}, { 398,    1}, { 508,    1}, { 605,    1}, { 606,   1},
	{ 701,    1}, { 709,    1}, { 773,    1}, { 843,    1}, { 907,    1}, { 923,   1},
	{ 966,    1}, { 988,    2}, {1058,    1}, {1059,    2}, {1060,    3}, {1061,   4},
	{1062,    5}, {1063,    6}, {1064,    7}, {1065,    8}, {1066,    9}, {1067,  10},
	{1068,   11}, {1069,   12}, {1070,   13}, {1071,   14}, {1072,   15}, {1073,  16},
	{1074,   17}, {1075,   18}, {1076,   19}, {1077,   20}, {1078,   21}, {1079,  22},
	{1080,   23}, {1081,   24}, {1082,   25}, {1083,   26}, {1084,   27}, {1085,  28},
	{1086,   29}, {1087,   30}, {1088,   31}, {1089,   32}, {1090,   33}, {1091,  34},
	{1092,   35}, {1093,   36}, {1094,   37}, {1095,   38}, {1096,   39}, {1097,  40},
	{1098,   41}, {1099,   42}, {1100,   43}, {1101,   44}, {1102,   48}, {1103,  45},
	{1104,   47}, {1105,   49}, {1106,   50}, {1107,   52}, {1108,   54}, {1109,  56},
	{1110,   57}, {1111,   58}, {1112,   59}, {1113,   60}, {1114,   61}, {1115,  62},
	{1116,   63}, {1117,   64}, {1118,   65}, {1119,   66}, {1120,   67}, {1121,  68},
	{1122,   69}, {1123,   71}, {1124,   72}, {1125,   73}, {1126,   74}
};

--- NEW FILE: logic.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/logic.h,v 1.1 2003/12/16 02:09:24 lavosspawn Exp $
 *
 */

#ifndef BSLOGIC_H
#define BSLOGIC_H
// combination of logic.c and scr_int.c

#include "sworddefs.h"
#include "objectman.h"
#include "common/util.h"

#define NON_ZERO_SCRIPT_VARS 95
#define NUM_SCRIPT_VARS		 1179

class SwordText;
class SwordSound;
class EventManager;
class SwordMenu;
class SwordRouter;
class SwordScreen;
class SwordMouse;
class SwordMusic;

class SwordLogic;
typedef int (SwordLogic::*BSMcodeTable)(BsObject *, int32, int32, int32, int32, int32, int32, int32);

class SwordLogic {
public:
	SwordLogic(ObjectMan *pObjMan, ResMan *resMan, SwordScreen *pScreen, SwordMouse *pMouse, SwordSound *pSound, SwordMusic *pMusic, SwordMenu *pMenu);
	~SwordLogic(void);
	void newScreen(uint32 newScreen);
	void engine(void);
	void updateScreenParams(void);
	void runMouseScript(BsObject *cpt, int32 scriptId);
	SwordRouter *giveRouter(void) { return _router; }; // for router debugging

	static uint32 _scriptVars[NUM_SCRIPT_VARS];
private:
	ObjectMan *_objMan;
	ResMan *_resMan;
	SwordScreen *_screen;
	SwordSound *_sound;
	SwordMouse *_mouse;
	SwordRouter *_router;
	SwordText *_textMan;
	EventManager *_eventMan;
	SwordMenu *_menu;
	SwordMusic *_music;
	uint32 _newScript; // <= ugly, but I can't avoid it.
	bool _speechRunning, _speechFinished, _textRunning;
	uint8 _speechClickDelay;
	Common::RandomSource _rnd;

	int scriptManager(BsObject *compact, uint32 id);
	void processLogic(BsObject *compact, uint32 id);
	int interpretScript(BsObject *compact, int id, Header *scriptModule, int scriptBase, int scriptNum);

	int logicWaitTalk(BsObject *compact);
	int logicStartTalk(BsObject *compact);
	int logicArAnimate(BsObject *compact, uint32 id);
	int speechDriver(BsObject *compact);
	int fullAnimDriver(BsObject *compact);
	int animDriver(BsObject *compact);

	static BSMcodeTable _mcodeTable[100];

	uint16 inRange(uint16 a, uint16 b, uint16 c);

//- mcodeTable:
	int fnBackground	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnForeground	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnSort			(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnNoSprite		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnMegaSet		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnAnim			(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnSetFrame		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnFullAnim		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnFullSetFrame	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnFadeDown		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnFadeUp		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnCheckFade		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnSetSpritePalette(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnSetWholePalette(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnSetFadeTargetPalette(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnSetPaletteToFade(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnSetPaletteToCut(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnPlaySequence	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);

	int fnIdle			(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnPause			(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnPauseSeconds	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnQuit			(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnKillId		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnSuicide		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnNewScript		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnSubScript		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnRestartScript	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnSetBookmark	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnGotoBookmark	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnSendSync		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnWaitSync		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	
	int cfnClickInteract(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int cfnSetScript	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int cfnPresetScript	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);

	int fnInteract		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnIssueEvent	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnCheckForEvent	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnWipeHands		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnISpeak		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnTheyDo		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnTheyDoWeWait	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnWeWait		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnChangeSpeechText(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnTalkError		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnStartTalk		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnCheckForTextLine(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnAddTalkWaitStatusBit(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnRemoveTalkWaitStatusBit(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);

	int fnNoHuman		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnAddHuman		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnBlankMouse	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnNormalMouse	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnLockMouse		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnUnlockMouse	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnSetMousePointer(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnSetMouseLuggage(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnMouseOn		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnMouseOff		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnChooser		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnEndChooser	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnStartMenu		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnEndMenu		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	
	int cfnReleaseMenu	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	
	int fnAddSubject	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnAddObject		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnRemoveObject	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnEnterSection	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnLeaveSection	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnChangeFloor	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnWalk			(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnTurn			(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnStand			(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnStandAt		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnFace			(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnFaceXy		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnIsFacing		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnGetTo			(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnGetToError	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnGetPos		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnGetGamepadXy	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnPlayFx		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnStopFx		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnPlayMusic		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnStopMusic		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnInnerSpace	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnRandom		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnSetScreen		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnPreload		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnCheckCD		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnRestartGame	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnQuitGame		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnDeathScreen	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnSetParallax	(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnTdebug		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);

	int fnRedFlash		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnBlueFlash		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnYellow		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnGreen			(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnPurple		(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	int fnBlack			(BsObject *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
	static const uint32 _scriptVarInit[NON_ZERO_SCRIPT_VARS][2];
};

#endif //BSLOGIC_H

--- NEW FILE: memman.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/memman.cpp,v 1.1 2003/12/16 02:09:24 lavosspawn Exp $
 *
 */

#include "stdafx.h"
#include "memman.h"
#include "common/util.h"

MemMan::MemMan(void) {
	_alloced = 0;
	_memListFree = _memListFreeEnd = NULL;
}

MemMan::~MemMan(void) {
}

void MemMan::alloc(BsMemHandle *bsMem, uint32 pSize, uint16 pCond) {
	_alloced += pSize;
	bsMem->data = (void*)malloc(pSize);
	if (!bsMem->data)
		error("MemMan::alloc(): Can't alloc %d bytes of memory.", pSize);
	bsMem->cond = pCond;
	bsMem->size = pSize;
	if (pCond == MEM_CAN_FREE) {
		warning("%d Bytes alloced as FREEABLE.", pSize); // why should one want to alloc mem if it can be freed?
		addToFreeList(bsMem);
	} else if (bsMem->next || bsMem->prev) // it's in our _freeAble list, remove it from there
        removeFromFreeList(bsMem);
	checkMemoryUsage();
}

void MemMan::freeNow(BsMemHandle *bsMem) {
	if (bsMem->cond != MEM_FREED) {
		_alloced -= bsMem->size;
		removeFromFreeList(bsMem);
		free(bsMem->data);
		bsMem->cond = MEM_FREED;
	}
}

void MemMan::setCondition(BsMemHandle *bsMem, uint16 pCond) {
	if ((pCond == MEM_FREED) || (pCond > MEM_DONT_FREE))
		error("MemMan::setCondition: program tried to set illegal memory condition");
	if (bsMem->cond != pCond) {
		bsMem->cond = pCond;
		if (pCond == MEM_DONT_FREE)
			removeFromFreeList(bsMem);
		else if (pCond == MEM_CAN_FREE)
			addToFreeList(bsMem);
	}
}

void MemMan::checkMemoryUsage(void) {
	while ((_alloced > MAX_ALLOC) && _memListFree) {
		free(_memListFreeEnd->data);
		_memListFreeEnd->data = NULL;
		_memListFreeEnd->cond = MEM_FREED;
		_alloced -= _memListFreeEnd->size;
		removeFromFreeList(_memListFreeEnd);
	}
}

void MemMan::addToFreeList(BsMemHandle *bsMem) {
	if (bsMem->next || bsMem->prev) {
		warning("addToFreeList: mem block is already in freeList");
		return;
	}
	bsMem->prev = NULL;
	bsMem->next = _memListFree;
	if (bsMem->next)
		bsMem->next->prev = bsMem;
	_memListFree = bsMem;
	if (!_memListFreeEnd)
		_memListFreeEnd = _memListFree;
}

void MemMan::removeFromFreeList(BsMemHandle *bsMem) {
	/*BsMemHandle *forw = _memListFree;
	BsMemHandle *rev = _memListFreeEnd;

	while (forw || rev) {
		if (!(forw && rev))
			error("mem list is completely fubared");
		printf("%p <-> %p\n", forw, rev);
		forw = forw->next;
		rev = rev->prev;
	}
	printf("\n");*/
	if (!(bsMem->prev || bsMem->next))
		warning("removeFromFreeList: memory block wasn't in list");
	if (_memListFree == bsMem)
		_memListFree = bsMem->next;
	if (_memListFreeEnd == bsMem)
		_memListFreeEnd = bsMem->prev;

	if (bsMem->next)
		bsMem->next->prev = bsMem->prev;
	if (bsMem->prev)
		bsMem->prev->next = bsMem->next;
	bsMem->next = bsMem->prev = NULL;
}

void MemMan::initHandle(BsMemHandle *bsMem) {
	memset(bsMem, 0, sizeof(BsMemHandle));
}


--- NEW FILE: memman.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/memman.h,v 1.1 2003/12/16 02:09:24 lavosspawn Exp $
 *
 */

#ifndef MEMMAN_H
#define MEMMAN_H

#include "scummsys.h"

struct BsMemHandle {
	void *data;
	uint32 size;
	uint32 refCount;
	uint16 cond;
	BsMemHandle *next, *prev;
};
// mem conditions:
#define MEM_FREED		0
#define MEM_CAN_FREE	1
#define MEM_DONT_FREE	2

#define MAX_ALLOC (6*1024*1024) // max amount of mem we want to alloc().

class MemMan {
public:
	MemMan(void);
	~MemMan(void);
	void alloc(BsMemHandle *bsMem, uint32 pSize, uint16 pCond = MEM_DONT_FREE);
	void setCondition(BsMemHandle *bsMem, uint16 pCond);
	void freeNow(BsMemHandle *bsMem);
	void initHandle(BsMemHandle *bsMem);
private:
	void addToFreeList(BsMemHandle *bsMem);
	void removeFromFreeList(BsMemHandle *bsMem);
	void checkMemoryUsage(void);
	uint32 _alloced;  //currently allocated memory
	BsMemHandle *_memListFree;
	BsMemHandle *_memListFreeEnd;
};

#endif //MEMMAN_H

--- NEW FILE: menu.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/menu.cpp,v 1.1 2003/12/16 02:09:24 lavosspawn Exp $
 *
 */

#include "stdafx.h"
#include "menu.h"
#include "resman.h"
#include "scummsys.h"
#include "common/util.h"
#include "system.h"
#include "mouse.h"
#include "screen.h"
#include "logic.h"

SwordMenuIcon::SwordMenuIcon(uint8 menuType, uint8 menuPos, uint32 resId, uint32 frame, SwordScreen *screen) {
	_menuType = menuType;
	_menuPos = menuPos;
	_resId = resId;
	_frame = frame;
	_screen = screen;
	_selected = false;
}

bool SwordMenuIcon::wasClicked(uint16 mouseX, uint16 mouseY) {
	return false;
}

void SwordMenuIcon::setSelect(bool pSel) {
	_selected = pSel;
}

void SwordMenuIcon::draw(void) {
	uint16 x = _menuPos * 40;
	uint16 y = (_menuType == MENU_TOP)?(0):(440);
	_screen->showFrame(x, y, _resId, _frame + (_selected ? 1 : 0));
}

SwordMenu::SwordMenu(SwordScreen *pScreen, SwordMouse *pMouse) {
	_screen = pScreen;
	_mouse = pMouse;
	for (uint8 cnt = 0; cnt < 16; cnt++)
		_subjects[cnt] = NULL;
}

uint8 SwordMenu::checkMenuClick(uint8 menuType) {
	uint16 mouseEvent = _mouse->testEvent();
	if (!mouseEvent)
		return 0;
	uint16 x, y;
	_mouse->giveCoords(&x, &y);
	if (menuType == MENU_BOT) {
		for (uint8 cnt = 0; cnt < SwordLogic::_scriptVars[IN_SUBJECT]; cnt++)
			if (_subjects[cnt]->wasClicked(x, y))
				if (mouseEvent == BS1L_BUTTON_DOWN) {
					SwordLogic::_scriptVars[OBJECT_HELD] = _subjectBar[cnt];
					buildSubjects();
					return 0;
				} else if (mouseEvent == BS1L_BUTTON_UP) {
					if (SwordLogic::_scriptVars[OBJECT_HELD] == _subjectBar[cnt])
						return cnt + 1;
					else {
						SwordLogic::_scriptVars[OBJECT_HELD] = 0;
						buildSubjects();
						return 0;
					}
				}
	} else {
		return 0;
	}
	return 0;
}

void SwordMenu::buildSubjects(void) {
	uint8 subDest = 0;
	clearMenu(MENU_BOT);
	for (uint8 cnt = 0; cnt < 16; cnt++)
		if (_subjects[cnt]) {
			delete _subjects[cnt];
			_subjects[cnt] = NULL;
		}
	for (uint8 cnt = 0; cnt < SwordLogic::_scriptVars[IN_SUBJECT]; cnt++) {
		uint32 res = _subjectList[(_subjectBar[cnt] & 65535) - BASE_SUBJECT].subjectRes;
		uint32 frame = _subjectList[(_subjectBar[cnt] & 65535) - BASE_SUBJECT].frameNo;
		_subjects[cnt] = new SwordMenuIcon(MENU_BOT, cnt, res, frame, _screen);
		_subjects[cnt]->setSelect(SwordLogic::_scriptVars[OBJECT_HELD] == (_subjectBar[cnt]&0xFFFF));
		_subjects[cnt]->draw();
	}
	//_system->update_screen();
}

void SwordMenu::refresh(uint8 menuType) {
	//warning("stub: SwordMenu::refresh())");
}

void SwordMenu::clearMenu(uint8 menuType) {
	warning("stub: SwordMenu::clearMenu()");
}

void SwordMenu::fnStartMenu(void) {
	warning("stub: SwordMenu::fnStartMenu()");
}

void SwordMenu::fnEndMenu(void) {
	warning("stub: SwordMenu::clearMenu()");
}

void SwordMenu::fnChooser(BsObject *compact) {
	SwordLogic::_scriptVars[OBJECT_HELD] = 0;
	buildSubjects();
	compact->o_logic = LOGIC_choose;
}

void SwordMenu::fnEndChooser(void) {
	SwordLogic::_scriptVars[OBJECT_HELD] = 0;
	clearMenu(MENU_BOT);
	clearMenu(MENU_TOP);
	//_system->update_screen();
	for (uint8 cnt = 0; cnt < 16; cnt++)
		if (_subjects[cnt]) {
			delete _subjects[cnt];
			_subjects[cnt] = NULL;
		}
}

int SwordMenu::logicChooser(BsObject *compact) {
	if (checkMenuClick(MENU_BOT)) {
		compact->o_logic = LOGIC_script;
		return 1;
	} else 
		return 0;
}

void SwordMenu::fnAddSubject(int32 sub) {
	_subjectBar[SwordLogic::_scriptVars[IN_SUBJECT]] = sub;
	SwordLogic::_scriptVars[IN_SUBJECT]++;
}

void SwordMenu::cfnReleaseMenu(void) {
	clearMenu(MENU_TOP);
	//_system->update_screen();
}

--- NEW FILE: menu.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/menu.h,v 1.1 2003/12/16 02:09:24 lavosspawn Exp $
 *
 */

#ifndef BSMENU_H
#define BSMENU_H

#include "sworddefs.h"
#include "object.h"

class SwordScreen;
class SwordMouse;
class ResMan;

#define MENU_TOP 0
#define MENU_BOT 1

struct Subject {
	uint32 subjectRes;
	uint32 frameNo;
};

class SwordMenuIcon {
public:
	SwordMenuIcon(uint8 menuType, uint8 menuPos, uint32 resId, uint32 frame, SwordScreen *screen);
	bool wasClicked(uint16 mouseX, uint16 mouseY);
	void setSelect(bool pSel);
	void draw(void);

private:
	uint8 _menuType, _menuPos;
	uint32 _resId, _frame;
	bool _selected;
	SwordScreen *_screen;
};

class SwordMenu {
public:
	SwordMenu(SwordScreen *pScreen, SwordMouse *pMouse);
	void fnChooser(BsObject *compact);
	void fnEndChooser(void);
	void fnAddSubject(int32 sub);
	void cfnReleaseMenu(void);
	int logicChooser(BsObject *compact);
	void engine(void);
	void refresh(uint8 menuType);
	void fnStartMenu(void);
	void fnEndMenu(void);

private:
	void buildSubjects(void);
	void clearMenu(uint8 menuType);
	uint8 checkMenuClick(uint8 menuType);
	SwordMenuIcon *_subjects[16];
	uint32 _subjectBar[16];

	SwordScreen *_screen;
	SwordMouse *_mouse;
	static const Subject _subjectList[TOTAL_subjects];

};

#endif //BSMENU_H

--- NEW FILE: mouse.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/mouse.cpp,v 1.1 2003/12/16 02:09:24 lavosspawn Exp $
 *
 */

#include "stdafx.h"
#include "mouse.h"
#include "menu.h"
#include "screen.h"
#include "logic.h"
#include "resman.h"
#include "objectman.h"
#include "sworddefs.h"
#include "system.h"
#include "swordres.h"

SwordMouse::SwordMouse(OSystem *system, ResMan *pResMan, ObjectMan *pObjMan) {
	_resMan = pResMan;
	_objMan = pObjMan;
	_system = system;
	_numObjs = 0;
	_mouseStatus = 0; // mouse off and unlocked
	_getOff = 0;

	for (uint8 cnt = 0; cnt < 17; cnt++) {
        _pointers[cnt] = (MousePtr*)_resMan->openFetchRes(MSE_POINTER + cnt);
#ifdef SCUMM_BIG_ENDIAN
		uint16 *data = (uint16*)pointers[cnt];
		for (uint8 endCnt = 0; endCnt < 5; endCnt++)
			data[endCnt] = READ_LE_UINT16(data + endCnt);
#endif
		fixTransparency(_pointers[cnt]->data + 0x30, _pointers[cnt]->sizeX * _pointers[cnt]->sizeY * _pointers[cnt]->numFrames);
	}
	/*_resMan->resOpen(MSE_POINTER);		// normal mouse (1 frame anim)
	_resMan->resOpen(MSE_OPERATE);
	_resMan->resOpen(MSE_PICKUP);
	_resMan->resOpen(MSE_EXAMINE);
	_resMan->resOpen(MSE_MOUTH);
	_resMan->resOpen(MSE_BECKON_L);
	_resMan->resOpen(MSE_BECKON_R);
	_resMan->resOpen(MSE_ARROW0);
	_resMan->resOpen(MSE_ARROW1);
	_resMan->resOpen(MSE_ARROW2);
	_resMan->resOpen(MSE_ARROW3);
	_resMan->resOpen(MSE_ARROW4);
	_resMan->resOpen(MSE_ARROW5);
	_resMan->resOpen(MSE_ARROW6);
	_resMan->resOpen(MSE_ARROW7);
	_resMan->resOpen(MSE_ARROW8);		// UPWARDS
	_resMan->resOpen(MSE_ARROW9);*/		// DOWNWARDS
	// luggage & chess stuff is opened dynamically
}

void SwordMouse::useLogic(SwordLogic *pLogic) {
	_logic = pLogic;
}

void SwordMouse::addToList(int id, BsObject *compact) {
	_objList[_numObjs].id = id;
	_objList[_numObjs].compact = compact;
	_numObjs++;
}

void SwordMouse::flushEvents(void) {
	_lastState = _state = 0;
}

void SwordMouse::engine(uint16 x, uint16 y, uint16 eventFlags) {
	//warning("Stub: SwordMouse::engine");
	_state = 0; // all mouse events are flushed after one cycle.
	if (_lastState) { // delay all events by one cycle to notice L_button + R_button clicks correctly.
		_state = _lastState | eventFlags;
		_lastState = 0;
	} else if (eventFlags)
		_lastState = eventFlags;
	if (!(_mouseStatus & 1)) {  // no human?
		// if the mouse is turned off, I want the menu automatically removed,
		// except while in conversation, while examining a menu object or while combining two menu objects!
		/*if ((!subject_status)&&(!menu_looking)&&(!second_icon))
		{
			HideMenu(TOP_MENU);
			menu_status=0;
		}*/
		_numObjs = 0;
		return;	// no human, so we don't want the mouse engine
	}
	// todo: check menus here.
	SwordLogic::_scriptVars[MOUSE_X] = SwordLogic::_scriptVars[SCROLL_OFFSET_X] + x + 128;
	SwordLogic::_scriptVars[MOUSE_Y] = SwordLogic::_scriptVars[SCROLL_OFFSET_Y] + y + 128 - 40;

	//-
	int32 touchedId = 0;
	uint16 clicked;
	if (y > 40) {
		for (uint16 priority = 0; (priority < 10) && (!touchedId); priority++) {
			for (uint16 cnt = 0; cnt < _numObjs; cnt++) {
				if ((_objList[cnt].compact->o_priority == priority) && 
					(SwordLogic::_scriptVars[MOUSE_X] >= (uint32)_objList[cnt].compact->o_mouse_x1) &&
					(SwordLogic::_scriptVars[MOUSE_X] <= (uint32)_objList[cnt].compact->o_mouse_x2) &&
					(SwordLogic::_scriptVars[MOUSE_Y] >= (uint32)_objList[cnt].compact->o_mouse_y1) &&
					(SwordLogic::_scriptVars[MOUSE_Y] <= (uint32)_objList[cnt].compact->o_mouse_y2)) {
						touchedId = _objList[cnt].id;
						clicked = cnt;
				}
			}
		}
		if (touchedId != SwordLogic::_scriptVars[SPECIAL_ITEM]) { //the mouse collision situation has changed in one way or another
			SwordLogic::_scriptVars[SPECIAL_ITEM] = touchedId;
			debug(9, "New special item: %X\n", touchedId);
			if (_getOff) { // there was something else selected before, run its get-off script
				_logic->runMouseScript(NULL, _getOff);
				_getOff = 0;
			}
			if (touchedId) { // there's something new selected, now.
				BsObject *compact = _objMan->fetchObject(SwordLogic::_scriptVars[SPECIAL_ITEM]);

				if	(_objList[clicked].compact->o_mouse_on)	//run its get on
					_logic->runMouseScript(_objList[clicked].compact, _objList[clicked].compact->o_mouse_on);

				_getOff = _objList[clicked].compact->o_mouse_off; //setup get-off for later
			}
		}
	} else
		SwordLogic::_scriptVars[SPECIAL_ITEM] = 0;
	if (_state & (BS1L_BUTTON_DOWN | BS1R_BUTTON_DOWN)) {
		// todo: handle menus
		SwordLogic::_scriptVars[MOUSE_BUTTON] = _state;
		if (SwordLogic::_scriptVars[SPECIAL_ITEM]) {
			BsObject *compact = _objMan->fetchObject(SwordLogic::_scriptVars[SPECIAL_ITEM]);
			_logic->runMouseScript(compact, compact->o_mouse_click);
		}
	}
	_numObjs = 0;
}

uint16 SwordMouse::testEvent(void) {
	return _state;
}

void SwordMouse::setLuggage(uint32 resId, uint32 rate) {
	warning("stub: SwordMouse::setLuggage(%d, %d)", resId, rate);
}

void SwordMouse::setPointer(uint32 resId, uint32 rate) {
	_currentPtrId = resId - MSE_POINTER;
	_rate = rate;
	_rateCnt = 1;
	_frame = 0;
	if (resId == 0) {
		_system->set_mouse_cursor(NULL, 0, 0, 0, 0);
		_system->show_mouse(false);
	} else {
        animate();
		_system->show_mouse(true);
	}
}

void SwordMouse::animate(void) {
	if (_rateCnt && (_mouseStatus == 1)) {
		_rateCnt--;
		if (!_rateCnt) {
			_rateCnt = _rate;
			_frame = (_frame + 1) % _pointers[_currentPtrId]->numFrames;
			uint16 size = _pointers[_currentPtrId]->sizeX * _pointers[_currentPtrId]->sizeY;
			_system->set_mouse_cursor(_pointers[_currentPtrId]->data + 0x30 + _frame * size, _pointers[_currentPtrId]->sizeX, _pointers[_currentPtrId]->sizeY, _pointers[_currentPtrId]->hotSpotX, _pointers[_currentPtrId]->hotSpotY);
		}
	}
}

void SwordMouse::fnNoHuman(void) {
	if (_mouseStatus & 2) // locked, can't do anything
		return ;
	_mouseStatus = 0; // off & unlocked
	setLuggage(0, 0);
	setPointer(0, 0);
}

void SwordMouse::fnAddHuman(void) {
	if (_mouseStatus & 2) // locked, can't do anything
		return ;
	_mouseStatus = 1;
	SwordLogic::_scriptVars[SPECIAL_ITEM] = -1;
	_getOff = SCR_std_off;
	setPointer(MSE_POINTER, 0);
	_mouseCount = 3;

}

void SwordMouse::fnBlankMouse(void) {
	setPointer(0, 0);
}

void SwordMouse::fnNormalMouse(void) {
	setPointer(MSE_POINTER, 0);
}

void SwordMouse::fnLockMouse(void) {
	_mouseStatus |= 2;
}

void SwordMouse::fnUnlockMouse(void) {
    _mouseStatus &= 1;
}

void SwordMouse::giveCoords(uint16 *x, uint16 *y) {
	*x = _mouseX;
	*y = _mouseY;
}

void SwordMouse::fixTransparency(uint8 *data, uint32 size) {
	for (uint32 cnt = 0; cnt < size; cnt++)
		if (data[cnt] == 0)
			data[cnt] = 255;
}

--- NEW FILE: mouse.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/mouse.h,v 1.1 2003/12/16 02:09:24 lavosspawn Exp $
 *
 */

#ifndef BSMOUSE_H
#define BSMOUSE_H

#include "scummsys.h"
#include "sworddefs.h"
#include "object.h"

#define MAX_MOUSE 30

#define BS1L_BUTTON_DOWN		2
#define BS1L_BUTTON_UP			4
#define BS1R_BUTTON_DOWN		8
#define BS1R_BUTTON_UP			16
#define MOUSE_BOTH_BUTTONS		(BS1L_BUTTON_DOWN | BS1R_BUTTON_DOWN)

struct MouseObj {
	int id;
	BsObject *compact;
};

#if !defined(__GNUC__)
	#pragma START_PACK_STRUCTS
#endif

struct MousePtr {
	uint16 numFrames;
	uint16 sizeX;
	uint16 sizeY;
	uint16 hotSpotX;
	uint16 hotSpotY;
	uint8  data[2]; // arbitrary number.
} GCC_PACK;

#if !defined(__GNUC__)
	#pragma END_PACK_STRUCTS
#endif

class SwordLogic;
class ResMan;
class ObjectMan;
class OSystem;

class SwordMouse {
public:
	SwordMouse(OSystem *system, ResMan *pResMan, ObjectMan *pObjMan);
    void addToList(int id, BsObject *compact);
    void useLogic(SwordLogic *pLogic);
	void setLuggage(uint32 resID, uint32 rate);
	void setPointer(uint32 resID, uint32 rate);
	void animate(void);
	void engine(uint16 x, uint16 y, uint16 eventFlags);
	uint16 testEvent(void);
	void flushEvents(void);
	void giveCoords(uint16 *x, uint16 *y);
	void fnNoHuman(void);
	void fnAddHuman(void);
	void fnBlankMouse(void);
	void fnNormalMouse(void);
	void fnLockMouse(void);
	void fnUnlockMouse(void);
private:
	void fixTransparency(uint8 *data, uint32 size);
	MousePtr *_pointers[17];
	uint32 _currentPtrId, _rate, _rateCnt, _frame;
	OSystem *_system;
	SwordLogic *_logic;
	MouseObj _objList[MAX_MOUSE];
	ResMan *_resMan;
	ObjectMan *_objMan;
	uint16 _mouseX, _mouseY;

	uint8 _mouseStatus, _mouseCount;
	uint16 _numObjs;
	uint16 _lastState, _state;
	uint32 _getOff;
};

#endif //BSMOUSE_H

--- NEW FILE: music.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/music.cpp,v 1.1 2003/12/16 02:09:25 lavosspawn Exp $
 *
 */

// todo: add fadeout, crossfading.
// this code always loops. make it depend on _loopFlag

#include "stdafx.h"
#include "music.h"
#include "sound/mixer.h"
#include "common/util.h"
#include "common/file.h"

SwordMusic::SwordMusic(OSystem *system, SoundMixer *pMixer) {
	_system = system;
	_mixer = pMixer;
	_mixer->setupPremix(passMixerFunc, this);
	_fading = 0;
	_playing = false;
	_loop = false;
	_mutex = _system->create_mutex();
	_waveSize = _wavePos = _bufPos = _smpInBuf = 0;
	assert(_mixer->getOutputRate() == 22050);
}

void SwordMusic::passMixerFunc(void *param, int16 *buf, uint len) {
	((SwordMusic*)param)->mixer(buf, len);
}

void SwordMusic::mixer(int16 *buf, uint len) {
	if (!_playing)
		memset(buf, 0, 2 * len * sizeof(int16));
	else {
		_system->lock_mutex(_mutex);
		len >>= 1;
		if (len > _smpInBuf)
			warning("SwordMusic::mixer: sample buffer underrun");
		else {
			uint32 maxLen = BUFSIZE - _bufPos;
			if (len >= maxLen) {
				for (uint32 cnt = 0; cnt < maxLen; cnt++)
					buf[(cnt << 2) | 0] = buf[(cnt << 2) | 1] =
					buf[(cnt << 2) | 2] = buf[(cnt << 2) | 3] = _musicBuf[_bufPos + cnt];
				_smpInBuf -= maxLen;
				_bufPos = 0;
				len -= maxLen;
				buf += maxLen * 4;
			}
			if (len) {
				for (uint32 cnt = 0; cnt < len; cnt++)
					buf[(cnt << 2) | 0] = buf[(cnt << 2) | 1] =
					buf[(cnt << 2) | 2] = buf[(cnt << 2) | 3] = _musicBuf[_bufPos + cnt];
				_smpInBuf -= len;
				_bufPos += len;
			}
		}
		_system->unlock_mutex(_mutex);
	}
}

void SwordMusic::stream(void) {
	// make sure we've got enough samples in buffer.
	if ((_smpInBuf < SAMPLERATE) && _playing) {
		_system->lock_mutex(_mutex);
		uint32 loadTotal = BUFSIZE - _smpInBuf;
		while (uint32 doLoad = loadTotal) {
			if (BUFSIZE - ((_bufPos + _smpInBuf) % BUFSIZE) < loadTotal)
				doLoad = BUFSIZE - (_bufPos + _smpInBuf) % BUFSIZE;
			if (_waveSize - _wavePos < doLoad)
				doLoad = _waveSize - _wavePos;
			int16 *dest = _musicBuf + ((_bufPos + _smpInBuf) % BUFSIZE);
			_musicFile.read(dest, doLoad * 2);
			_wavePos += doLoad;
			if (_wavePos == _waveSize) {
				_wavePos = 0;
				_musicFile.seek(WAVEHEADERSIZE);
			}
			loadTotal -= doLoad;
			_smpInBuf += doLoad;
		}
		_system->unlock_mutex(_mutex);
	}
}

void SwordMusic::startMusic(int32 tuneId, int32 loopFlag) {
	_system->lock_mutex(_mutex);
	_loop = (loopFlag > 0);
	if (tuneId) {
		if (_musicFile.isOpen())
			_musicFile.close();
		char fName[20];
		sprintf(fName, "MUSIC1\\%s.wav", _tuneList[tuneId]);
		_musicFile.open(fName);
		if (_musicFile.isOpen()) {
			_musicFile.seek(0x28);
			_waveSize = _musicFile.readUint32LE() / 2;
			_wavePos = 0;
			_smpInBuf = 0;
			_bufPos = 0;
			_playing = true;
		} else
			_playing = false;
	} else
		_playing = false;
	_system->unlock_mutex(_mutex);
	stream();
}

void SwordMusic::fadeDown(void) {
	warning("stub: SwordMusic::fadeDown");
}


--- NEW FILE: music.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/music.h,v 1.1 2003/12/16 02:09:25 lavosspawn Exp $
 *
 */

#ifndef BSMUSIC_H
#define BSMUSIC_H

#include "scummsys.h"
#include "common/system.h"
#include "common/file.h"
#define TOTAL_TUNES 270

#define SAMPLERATE 11025
#define BUFSIZE (4 * SAMPLERATE)
#define WAVEHEADERSIZE 0x2C

class SoundMixer;
//class File;

class SwordMusic {
public:
	SwordMusic(OSystem *system, SoundMixer *pMixer);
	void stream(void);
	void startMusic(int32 tuneId, int32 loopFlag);
	void fadeDown(void);
private:
	File _musicFile;
	OSystem *_system;
	SoundMixer *_mixer;
	uint16 _fading;
	bool _playing;
	bool _loop;
	OSystem::MutexRef _mutex;
	static void passMixerFunc(void *param, int16 *buf, uint len);
	void mixer(int16 *buf, uint len);
	static const char _tuneList[TOTAL_TUNES][8]; // in staticres.cpp
	uint32 _waveSize, _wavePos;
	uint32 _bufPos, _smpInBuf;
	int16 _musicBuf[BUFSIZE]; // samples for 8 seconds
};

#endif // BSMUSIC_H

--- NEW FILE: object.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/object.h,v 1.1 2003/12/16 02:09:25 lavosspawn Exp $
 *
 */

#ifndef BSOBJECT_H
#define BSOBJECT_H

#include "scummsys.h"

#define	O_TOTAL_EVENTS	5
#define	O_WALKANIM_SIZE	600			//max number of nodes in router output
#define	O_GRID_SIZE		200
#define	EXTRA_GRID_SIZE	20
//--------------------------------------------------------------------------------------

struct OEventSlot {			//receiving event list in the compact - 
	int32	o_event;		//array of these with O_TOTAL_EVENTS elements
	int32	o_event_script;
};

#define	TOTAL_script_levels	5
//-----
struct ScriptTree {								//this is a logic tree, used by OBJECTs
	int32	o_script_level;						//logic level
	int32	o_script_id[TOTAL_script_levels];	//script id's (are unique to each level)
	int32	o_script_pc[TOTAL_script_levels];	//pc of script for each (if script_manager)
};	// size = 11*int32 = 44 bytes
//--------------------------------------------------------------------------------------
struct TalkOffset {
	int32	x;
	int32	y;
};	// size = 2*int32 = 8 bytes
//--------------------------------------------------------------------------------------
struct WalkData {
	int32	frame;
	int32	x;
	int32	y;
	int32	step;
	int32	dir;
};	// size = 5*int32 = 20 bytes

struct BsObject {
	int32	o_type;						// 0  broad description of type - object, floor, etc.
	int32	o_status;					// 4  bit flags for logic, graphics, mouse, etc.
	int32	o_logic;					// 8  logic type
	int32	o_place;					// 12 where is the mega character
	int32	o_down_flag;				// 16 pass back down with this - with C possibly both are unnecessary?
	int32	o_target;					// 20 target object for the GTM			*these are linked to script
	int32	o_screen;					// 24 physical screen/section
	int32	o_frame;					// 28 frame number &
	int32	o_resource;					// 32 id of spr file it comes from
	int32	o_sync;						// 36 receive sync here
	int32	o_pause;					// 40 logic_engine() pauses these cycles
	int32	o_xcoord;					// 44 
	int32	o_ycoord;					// 48
	int32	o_mouse_x1;					// 52 top-left of mouse area is (x1,y1)
	int32	o_mouse_y1;					// 56 
	int32	o_mouse_x2;					// 60 bottom-right of area is (x2,y2)	(these coords are inclusive)
	int32	o_mouse_y2;					// 64 
	int32	o_priority;					// 68
	int32	o_mouse_on;					// 72
	int32	o_mouse_off;				// 76
	int32	o_mouse_click;				// 80
	int32	o_interact;					// 84
	int32	o_get_to_script;			// 88
	int32	o_scale_a;					// 92 used by floors
	int32	o_scale_b;					// 96 
	int32	o_anim_x;					// 100
	int32	o_anim_y;					// 104

	ScriptTree	o_tree;					// 108	size = 44 bytes
	ScriptTree	o_bookmark;				// 152	size = 44 bytes

	int32	o_dir;					 	// 196
	int32	o_speech_pen;				// 200
	int32	o_speech_width;				// 204
	int32	o_speech_time;				// 208
	int32	o_text_id;					// 212 working back from o_ins1
	int32	o_tag;					 	// 216
	int32	o_anim_pc;					// 220 position within an animation structure
	int32	o_anim_resource;			// 224 cdt or anim table

	int32	o_walk_pc;					// 228

	TalkOffset	talk_table[6];			// 232	size = 6*8 bytes = 48

	OEventSlot o_event_list[O_TOTAL_EVENTS];	// 280	size = 5*8 bytes = 40

	int32	o_ins1;						// 320
	int32	o_ins2;						// 324
	int32	o_ins3;						// 328

	int32	o_mega_resource;			// 332
	int32	o_walk_resource;			// 336

	WalkData	o_route[O_WALKANIM_SIZE];	// 340	size = 600*20 bytes = 12000
				// mega size = 12340 bytes (+ 8 byte offset table + 20 byte header = 12368)
};

struct _collisionData {
	BsObject  *compact;
	int32	w[24];
	int32	h[24];
	WalkData route[24];
};

#endif //BSOBJECT_H


--- NEW FILE: objectman.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/objectman.cpp,v 1.1 2003/12/16 02:09:25 lavosspawn Exp $
 *
 */

#include "stdafx.h"
#include "objectman.h"
#include "scummsys.h"
#include "common/util.h"
#include "sworddefs.h"
#include "swordres.h"
#include "sword1.h"

ObjectMan::ObjectMan(ResMan *pResourceMan) {
	_resMan = pResourceMan;
	for (uint16 cnt = 0; cnt < TOTAL_SECTIONS; cnt++)
		_liveList[cnt] = 0;
	
	_liveList[128] = _liveList[129] = _liveList[130] = _liveList[131] = _liveList[133] =
		_liveList[134] = _liveList[145] = _liveList[146] = _liveList[TEXT_sect] = 1;
	
	for (uint16 cnt = 0; cnt < TOTAL_SECTIONS; cnt++) {
		if (_liveList[cnt])
			_cptData[cnt] = (uint8*)_resMan->cptResOpen(_objectList[cnt]) + sizeof(Header);
		else
			_cptData[cnt] = NULL;
	}

}

ObjectMan::~ObjectMan(void) {
	for (uint16 cnt = 0; cnt < TOTAL_SECTIONS; cnt++)
		if (_liveList[cnt])
			_resMan->resClose(_objectList[cnt]);
}

bool ObjectMan::sectionAlive(uint16 section) {
	return (_liveList[section] > 0);
}

void ObjectMan::megaEntering(uint16 section) {
	_liveList[section]++;
	if (_liveList[section] == 1)
		_cptData[section] = ((uint8*)_resMan->cptResOpen(_objectList[section])) + sizeof(Header);
}

void ObjectMan::megaLeaving(uint16 section, int id) {
	if (_liveList[section] == 0)
		error("mega %d is leaving empty section %d", id, section);
	_liveList[section]--;
	if ((_liveList[section] == 0) && (id != PLAYER)) {
		_resMan->resClose(_liveList[section]);
		_cptData[section] = NULL;
	}
	/* if the player is leaving the section then we have to close the resources after
	   mainloop ends, because the screen will still need the resources*/
}

uint8 ObjectMan::fnCheckForTextLine(uint32 textId) {
	uint8 retVal = 0;
	if (!_textList[textId / ITM_PER_SEC][0])
		return 0; // section does not exist

	uint8 lang = SwordEngine::_systemVars.language;
	uint32 *textData = (uint32*)((uint8*)_resMan->openFetchRes(_textList[textId / ITM_PER_SEC][lang]) + sizeof(Header));
	if ((textId & ITM_ID) < READ_LE_UINT32(textData)) {
		textData++;
		if (textData[textId & ITM_ID])
			retVal = 1;
	}
	_resMan->resClose(_textList[textId / ITM_PER_SEC][lang]);
	return retVal;
}

char *ObjectMan::lockText(uint32 textId) {
	uint8 lang = SwordEngine::_systemVars.language;
	char *addr = (char*)_resMan->openFetchRes(_textList[textId / ITM_PER_SEC][lang]) + sizeof(Header);
	if ((textId & ITM_ID) >= READ_LE_UINT32(addr)) {
		warning("ObjectMan::lockText(%d): only %d texts in file", textId & ITM_ID, READ_LE_UINT32(addr));
		textId = 0; // get first line instead
	}
	uint32 offset = READ_LE_UINT32(addr + ((textId & ITM_ID) + 1)* 4);
	if (offset == 0)
		warning("ObjectMan::lockText(%d): text number has no text lines", textId);
	return addr + offset;
}

void ObjectMan::unlockText(uint32 textId) {
	_resMan->resClose(_textList[textId / ITM_PER_SEC][SwordEngine::_systemVars.language]);
}

uint32 ObjectMan::lastTextNumber(int section) {
	uint8 *data = (uint8*)_resMan->openFetchRes(_textList[section][SwordEngine::_systemVars.language]) + sizeof(Header);
	uint32 result = READ_LE_UINT32(data) - 1;
	_resMan->resClose(_textList[section][SwordEngine::_systemVars.language]);
	return result;
}

BsObject *ObjectMan::fetchObject(uint32 id) {
	uint8 *addr = _cptData[id / ITM_PER_SEC];
	if (!addr)
		error("fetchObject: section %d is not open!", id / ITM_PER_SEC);
	id &= ITM_ID;
	// DON'T do endian conversion here. it's already done.
	return (BsObject*)(addr + *(uint32*)(addr + (id + 1)*4));
}

uint32 ObjectMan::fetchNoObjects(int section) {
	if (_cptData[section] == NULL)
		error("fetchNoObjects: section %d is not open!", section);
	return *(uint32*)_cptData[section];
}

void ObjectMan::closeSection(uint32 screen) {
	if (_liveList[screen] == 0)	 // close the section that PLAYER has just left, if it's empty now
		_resMan->resClose(_objectList[screen]);
}

--- NEW FILE: objectman.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/objectman.h,v 1.1 2003/12/16 02:09:25 lavosspawn Exp $
 *
 */

// this is the object manager. our equivalent to protocol.c and coredata.c

#ifndef OBJECTMAN_H
#define OBJECTMAN_H

#include "resman.h"
#include "sworddefs.h"
#include "object.h"

class ObjectMan {
public:
	ObjectMan(ResMan *pResourceMan);
	~ObjectMan(void);
	BsObject *fetchObject(uint32 id);
	//void unlockObject(uint32 id);
	uint32 fetchNoObjects(int section);
	bool sectionAlive(uint16 section);
	void megaEntering(uint16 section);
	void megaLeaving(uint16 section, int id);

	uint8 fnCheckForTextLine(uint32 textId);
	char *lockText(uint32 textId);
	void unlockText(uint32 textId);
	uint32 lastTextNumber(int section);

    void closeSection(uint32 screen);
private:
	ResMan *_resMan;
	static const uint32 _objectList[TOTAL_SECTIONS];	//a table of pointers to object files
	static const uint32 _textList[TOTAL_SECTIONS][7];	//a table of pointers to text files
	int	_liveList[TOTAL_SECTIONS]; 						//which sections are active
	uint8 *_cptData[TOTAL_SECTIONS];
};

#endif //OBJECTMAN_H


--- NEW FILE: resman.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/resman.cpp,v 1.1 2003/12/16 02:09:25 lavosspawn Exp $
 *
 */

#include "stdafx.h"
#include "scummsys.h"
#include <stdio.h>
#include <stdlib.h>
#include "memman.h"
#include "resman.h"
#include "sworddefs.h"
#include "base/engine.h"
#include "common/util.h"
#include "swordres.h"

#define MAX_PATH_LEN 260

ResMan::ResMan(const char *resFile, MemMan *pMemoMan) {
	_memMan = pMemoMan;
	loadCluDescript(resFile);
}

ResMan::~ResMan(void) {
	freeCluDescript();
}

void ResMan::loadCluDescript(const char *fileName) {
	File resFile;
	resFile.open(fileName);
	if (!resFile.isOpen())
		error("ResMan::loadCluDescript(): File %s not found!", fileName);
	
	_prj.noClu = resFile.readUint32LE();
	_prj.clu = new BsClu*[_prj.noClu];

	uint32 *cluIndex = (uint32*)malloc(_prj.noClu * 4);
	resFile.read(cluIndex, _prj.noClu * 4);

	for (uint32 clusCnt = 0; clusCnt < _prj.noClu; clusCnt++)
		if (cluIndex[clusCnt]) {
			BsClu *cluster = _prj.clu[clusCnt] = new BsClu;
			resFile.read(cluster->label, MAX_LABEL_SIZE);

			cluster->noGrp = resFile.readUint32LE();
			cluster->grp = new BsGrp*[cluster->noGrp];

			uint32 *grpIndex = (uint32*)malloc(cluster->noGrp * 4);
			resFile.read(grpIndex, cluster->noGrp * 4);

			for (uint32 grpCnt = 0; grpCnt < cluster->noGrp; grpCnt++)
				if (grpIndex[grpCnt]) {
					BsGrp *group = cluster->grp[grpCnt] = new BsGrp;
					group->noRes = resFile.readUint32LE();
					group->resHandle = new BsMemHandle[group->noRes];
					group->offset = new uint32[group->noRes];
					group->length = new uint32[group->noRes];
					uint32 *resIdIdx = (uint32*)malloc(group->noRes * 4);
					resFile.read(resIdIdx, group->noRes * 4);

					for (uint32 resCnt = 0; resCnt < group->noRes; resCnt++) {
						if (resIdIdx[resCnt]) {
							group->offset[resCnt] = resFile.readUint32LE();
							group->length[resCnt] = resFile.readUint32LE();
							_memMan->initHandle(group->resHandle + resCnt);
						} else {
							group->offset[resCnt] = 0xFFFFFFFF;
							group->length[resCnt] = 0;
							_memMan->initHandle(group->resHandle + resCnt);
						}
					}
                    free(resIdIdx);
				} else
					cluster->grp[grpCnt] = NULL;
			free(grpIndex);
		} else
			_prj.clu[clusCnt] = NULL;
	free(cluIndex);
}

void ResMan::freeCluDescript(void) {
	
	for (uint32 clusCnt = 0; clusCnt < _prj.noClu; clusCnt++)
		if (BsClu *cluster = _prj.clu[clusCnt]) {
			for (uint32 grpCnt = 0; grpCnt < cluster->noGrp; grpCnt++)
				if (BsGrp *group = cluster->grp[grpCnt]) {
					_memMan->freeNow(group->resHandle);
					delete[] group->resHandle;
					delete[] group->offset;
					delete[] group->length;
					delete group;
				}
			delete[] cluster->grp;
			delete cluster;
		}
	delete[] _prj.clu;
}

void *ResMan::fetchRes(uint32 id) {
	BsMemHandle *memHandle = resHandle(id);
	if (!memHandle->data)
		error("fetchRes:: resource %d is not open!", id);
	return memHandle->data;
}

void *ResMan::openFetchRes(uint32 id) {
	resOpen(id);
	return fetchRes(id);
}

void ResMan::dumpRes(uint32 id) {
	char outn[30];
	sprintf(outn, "DUMP%08X.BIN", id);
	FILE *outf = fopen( outn, "wb");
	resOpen(id);
	BsMemHandle *memHandle = resHandle(id);
	fwrite(memHandle->data, 1, memHandle->size, outf);
	fclose(outf);
	resClose(id);
}

Header *ResMan::lockScript(uint32 scrID) {
	if (!_scriptList[scrID / ITM_PER_SEC])
		error("Script id %d not found.\n", scrID);
	scrID = _scriptList[scrID / ITM_PER_SEC];
#ifdef SCUMM_BIG_ENDIAN
	BsMemHandle *memHandle = resHandle(scrID);
	if (memHandle->cond == MEM_FREED)
		openScriptResourceBigEndian(scrID);
	else
		resOpen(scrID);
#else
	resOpen(scrID);
#endif
	return (Header*)resHandle(scrID)->data;
}

void ResMan::unlockScript(uint32 scrID) {
	resClose(_scriptList[scrID / ITM_PER_SEC]);
}

void *ResMan::cptResOpen(uint32 id) {
#ifdef SCUMM_BIG_ENDIAN
	BsMemHandle *memHandle = resHandle(id);
	if (memHandle->cond == MEM_FREED)
		openCptResourceBigEndian(id);
	else
		resOpen(id);
#else
	resOpen(id);
#endif
	return resHandle(id)->data;
}

void ResMan::resOpen(uint32 id) {  // load resource ID into memory
	BsMemHandle *memHandle = resHandle(id);
	if (memHandle->cond == MEM_FREED) { // memory has been freed
		uint32 size = resLength(id);
		_memMan->alloc(memHandle, size);
		uint8 *dest = (uint8*)memHandle->data;
		File *clusFile = openClusterFile(id);
		clusFile->seek( resOffset(id) );
		clusFile->read( memHandle->data, size);
		if (clusFile->ioFailed())
			error("Can't read %d bytes from cluster %d\n", size, id);
		// original loop was a lot more complicated, more error handling and
		// some calls to the music system, don't think we'll need that.
		clusFile->close();
		delete clusFile;
	} else
		_memMan->setCondition(memHandle, MEM_DONT_FREE);
	memHandle->refCount++;
	if (memHandle->refCount > 20) {
		debug(1, "%d references to id %d. Guess there's something wrong.", memHandle->refCount, id);
	}
}

void ResMan::resClose(uint32 id) {
	BsMemHandle *handle = resHandle(id);
	if (!handle->refCount) {
		warning("Resource Manager fail: unlocking object with refCount 0. Id: %d\n", id);		
	} else
		handle->refCount--;
	if (!handle->refCount)
		_memMan->setCondition( handle, MEM_CAN_FREE);
}

FrameHeader *ResMan::fetchFrame(void *resourceData, uint32 frameNo) {
	uint8 *frameFile = (uint8*)resourceData;
    uint8 *idxData = frameFile + sizeof(Header);
	if (frameNo >= READ_LE_UINT32(idxData))
		error("fetchFrame:: frame %d doesn't exist in resource.", frameNo);
	frameFile += READ_LE_UINT32(idxData + (frameNo+1) * 4);
	return (FrameHeader*)frameFile;
}

File *ResMan::openClusterFile(uint32 id) {
	File *clusFile = new File();;
	char fullPath[MAX_PATH_LEN];
	char fileName[15];
	makePathToCluster(fullPath);
	sprintf(fileName, "%s.CLU", _prj.clu[(id >> 24)-1]->label);
	clusFile->open(fileName);
	if (!clusFile->isOpen())
		error("Can't open cluster file %s in directory: %s\n", fileName, fullPath);
	return clusFile;
}

BsMemHandle *ResMan::resHandle(uint32 id) {
	uint8 cluster = (uint8)((id >> 24) - 1);
	uint8 group = (uint8)(id >> 16);

	return &(_prj.clu[cluster]->grp[group]->resHandle[id & 0xFFFF]);
}

uint32 ResMan::resLength(uint32 id) {
	uint8 cluster = (uint8)((id >> 24) - 1);
	uint8 group = (uint8)(id >> 16);

	return _prj.clu[cluster]->grp[group]->length[id & 0xFFFF];
}

uint32 ResMan::resOffset(uint32 id) {
	uint8 cluster = (uint8)((id >> 24) - 1);
	uint8 group = (uint8)(id >> 16);

	return _prj.clu[cluster]->grp[group]->offset[id & 0xFFFF];
}

void ResMan::makePathToCluster(char *str) {
	*str = '\0';
	// todo: add search stuff, cd1, cd2, etc.
}

void ResMan::openCptResourceBigEndian(uint32 id) {
	resOpen(id);
	BsMemHandle *handle = resHandle(id);
	uint32 totSize = handle->size;
	uint8 *data = ((uint8*)handle->data) + sizeof(Header);
	totSize -= sizeof(Header);

	uint32 numCpts = *(uint32*)data = READ_LE_UINT32(data);
	data += 4;
	uint32 *dataIdx = (uint32*)data;

	for (uint32 cnt = 0; cnt < numCpts; cnt++) {
		uint32 cptSize;
		//uint32 cptPos = READ_LE_UINT32(data + cnt * 4);
		uint32 cptPos = dataIdx[cnt] = READ_LE_UINT32(dataIdx + cnt);
		if (cnt == numCpts-1)
			cptSize = totSize - cptPos - 4;
		else
			cptSize = READ_LE_UINT32(data + (cnt + 1) * 4) - cptPos;
		if (cptSize & 3)
			error("Odd compact size during endian conversion. Resource ID = %d, Cpt = %d of %d, Size %d\n", id, cnt, numCpts, cptSize);
		
		cptSize >>= 2;
		uint32 *cptData = (uint32*)(data + cptPos);
		for (uint32 elemCnt = 0; elemCnt < cptSize; elemCnt++)
			cptData[elemCnt] = READ_LE_UINT32(cptData + elemCnt);
	}
}

void ResMan::openScriptResourceBigEndian(uint32 id) {
	resOpen(id);
	BsMemHandle *handle = resHandle(id);
	uint32 totSize = handle->size;
	Header *head = (Header*)handle->data;
	head->comp_length = FROM_LE_32(head->comp_length);
	head->decomp_length = FROM_LE_32(head->decomp_length);
	head->version = FROM_LE_16(head->version);
	uint32 *data = (uint32*)((uint8*)handle->data + sizeof(Header));
	uint32 size = handle->size - sizeof(Header);
	if (size & 3)
		error("Odd size during script endian conversion. Resource ID =%d, size = %d", id, size);
	size >>= 2;
	for (uint32 cnt = 0; cnt < size; cnt++) {
		*data = READ_LE_UINT32(data);
		data++;
	}
}

--- NEW FILE: resman.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/resman.h,v 1.1 2003/12/16 02:09:25 lavosspawn Exp $
 *
 */

#ifndef RESMAN_H
#define RESMAN_H

#include "memman.h"
#include "file.h"
#include "sworddefs.h"

#define MAX_LABEL_SIZE (31+1)

struct BsGrp {
	uint32 noRes;
	BsMemHandle *resHandle;
	uint32 *offset;
	uint32 *length;
};

struct BsClu {
	char label[MAX_LABEL_SIZE];
	uint32 noGrp;
	BsGrp **grp;
};

struct BsPrj {
	uint32 noClu;
	BsClu **clu;
};

class ResMan {
public:
	ResMan(const char *resFile, MemMan *pMemoMan);
	~ResMan(void);
	void resClose(uint32 id);
	//void resOpen(uint32 id);
	void resOpen(uint32 id);
	void *fetchRes(uint32 id);
	void dumpRes(uint32 id);
	void *openFetchRes(uint32 id);
	void *cptResOpen(uint32 id);
	Header *lockScript(uint32 scrID);
	void unlockScript(uint32 scrID);
	FrameHeader *fetchFrame(void *resourceData, uint32 frameNo);
	uint32 resLength(uint32 id); // this should be private. it's used in SwordSound for endian conversion, though 
							     // make it private again when the mixer supports little endian data.
private:
	BsMemHandle *resHandle(uint32 id);
	uint32 resOffset(uint32 id);
	void openCptResourceBigEndian(uint32 id);
	void openScriptResourceBigEndian(uint32 id);

    File *openClusterFile(uint32 id);
	void makePathToCluster(char *str);
	void loadCluDescript(const char *fileName);
	void freeCluDescript(void);
	BsPrj _prj;
	MemMan *_memMan;
	static const uint32 _scriptList[TOTAL_SECTIONS];	//a table of resource tags
};

#endif //RESMAN_H

--- NEW FILE: router.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) Revolution Software Ltd.
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/router.cpp,v 1.1 2003/12/16 02:09:25 lavosspawn Exp $
 *
[...1929 lines suppressed...]
		else
			tar_dir = 6;
	} else if (slope == 2) { //vertical
		if (signY == 1)	// going down
			tar_dir = 4;
		else
			tar_dir = 0;
	} else if (signX == 1) { //right diagonal
		if (signY == 1)	// going down
			tar_dir = 3;
		else
			tar_dir = 1;
	} else { //left diagonal
		if (signY == 1)	// going down
			tar_dir = 5;
		else
			tar_dir = 7;
	}
	return tar_dir;
}

--- NEW FILE: router.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) Revolution Software Ltd.
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/router.h,v 1.1 2003/12/16 02:09:25 lavosspawn Exp $
 *
 */

#ifndef BSROUTER_H
#define BSROUTER_H

#include "scummsys.h"
#include "object.h"

#define EXTRA_GRID_SIZE 20
#define O_GRID_SIZE 200

#if !defined(__GNUC__)
	#pragma START_PACK_STRUCTS
#endif

struct BarData {
	int16   x1;
  	int16   y1;
  	int16   x2;
	int16   y2;
	int16   xmin;
	int16   ymin;
	int16   xmax;
	int16   ymax;
	int16   dx;	   // x2 - x1
	int16   dy;	   // y2 - y1
	int32   co;	   // co = (y1 *dx)- (x1*dy) from an equation for a line y*dx = x*dy + co
} GCC_PACK;

struct NodeData {
	int16   x;
	int16   y;
	int16	level;
	int16   prev;
	int16   dist;
} GCC_PACK;

#if !defined(__GNUC__)
	#pragma END_PACK_STRUCTS
#endif

struct FloorData {
	int32		nbars;
	BarData		*bars;
	int32		nnodes;
	NodeData	*node;
};

struct RouteData {
	int32	x;
	int32	y;
	int32	dirS;
	int32	dirD;
};

struct PathData {
	int32	x;
	int32	y;
	int32	dir;
	int32	num;
};

struct FrameInfos {
	int32 framesPerStep, framesPerChar;
	int32 standFrames;
	int32 slowInFrames, slowOutFrames;
	int32 turnFramesLeft, turnFramesRight;
	int32 walkFramesLeft, walkFramesRight;
	uint16 startX, startY, targetX, targetY, targetDir;
	int32 scaleA, scaleB;
};

#define ROUTE_END_FLAG 255
#define NO_DIRECTIONS 8
#define MAX_FRAMES_PER_CYCLE 16
#define MAX_FRAMES_PER_CHAR (MAX_FRAMES_PER_CYCLE * NO_DIRECTIONS)
#define O_ROUTE_SIZE 50

class ObjectMan;
class ResMan;

class SwordRouter {
public:
	SwordRouter(ObjectMan *pObjMan, ResMan *pResMan);
	~SwordRouter(void);
	int routeFinder(int32 id, BsObject *mega, int32 x, int32 y, int32 dir);
	int whatTarget(int32 startX, int32 startY, int32 destX, int32 destY);
	void setPlayerTarget(int32 x, int32 y, int32 dir, int32 stance);
	void resetExtraData(void);

	// these should be private but are read by SwordScreen for debugging:
	int32 _nBars, _nNodes;
	BarData _bars[O_GRID_SIZE + EXTRA_GRID_SIZE];
	NodeData _node[O_GRID_SIZE + EXTRA_GRID_SIZE];
private:
	// when the player collides with another mega, we'll receive a ReRouteRequest here.
	// that's why we need to remember the player's target coordinates
	int32 _playerTargetX, _playerTargetY, _playerTargetDir, _playerTargetStance;
	// additional route data to block parts of the floor and enable routine around megas:
	int32 _numExtraBars, _numExtraNodes;
	BarData _extraBars[EXTRA_GRID_SIZE];
	NodeData _extraNodes[EXTRA_GRID_SIZE];
	ObjectMan *_objMan;
	ResMan *_resMan;

	uint8 _nWalkFrames, _nTurnFrames;
	int32 _dx[NO_DIRECTIONS + MAX_FRAMES_PER_CHAR];
	int32 _dy[NO_DIRECTIONS + MAX_FRAMES_PER_CHAR];
	int32 _modX[NO_DIRECTIONS];
	int32 _modY[NO_DIRECTIONS];
	int32 _diagonalx, _diagonaly;

	RouteData _route[O_ROUTE_SIZE];
	//int32 _routeLength;
	PathData  _smoothPath[O_ROUTE_SIZE];
	PathData  _modularPath[O_ROUTE_SIZE];


	void loadWalkResources(int32 megaId, BsObject *mega, int32 x, int32 y, int32 targetDir);
	int getRoute(void);
	int checkTarget(int16 x, int16 y);
	
	int scan(int32 level);	
	int newCheck(int32 status, int16 x1, int16 x2, int16 y1, int16 y2);
	int check(int16 x1, int16 y1, int16 x2, int16 y2);
	int horizCheck(int16 x1, int16 y, int16 x2);
	int vertCheck(int16 x, int16 y1, int16 y2);
	int lineCheck(int16 x1, int16 y1, int16 x2, int16 y2);

	int32 extractRoute(int32 targetDir);

	void slidyPath(int32 scaleA, int32 scaleB, uint16 targetDir);
	void slidyWalkAnimator(WalkData *walkAnim, FrameInfos *frInfo, int32 megaId);
	
	int32 smoothestPath(uint16 startX, uint16 startY, uint16 startDir, int32 routeLength);
	int32 smoothCheck(int32 best, int32 p, int32 dirS, int32 dirD);

    int32 solidPath(int32 scaleA, int32 scaleB);
	int32 solidWalkAnimator(WalkData *walkAnim, FrameInfos *frInfo, int32 megaId);
};

#endif //BSROUTER_H

--- NEW FILE: screen.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/screen.cpp,v 1.1 2003/12/16 02:09:25 lavosspawn Exp $
 *
 */

#include "stdafx.h"
#include "screen.h"
#include "logic.h"
#include "sworddefs.h"
#include "text.h"
#include "resman.h"
#include "objectman.h"
#include "scummsys.h"
#include "common/util.h"
#include "system.h"
#include "router.h"

#define SCROLL_FRACTION 16
#define MAX_SCROLL_DISTANCE 8
#define FADE_UP 1
#define FADE_DOWN -1

SwordScreen::SwordScreen(OSystem *system, ResMan *pResMan, ObjectMan *pObjMan) {
	_system = system;
	_resMan = pResMan;
	_objMan = pObjMan;
	_screenBuf = _screenGrid = NULL;
	_backLength = _foreLength = _sortLength = 0;
	_fadingStep = 0;
}

void SwordScreen::useTextManager(SwordText *pTextMan) {
	_textMan = pTextMan;
}

int32 SwordScreen::inRange(int32 a, int32 b, int32 c) { // return b(!) so that: a <= b <= c
	return (a > b) ? (a) : ((b < c) ? b : c);
}

void SwordScreen::setScrolling(int16 offsetX, int16 offsetY) {
	if (!SwordLogic::_scriptVars[SCROLL_FLAG])
		return ; // screen is smaller than 640x400 => no need for scrolling

	int32 dx, dy;
	uint32 scrlDistX, scrlDistY;
	uint32 scrlToX, scrlToY;

	offsetX = inRange(0, offsetX, SwordLogic::_scriptVars[MAX_SCROLL_OFFSET_X]);
	offsetY = inRange(0, offsetY, SwordLogic::_scriptVars[MAX_SCROLL_OFFSET_Y]);
	_oldScrollX = SwordLogic::_scriptVars[SCROLL_OFFSET_X];
	_oldScrollY = SwordLogic::_scriptVars[SCROLL_OFFSET_Y];

	if (SwordLogic::_scriptVars[SCROLL_FLAG] == 2) { // first time on this screen - need absolute scroll immediately!
		scrlToX = (uint32)offsetX;
		scrlToY = (uint32)offsetY;
	} else {		// catch up with required scroll offsets - speed depending on distance to catch up (dx and dy) & 'SCROLL_FRACTION' used
					// but limit to certain number of pixels per cycle (MAX_SCROLL_DISTANCE)
		dx = SwordLogic::_scriptVars[SCROLL_OFFSET_X] - offsetX;
		dy = SwordLogic::_scriptVars[SCROLL_OFFSET_Y] - offsetY;
		int8 sig = (dx < 0) ? (-1) : 1;
		if (dx < 0)
			dx = -dx;
		scrlDistX = 1 + dx/SCROLL_FRACTION;
		scrlDistX = inRange(0, scrlDistX, MAX_SCROLL_DISTANCE);
		scrlToX = SwordLogic::_scriptVars[SCROLL_OFFSET_X] + sig * scrlDistX;

		sig = (dy < 0) ? (-1) : 1;
		if (dy < 0)
			dy = -dy;
		scrlDistY = 1 + dy/SCROLL_FRACTION;
		scrlDistY = inRange(0, scrlDistY, MAX_SCROLL_DISTANCE);
		scrlToY = SwordLogic::_scriptVars[SCROLL_OFFSET_Y] + sig * scrlDistY;
	}
	scrlToX = inRange(0, scrlToX, SwordLogic::_scriptVars[MAX_SCROLL_OFFSET_X]);
	scrlToY = inRange(0, scrlToY, SwordLogic::_scriptVars[MAX_SCROLL_OFFSET_Y]);
	if ((scrlToX != SwordLogic::_scriptVars[SCROLL_OFFSET_X]) || (scrlToY != SwordLogic::_scriptVars[SCROLL_OFFSET_Y])) {
		_fullRefresh = true;
		SwordLogic::_scriptVars[SCROLL_OFFSET_X] = scrlToX;
		SwordLogic::_scriptVars[SCROLL_OFFSET_Y] = scrlToY;
	} else
		_fullRefresh = false;
	if (SwordLogic::_scriptVars[SCROLL_FLAG] == 2) {
		_oldScrollX = scrlToX;
		_oldScrollY = scrlToY;
		SwordLogic::_scriptVars[SCROLL_FLAG] = 1;
	}
}

void SwordScreen::fadeDownPalette(void) {
	_fadingStep = 15;
	_fadingDirection = FADE_DOWN;
}

void SwordScreen::fadeUpPalette(void) {
	_fadingStep = 15;
	_fadingDirection = FADE_UP;
}

void SwordScreen::fnSetPalette(uint8 start, uint16 length, uint8 *data) {
	memcpy(_targetPalette + start * 3, data, length * 3);
	_system->set_palette(data, start, length);
}

void SwordScreen::fnSetFadeTargetPalette(uint8 start, uint16 length, uint8 *data) {
	memcpy(_targetPalette + start * 3, data, length * 3);
	debug(1, "fnSetFadeTargetPalette called");
}

bool SwordScreen::stillFading(void) {
	return (_fadingStep > 0);
}

void SwordScreen::updateScreen(void) {
	if (SwordLogic::_scriptVars[NEW_PALETTE]) {
		_fadingStep = 1;
		_fadingDirection = FADE_UP;
		memcpy(_targetPalette, _resMan->openFetchRes(_roomDefTable[_currentScreen].palettes[0]), 184 * 3); // set colours 0-183 for background palette
		_resMan->resClose(_roomDefTable[_currentScreen].palettes[0]);
		memcpy(_targetPalette + 184 * 3, _resMan->openFetchRes(_roomDefTable[_currentScreen].palettes[1]),  72 * 3); // set colours 184-255 for sprite palette - george, icons & menubar
		_resMan->resClose(_roomDefTable[_currentScreen].palettes[1]);
		SwordLogic::_scriptVars[NEW_PALETTE] = 0;
	}
	if (_fadingStep) {
		fadePalette();
		_system->set_palette(_currentPalette, 0, 256);
	}

	uint16 scrlX = (uint16)SwordLogic::_scriptVars[SCROLL_OFFSET_X];
	uint16 scrlY = (uint16)SwordLogic::_scriptVars[SCROLL_OFFSET_Y];
	_fullRefresh = true;
	if (_fullRefresh) {
		_fullRefresh = false;
		uint16 copyWidth = SCREEN_WIDTH;
		uint16 copyHeight = SCREEN_DEPTH;
		if (scrlX + copyWidth > _scrnSizeX)
			copyWidth = _scrnSizeX - scrlX;
		if (scrlY + copyHeight > _scrnSizeY)
			copyHeight = _scrnSizeY - scrlY;
		_system->copy_rect(_screenBuf + scrlY * _scrnSizeX + scrlX, _scrnSizeX, 0, 40, copyWidth, copyHeight);
	} else {
		// partial screen update only. The screen coordinates probably won't fit to the
		// grid holding the informations on which blocks have to be updated.
		// as the grid will be X pixel higher and Y pixel more to the left, this can be cured
		// by first checking the top border, then the left column and then the remaining (aligned) part.
		uint8 *gridPos = _screenGrid + (scrlX / SCRNGRID_X) + (scrlY / SCRNGRID_Y) * _gridSizeX;
		uint8 *scrnBuf = _screenBuf + scrlY * _scrnSizeX + scrlX;
		uint8 diffX = (uint8)(scrlX % SCRNGRID_X);
		uint8 diffY = (uint8)(scrlY % SCRNGRID_Y);
		uint16 gridW = SCREEN_WIDTH / SCRNGRID_X;
		uint16 gridH = SCREEN_DEPTH / SCRNGRID_Y;
		if (diffY) {
			uint8 cpHeight = SCRNGRID_Y - diffY;
			uint16 cpWidth = 0;
			for (uint16 cntx = 0; cntx < gridW; cntx++) 
				if (gridPos[cntx] & 1) {
					gridPos[cntx] &= ~1;
					cpWidth++;
				} else if (cpWidth) {
					int16 xPos = (cntx - cpWidth) * SCRNGRID_X - diffX;
					if (xPos < 0)
						xPos = 0;
					_system->copy_rect(scrnBuf + xPos, _scrnSizeX, xPos, 40, cpWidth * SCRNGRID_X, cpHeight);
					cpWidth = 0;
				}
			if (cpWidth) {
				int16 xPos = (gridW - cpWidth) * SCRNGRID_X - diffX;
				if (xPos < 0)
					xPos = 0;
				_system->copy_rect(scrnBuf + xPos, _scrnSizeX, xPos, 40, SCREEN_WIDTH - xPos, cpHeight);
			}
		} // okay, y scrolling is compensated. check x now.
		gridPos += _gridSizeX;
		scrnBuf = _screenBuf + scrlX + diffY * _scrnSizeX;
		if (diffX) {
			uint8 cpWidth = SCRNGRID_X - diffX;
			uint16 cpHeight = 0;
			for (uint16 cnty = 0; cnty < gridH; cnty++)
				if (gridPos[cnty * SCRNGRID_X] & 1) {
					gridPos[cnty * SCRNGRID_X] &= ~1;
					cpHeight++;
				} else if (cpHeight) {
					uint16 yPos = (cnty - cpHeight) * SCRNGRID_Y;
					_system->copy_rect(scrnBuf + yPos * _scrnSizeX, _scrnSizeX, 0, yPos + diffY + 40, cpWidth, cpHeight * SCRNGRID_Y);
				}
			if (cpHeight) {
				uint16 yPos = (gridH - cpHeight) * SCRNGRID_Y;
				_system->copy_rect(scrnBuf + yPos * _scrnSizeX, _scrnSizeX, 0, yPos + diffY + 40, cpWidth, SCREEN_DEPTH - (yPos + diffY));
			}			
		} // x scroll is compensated, too. check the rest of the screen, now.
		scrlX = (scrlX + SCRNGRID_X - 1) &~ (SCRNGRID_X - 1);
		scrlY = (scrlY + SCRNGRID_Y - 1) &~ (SCRNGRID_Y - 1);
		scrnBuf = _screenBuf + scrlY * _scrnSizeX + scrlX;
		gridPos++;
		for (uint16 cnty = 0; cnty < gridH; cnty++) {
			uint16 cpWidth = 0;
			uint16 cpHeight = SCRNGRID_Y;
			if (cnty == gridH - 1)
				cpHeight = SCRNGRID_Y - diffY;
			for (uint16 cntx = 0; cntx < gridW; cntx++)
				if (gridPos[cntx] & 1) {
					gridPos[cntx] &= ~1;
					cpWidth++;
				} else if (cpWidth) {
					_system->copy_rect(scrnBuf + (cntx - cpWidth) * SCRNGRID_X, _scrnSizeX, (cntx - cpWidth) * SCRNGRID_X + diffX, cnty * SCRNGRID_Y + diffY + 40, cpWidth * SCRNGRID_X, cpHeight);
				}
			if (cpWidth) {
				uint16 xPos = (gridW - cpWidth) * SCRNGRID_X;
				_system->copy_rect(scrnBuf + xPos, _scrnSizeX, xPos + diffX, cnty * SCRNGRID_Y + diffY + 40, SCREEN_WIDTH - (xPos + diffX), cpHeight);
			}
			gridPos += _gridSizeX;
			scrnBuf += _scrnSizeX * SCRNGRID_Y;
		}
	}
	_system->update_screen();
}

void SwordScreen::newScreen(uint32 screen) {
	// set sizes and scrolling, initialize/load screengrid, force screen refresh
	// force palette fadeup?
	_currentScreen = screen;
	_scrnSizeX = _roomDefTable[screen].sizeX;
	_scrnSizeY = _roomDefTable[screen].sizeY;
	_gridSizeX = _scrnSizeX / SCRNGRID_X;
	_gridSizeY = _scrnSizeY / SCRNGRID_Y;
	if ((_scrnSizeX % SCRNGRID_X) || (_scrnSizeY % SCRNGRID_Y))
		error("Illegal screensize: %d: %d/%d", screen, _scrnSizeX, _scrnSizeY);
	if ((_scrnSizeX > SCREEN_WIDTH) || (_scrnSizeY > SCREEN_DEPTH)) {
		SwordLogic::_scriptVars[SCROLL_FLAG] = 2;
		SwordLogic::_scriptVars[MAX_SCROLL_OFFSET_X] = _scrnSizeX - SCREEN_WIDTH;
		SwordLogic::_scriptVars[MAX_SCROLL_OFFSET_Y] = _scrnSizeY - SCREEN_DEPTH;
	} else {
		SwordLogic::_scriptVars[SCROLL_FLAG] = 0;
		SwordLogic::_scriptVars[MAX_SCROLL_OFFSET_X] = 0;
		SwordLogic::_scriptVars[MAX_SCROLL_OFFSET_Y] = 0;
		SwordLogic::_scriptVars[SCROLL_OFFSET_X] = 0;
		SwordLogic::_scriptVars[SCROLL_OFFSET_Y] = 0;
	}
	_screenBuf = (uint8*)malloc(_scrnSizeX * _scrnSizeY);
	_screenGrid = (uint8*)malloc(_gridSizeX * _gridSizeY);
	memset(_screenGrid, 0x80, _gridSizeX * _gridSizeY); // force refresh
	for (uint8 cnt = 0; cnt < _roomDefTable[_currentScreen].totalLayers; cnt++) {
		// open and lock all resources, will be closed in closeScreen()
		_layerBlocks[cnt] = (uint8*)_resMan->openFetchRes(_roomDefTable[_currentScreen].layers[cnt]);
	}
	for (uint8 cnt = 0; cnt < _roomDefTable[_currentScreen].totalLayers - 1; cnt++) {
		// there's no grid for the background layer, so it's totalLayers - 1
		_layerGrid[cnt] = (uint16*)_resMan->openFetchRes(_roomDefTable[_currentScreen].grids[cnt]);
		_layerGrid[cnt] += 0x12; // not sure about the 0x12
	}
	_parallax[0] = _parallax[1] = NULL;
	if (_roomDefTable[_currentScreen].parallax[0])
		_parallax[0] = (uint8*)_resMan->openFetchRes(_roomDefTable[_currentScreen].parallax[0]);
	if (_roomDefTable[_currentScreen].parallax[1])
		_parallax[1] = (uint8*)_resMan->openFetchRes(_roomDefTable[_currentScreen].parallax[1]);

	// TEMPORARY!
	uint8 *bgPal = (uint8*)_resMan->openFetchRes(_roomDefTable[_currentScreen].palettes[0]);
	uint8 *sprPal = (uint8*)_resMan->openFetchRes(_roomDefTable[_currentScreen].palettes[1]);
	for (uint16 cnt = 0; cnt < 256; cnt++) {
		_targetPalette[cnt * 4 + 0] = bgPal[cnt * 3 + 0] << 2;
		_targetPalette[cnt * 4 + 1] = bgPal[cnt * 3 + 1] << 2;
		_targetPalette[cnt * 4 + 2] = bgPal[cnt * 3 + 2] << 2;
	}
	/*for (uint16 cnt = 0; cnt < 72; cnt++) {
		_targetPalette[(cnt + 184) * 4 + 0] = bgPal[cnt * 3 + 0];
		_targetPalette[(cnt + 184) * 4 + 1] = bgPal[cnt * 3 + 1];
		_targetPalette[(cnt + 184) * 4 + 2] = bgPal[cnt * 3 + 2];
	}*/
	_targetPalette[0] = _targetPalette[1] = _targetPalette[2] = 0;
	_system->set_palette(_targetPalette, 0, 256);	
	_resMan->resClose(_roomDefTable[_currentScreen].palettes[0]);
	_resMan->resClose(_roomDefTable[_currentScreen].palettes[1]);
}

void SwordScreen::quitScreen(void) {
	for (uint8 cnt = 0; cnt < _roomDefTable[_currentScreen].totalLayers; cnt++)
		_resMan->resClose(_roomDefTable[_currentScreen].layers[cnt]);
	for (uint8 cnt = 0; cnt < _roomDefTable[_currentScreen].totalLayers - 1; cnt++)
		_resMan->resClose(_roomDefTable[_currentScreen].grids[cnt]);
	if (_roomDefTable[_currentScreen].parallax[0])
		_resMan->resClose(_roomDefTable[_currentScreen].parallax[0]);
	if (_roomDefTable[_currentScreen].parallax[1])
		_resMan->resClose(_roomDefTable[_currentScreen].parallax[1]);
}

void SwordScreen::recreate() {
	memcpy(_screenBuf, _layerBlocks[0], _scrnSizeX * _scrnSizeY);
}

void SwordScreen::spritesAndParallax(void) {
	if ((_currentScreen == 54) && _parallax[0])
		renderParallax(_parallax[0]); // rm54 has a BACKGROUND parallax layer in parallax[0]

	for (uint8 cnt = 0; cnt < _backLength; cnt++)
		processImage(_backList[cnt]);

	SortSpr temp;
	for (uint8 cnt = 0; cnt < _sortLength - 1; cnt++)
		for (uint8 sCnt = 0; sCnt < _sortLength - 1; sCnt++)
			if (_sortList[sCnt].y > _sortList[sCnt + 1].y) {
                temp = _sortList[sCnt];
				_sortList[sCnt] = _sortList[sCnt + 1];
				_sortList[sCnt + 1] = temp;
			}
	for (uint8 cnt = 0; cnt < _sortLength; cnt++)
		processImage(_sortList[cnt].id);

	if ((_currentScreen != 54) && _parallax[0])
		renderParallax(_parallax[0]); // screens other than 54 have FOREGROUND parallax layer in parallax[0]
	if (_parallax[1])
		renderParallax(_parallax[1]);

	for (uint8 cnt = 0; cnt < _foreLength; cnt++)
		processImage(_foreList[cnt]);

	_backLength = _sortLength = _foreLength = 0;
}

void SwordScreen::processImage(uint32 id) {
	BsObject *compact;
	FrameHeader *frameHead;
	int scale;

	compact = _objMan->fetchObject(id);
	if (compact->o_type == TYPE_TEXT)
		frameHead = _textMan->giveSpriteData((uint8)compact->o_target);
	else
		frameHead = _resMan->fetchFrame(_resMan->openFetchRes(compact->o_resource), compact->o_frame);
	
	uint8 *sprData = ((uint8*)frameHead) + sizeof(FrameHeader);

	uint16 spriteX = compact->o_anim_x;
	uint16 spriteY = compact->o_anim_y;
	if (compact->o_status & STAT_SHRINK) {
		scale = (compact->o_scale_a * compact->o_ycoord + compact->o_scale_b) / 256;
		spriteX += (FROM_LE_16(frameHead->offsetX) * scale) / 256;
		spriteY += (FROM_LE_16(frameHead->offsetY) * scale) / 256;
	} else {
		scale = 256;
		spriteX += FROM_LE_16(frameHead->offsetX);
		spriteY += FROM_LE_16(frameHead->offsetY);
	}
	if (scale > 512)
		debug(1, "compact %d is oversized: scale = %d", id, scale);

	uint8 *tonyBuf = NULL;
	if (frameHead->runTimeComp[3] == '7') { // RLE7 encoded?
		decompressRLE7(sprData, FROM_LE_32(frameHead->compSize), _rleBuffer);
		sprData = _rleBuffer;
	} else if (frameHead->runTimeComp[3] == '0') { // RLE0 encoded?
		decompressRLE0(sprData, FROM_LE_32(frameHead->compSize), _rleBuffer, FROM_LE_16(frameHead->width));
		sprData = _rleBuffer;
	} else if (frameHead->runTimeComp[1] == 'I') { // new type
		tonyBuf = (uint8*)malloc(FROM_LE_16(frameHead->width) * FROM_LE_16(frameHead->height));
		decompressTony(sprData, FROM_LE_32(frameHead->compSize), tonyBuf);
		sprData = tonyBuf;
	}

	uint16 sprSizeX, sprSizeY;
	if (compact->o_status & STAT_SHRINK) {
		sprSizeX = (scale * FROM_LE_16(frameHead->width)) / 256;
		sprSizeY = (scale * FROM_LE_16(frameHead->height)) / 256;
		fastShrink(sprData, FROM_LE_16(frameHead->width), FROM_LE_16(frameHead->height), scale, _shrinkBuffer);
		sprData = _shrinkBuffer;
	} else {
		sprSizeX = FROM_LE_16(frameHead->width);
		sprSizeY = FROM_LE_16(frameHead->height);
	}
	if (!(compact->o_status & STAT_OVERRIDE)) {
		//mouse size linked to exact size & coordinates of sprite box - shrink friendly
		if ((frameHead->offsetX) || (frameHead->offsetY)) {
			//for megas the mouse area is reduced to account for sprite not
			//filling the box size is reduced to 1/2 width, 4/5 height
			compact->o_mouse_x1 = spriteX + sprSizeX / 4;
			compact->o_mouse_x2 = spriteX + (3 * sprSizeX) / 4;
			compact->o_mouse_y1 = spriteY + sprSizeY / 10;
			compact->o_mouse_y2 = spriteY + (9 * sprSizeY) / 10;
		} else {
			compact->o_mouse_x1 = spriteX;
			compact->o_mouse_x2 = spriteX + sprSizeX;
			compact->o_mouse_y1 = spriteY;
			compact->o_mouse_y2 = spriteY + sprSizeY;
		}
	}
	uint16 sprPitch = sprSizeX;
	uint16 incr;
	spriteClipAndSet(&spriteX, &spriteY, &sprSizeX, &sprSizeY, &incr);
	if ((sprSizeX > 0) && (sprSizeY > 0)) {
		drawSprite(sprData + incr, spriteX, spriteY, sprSizeX, sprSizeY, sprPitch);
		if (!(compact->o_status&STAT_FORE))
			verticalMask(spriteX, spriteY, sprSizeX, sprSizeY);
	}
	if (compact->o_type != TYPE_TEXT)
		_resMan->resClose(compact->o_resource);
	if (tonyBuf)
		free(tonyBuf);
}

void SwordScreen::verticalMask(uint16 x, uint16 y, uint16 bWidth, uint16 bHeight) {
	if (_roomDefTable[_currentScreen].totalLayers <= 1)
		return;
	bWidth = (bWidth + (SCRNGRID_X - 1)) / SCRNGRID_X;
	bHeight = (bHeight + (SCRNGRID_Y - 1)) / SCRNGRID_Y;
	
	if (x & (SCRNGRID_X - 1))
		bWidth++;
	if (y & (SCRNGRID_Y - 1))
		bHeight++;

	x /= SCRNGRID_X;
	y /= SCRNGRID_Y;
	if (x + bWidth > _gridSizeX)
		bWidth = _gridSizeX - x;
	if (y + bHeight > _gridSizeY)
		bHeight = _gridSizeY - y;

	for (uint16 blkx = 0; blkx < bWidth; blkx++) {
		for (uint8 z = 1; z < _roomDefTable[_currentScreen].totalLayers; z++) { // current layer
			uint16 *grid = _layerGrid[z - 1] + x + blkx + y * _gridSizeX;
			for (uint16 blky = 0; blky < bHeight; blky++) {
				if (*grid) {
					uint8 *blkData = _layerBlocks[z] + (READ_LE_UINT16(grid) - 1) * 128;
			        blitBlockClear(x + blkx, y + blky, blkData);
				}
				grid += _gridSizeX;
			}
		}
	}
}

void SwordScreen::blitBlockClear(uint16 x, uint16 y, uint8 *data) {
	uint8 *dest = _screenBuf + (y * SCRNGRID_Y) * _scrnSizeX + (x * SCRNGRID_X);
	for (uint8 cnty = 0; cnty < SCRNGRID_Y; cnty++) {
		for (uint8 cntx = 0; cntx < SCRNGRID_X; cntx++)
			if (data[cntx])
				dest[cntx] = data[cntx];
		data += SCRNGRID_X;
		dest += _scrnSizeX;
	}
}

void SwordScreen::renderParallax(uint8 *data) {
	ParallaxHeader *header = (ParallaxHeader*)data;
	assert((FROM_LE_16(header->sizeX) >= SCREEN_WIDTH) && (FROM_LE_16(header->sizeY) >= SCREEN_DEPTH));
	double scrlfx =  FROM_LE_16(header->sizeX) / ((double)_scrnSizeX );
	double scrlfy = FROM_LE_16(header->sizeY) / ((double)_scrnSizeY );
	uint16 scrlX = (uint16)(SwordLogic::_scriptVars[SCROLL_OFFSET_X] * scrlfx);
	uint16 scrlY = (uint16)(SwordLogic::_scriptVars[SCROLL_OFFSET_Y] * scrlfy);

	for (uint16 cnty = 0; cnty < SCREEN_DEPTH; cnty++) {
		uint8 *src = data + READ_LE_UINT32(header->lineIndexes + cnty + scrlY);
		uint8 *dest = _screenBuf + SwordLogic::_scriptVars[SCROLL_OFFSET_X] + cnty * _scrnSizeX;
		uint16 remain = scrlX;
		uint16 xPos = 0;
		bool copyFirst = false;
		while (remain) { // skip past the first part of the parallax to get to the right scrolling position
			uint8 doSkip = *src++;
			if (doSkip <= remain)
				remain -= doSkip;
			else {
                xPos = doSkip - remain;
				dest += xPos;
				remain = 0;
			}
			if (remain) {
				uint8 doCopy = *src++;
				if (doCopy <= remain) {
					remain -= doCopy;
					src += doCopy;
				} else {
					uint16 remCopy = doCopy - remain;
					memcpy(dest, src + remain, remCopy);
					dest += remCopy;
					src += doCopy;
					xPos = remCopy;
					remain = 0;
				}
			} else
				copyFirst = true;
		}
		while (xPos < SCREEN_WIDTH) {
			if (!copyFirst) {
				if (uint8 skip = *src++) {
					dest += skip;
					xPos += skip;
				}
			} else
				copyFirst = false;
			if (xPos < SCREEN_WIDTH) {
				if (uint8 doCopy = *src++) {
					if (xPos + doCopy > SCREEN_WIDTH)
						doCopy = SCREEN_WIDTH - xPos;
					memcpy(dest, src, doCopy);
					dest += doCopy;
					xPos += doCopy;
					src += doCopy;
				}
			}
		}
	}
}

void SwordScreen::drawSprite(uint8 *sprData, uint16 sprX, uint16 sprY, uint16 sprWidth, uint16 sprHeight, uint16 sprPitch) {
	uint8 *dest = _screenBuf + (sprY * _scrnSizeX) + sprX;
	for (uint16 cnty = 0; cnty < sprHeight; cnty++) {
		for (uint16 cntx = 0; cntx < sprWidth; cntx++)
			if (sprData[cntx])
				dest[cntx] = sprData[cntx];
		sprData += sprPitch;
		dest += _scrnSizeX;
	}
}

// nearest neighbor filter:
void SwordScreen::fastShrink(uint8 *src, uint32 width, uint32 height, uint32 scale, uint8 *dest) {
	uint32 resHeight = (height * scale) >> 8;
	uint32 resWidth = (width * scale) >> 8;
	uint32 step = 0x10000 / scale;
	uint8 columnTab[160];
	uint32 res = step >> 1;
	for (uint16 cnt = 0; cnt < resWidth; cnt++) {
		columnTab[cnt] = (uint8)(res >> 8);
		res += step;
	}

	uint32 newRow = step >> 1;
	uint32 oldRow = 0;

    uint8 *destPos = dest;
	for (uint16 lnCnt = 0; lnCnt < resHeight; lnCnt++) {
		while (oldRow < (newRow >> 8)) {
			oldRow++;
			src += width;
		}
		for (uint16 colCnt = 0; colCnt < resWidth; colCnt++) {
			*destPos++ = src[columnTab[colCnt]];
		}
		newRow += step;
	}
	// scaled, now stipple shadows if there are any
	for (uint16 lnCnt = 0; lnCnt < resHeight; lnCnt++) {
		uint16 xCnt = lnCnt & 1;
		destPos = dest + lnCnt * resWidth + (lnCnt & 1);
		while (xCnt < resWidth) {
			if (*destPos == 200)
				*destPos = 0;
			destPos += 2;
			xCnt += 2;
		}
	}
}

void SwordScreen::addToGraphicList(uint8 listId, uint32 objId) {
	if (listId == 0) {
		_foreList[_foreLength++] = objId;
		if (_foreLength > MAX_FORE)
			error("foreList exceeded!");
	}
	if (listId == 1) {
		BsObject *cpt = _objMan->fetchObject(objId);
		_sortList[_sortLength].id = objId;
		_sortList[_sortLength].y = cpt->o_anim_y; // gives feet coords if boxed mega, otherwise top of sprite box
		if (!(cpt->o_status & STAT_SHRINK)) {     // not a boxed mega using shrinking
			Header *frameRaw = (Header*)_resMan->openFetchRes(cpt->o_resource);
			FrameHeader *frameHead = _resMan->fetchFrame(frameRaw, cpt->o_frame);
			_sortList[_sortLength].y += frameHead->height - 1; // now pointing to base of sprite
			_resMan->resClose(cpt->o_resource);
		}
		_sortLength++;
		if (_sortLength > MAX_SORT)
			error("sortList exceeded!");
	}
	if (listId == 2) {
		_backList[_backLength++] = objId;
		if (_backLength > MAX_BACK)
			error("backList exceeded!");
	}
}

void SwordScreen::decompressTony(uint8 *src, uint32 compSize, uint8 *dest) {
	uint8 *endOfData = src + compSize;
	while (src < endOfData) {
		uint8 numFlat = *src++;
		if (numFlat) {
			memset(dest, *src, numFlat);
			src++;
			dest += numFlat;
		}
		if (src < endOfData) {
			uint8 numNoFlat = *src++;
			memcpy(dest, src, numNoFlat);
			src += numNoFlat;
			dest += numNoFlat;
		}
	}
}

void SwordScreen::decompressRLE7(uint8 *src, uint32 compSize, uint8 *dest) {
	uint8 *compBufEnd = src + compSize;
	while (src < compBufEnd) {
		uint8 code = *src++;
		if ((code > 127) || (code == 0))
			*dest++ = code;
		else {
			code++;
			memset(dest, *src++, code);
			dest += code;
		}
	}
}

void SwordScreen::decompressRLE0(uint8 *src, uint32 compSize, uint8 *dest, uint16 width) {
	// these are saved vertically flipped. *SIIIIIIIGH*
	uint8 *srcBufEnd = src + compSize;
	uint16 destX = width-1;
	while (src < srcBufEnd) {
		uint8 color = *src++;
		if (color) {
			dest[destX] = color;
			if (destX == 0) {
				destX = width-1;
				dest += width;
			} else
				destX--;
		} else {
			uint8 skip = *src++;
			for (uint16 cnt = 0; cnt < skip; cnt++) {
				dest[destX] = 0;
				if (destX == 0) {
					destX = width-1;
					dest += width;
				} else
					destX--;
			}
		}
	}
}

void SwordScreen::fadePalette(void) {
	if (_fadingStep == 16)
		memcpy(_currentPalette, _targetPalette, 256 * 4);
	else
		for (uint16 cnt = 0; cnt < 256 * 4; cnt++)
			_currentPalette[cnt] = (_targetPalette[cnt] * _fadingStep) >> 4;

	_fadingStep += _fadingDirection;
	if (_fadingStep == 17)
		_fadingStep = 0;
}

void SwordScreen::fnSetParallax(uint32 screen, uint32 resId) {
	if ((screen == _currentScreen) && (resId != _roomDefTable[screen].parallax[0]))
		warning("fnSetParallax: setting parallax for current room!!");
	_roomDefTable[screen].parallax[0] = resId;
}

void SwordScreen::spriteClipAndSet(uint16 *pSprX, uint16 *pSprY, uint16 *pSprWidth, uint16 *pSprHeight, uint16 *incr) {
	int16 sprX = *pSprX - SCREEN_LEFT_EDGE;
	int16 sprY = *pSprY - SCREEN_TOP_EDGE;
	int16 sprW = *pSprWidth;
	int16 sprH = *pSprHeight;
	
	if (sprY < 0) {
		*incr = (uint16)((-sprY) * sprW);
		sprH += sprY;
		sprY = 0;
	} else
		*incr = 0;
	if (sprX < 0) {
		*incr -= sprX;
		sprW += sprX;
		sprX = 0;
	}
	
	if (sprY + sprH > _scrnSizeY)
		sprH = _scrnSizeY - sprY;
	if (sprX + sprW > _scrnSizeX)
		sprW = _scrnSizeX - sprX;
    
	if (sprH < 0)
		*pSprHeight = 0;
	else
		*pSprHeight = (uint16)sprH;
	if (sprW < 0)
		*pSprWidth = 0;
	else
		*pSprWidth = (uint16)sprW;
	*pSprX = (uint16)sprX;
	*pSprY = (uint16)sprY;
	
	uint16 gridH = (*pSprHeight + SCRNGRID_Y - 1) / SCRNGRID_Y;
	uint16 gridW = (*pSprWidth + SCRNGRID_X - 1) / SCRNGRID_X;
	uint16 gridX = sprX / SCRNGRID_X;
	uint16 gridY = sprY / SCRNGRID_Y;
	uint8 *gridBuf = _screenGrid + gridX + gridY * _gridSizeX;
	if (gridX + gridW > _gridSizeX)
		gridW = _gridSizeX - gridX;
	if (gridY + gridH > _gridSizeY)
		gridH = _gridSizeY - gridY;

	for (uint16 cnty = 0; cnty < gridH; cnty++) {
		for (uint16 cntx = 0; cntx < gridW; cntx++)
			gridBuf[cntx] |= 0x80;
		gridBuf += _gridSizeX;
	}
}

void SwordScreen::showFrame(uint16 x, uint16 y, uint32 resId, uint32 frameNo) {
	warning("stub: SwordScreen::showFrame(%d, %d, %d, %d)", x, y, resId, frameNo);
}

void SwordScreen::fnFlash(uint8 color) {
	warning("stub: SwordScreen::fnFlash(%d)", color);
}

// ------------------- router debugging code --------------------------------

void SwordScreen::vline(uint16 x, uint16 y1, uint16 y2) {
	for (uint16 cnty = y1; cnty <= y2; cnty++)
		_screenBuf[x + _scrnSizeX * cnty] = 0;
}

void SwordScreen::hline(uint16 x1, uint16 x2, uint16 y) {
    for (uint16 cntx = x1; cntx <= x2; cntx++)
		_screenBuf[y * _scrnSizeX + cntx] = 0;
}

void SwordScreen::bsubline_1(uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
	int x, y, ddx, ddy, e;
    ddx = abs(x2 - x1);
    ddy = abs(y2 - y1) << 1;
    e = ddx - ddy;
    ddx <<= 1;
    
    if (x1 > x2) {
		uint16 tmp;
		tmp = x1; x1 = x2; x2 = tmp;
		tmp = y1; y1 = y2; y2 = tmp;
    }
    
    for (x = x1, y = y1; x <= x2; x++) {
		_screenBuf[y * _scrnSizeX + x] = 0;
		if (e < 0) {
		    y++;
		    e += ddx - ddy;
		} else {
		    e -= ddy;
		}
    }
}

void SwordScreen::bsubline_2(uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
	int x, y, ddx, ddy, e;
    ddx = abs(x2 - x1) << 1;
    ddy = abs(y2 - y1);
    e = ddy - ddx;
    ddy <<= 1;
    
    if (y1 > y2) {
		uint16 tmp;
		tmp = x1; x1 = x2; x2 = tmp;
		tmp = y1; y1 = y2; y2 = tmp;
    }
    
    for (y = y1, x = x1; y <= y2; y++) {
		_screenBuf[y * _scrnSizeX + x] = 0;
		if (e < 0) {
			x++;
			e += ddy - ddx;
		} else {
			e -= ddx;
		}
    }
}

void SwordScreen::bsubline_3(uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
	int x, y, ddx, ddy, e;
    ddx = abs(x1 - x2) << 1;
    ddy = abs(y2 - y1);
    e = ddy - ddx;
    ddy <<= 1;
    
    if (y1 > y2) {
		uint16 tmp;
		tmp = x1; x1 = x2; x2 = tmp;
		tmp = y1; y1 = y2; y2 = tmp;
    }

    for (y = y1, x = x1; y <= y2; y++) {
		_screenBuf[y * _scrnSizeX + x] = 0;
		if (e < 0) {
			x--;
		    e += ddy - ddx;
		} else {
			e -= ddx;
		}
    }
}

void SwordScreen::bsubline_4(uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
	int x, y, ddx, ddy, e;
    ddy = abs(y2 - y1) << 1;
    ddx = abs(x1 - x2);
    e = ddx - ddy;
    ddx <<= 1;
    
    if (x1 > x2) {
		uint16 tmp;
		tmp = x1; x1 = x2; x2 = tmp;
		tmp = y1; y1 = y2; y2 = tmp;
    }
    
    for (x = x1, y = y1; x <= x2; x++) {
		_screenBuf[y * _scrnSizeX + x] = 0;
		if (e < 0) {
		    y--;
		    e += ddx - ddy;
		} else {
		    e -= ddy;
		}
    }
}

void SwordScreen::drawLine(uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
	if ((x1 == x2) && (y1 == y2)) {
		_screenBuf[x1 + y1 * _scrnSizeX] = 0;
	}
    if (x1 == x2) {
		vline(x1, min(y1, y2), max(y1, y2));
		return;
    }
    
    if (y1 == y2) {
		hline(min(x1, x2), max(x1, x2), y1);
		return;
    }

    float k = float(y2 - y1) / float(x2 - x1);
    
    if ((k >= 0) && (k <= 1)) {
		bsubline_1(x1, y1, x2, y2);
    } else if (k > 1) {
		bsubline_2(x1, y1, x2, y2);
    } else if ((k < 0) && (k >= -1)) {
		bsubline_4(x1, y1, x2, y2);
    } else {
		bsubline_3(x1, y1, x2, y2);
    }	

}

void SwordScreen::showBarsAndNodes(SwordRouter *router) {
	for (uint16 cnt = 0; cnt < router->_nBars; cnt++) {
		drawLine(router->_bars[cnt].x1 - 128, router->_bars[cnt].y1 - 128, router->_bars[cnt].x2 - 128, router->_bars[cnt].y2 - 128);
	}
	if (!router->_nNodes)
		return;
	for (uint16 cnt = 0; cnt <= router->_nNodes; cnt++) {
		uint16 y = router->_node[cnt].y - 128;
		uint16 x = router->_node[cnt].x - 128;
		vline(x, y - 2, y + 2);
		hline(x - 2, x + 2, y);
		if (router->_node[cnt].dist != 9999) {
			drawLine(x, y, router->_node[router->_node[cnt].prev].x - 128, router->_node[router->_node[cnt].prev].y - 128);
		}
	}
}


--- NEW FILE: screen.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/screen.h,v 1.1 2003/12/16 02:09:25 lavosspawn Exp $
 *
 */

// vertical_mask from layers.c belongs here, as well.

#ifndef BSSCREEN_H
#define BSSCREEN_H

#include "sworddefs.h"

#define MAX_FORE 20
#define MAX_BACK 20
#define MAX_SORT 20

struct SortSpr {
	int32 id, y;
};

struct RoomDef {
	int		totalLayers;
	int		sizeX;
	int		sizeY;
	int		gridWidth;	//number of 16*16 grid blocks across - including off screen edges.
	uint32	layers[4];
	uint32	grids[3];
	uint32	palettes[2];
	uint32	parallax[2];
};

#define SCRNGRID_X 16
#define SCRNGRID_Y 8
#define SHRINK_BUFFER_SIZE 50000
#define RLE_BUFFER_SIZE 50000

#define FLASH_RED 0
#define FLASH_BLUE 1
#define BORDER_YELLOW 2
#define BORDER_GREEN 3
#define BORDER_PURPLE 4
#define BORDER_BLACK 5

class ResMan;
class ObjectMan;
class SwordText; // Text objects use sprites that are created internally at run-time
				 // the buffer belongs to SwordText, so we need a reference here.
class SwordRouter;
class OSystem;

class SwordScreen {
public:
	SwordScreen(OSystem *system, ResMan *pResMan, ObjectMan *pObjMan);
	void useTextManager(SwordText *pTextMan);
	~SwordScreen(void);
	void flushSprites(void) { _backLength = _sortLength = _foreLength = 0; };

	void quitScreen(void);
	void newScreen(uint32 screen);

	void setScrolling(int16 offsetX, int16 offsetY);

	void addToGraphicList(uint8 listId, uint32 objId);

	void recreate();
	void spritesAndParallax(void); //=> background_parallax, backsprites, sortsprites
								   //   foreground_parallax, foresprites
	void fadeDownPalette(void);
	void fadeUpPalette(void);
	void fnSetPalette(uint8 start, uint16 length, uint8 *data);
	void fnSetFadeTargetPalette(uint8 start, uint16 length, uint8 *data);
	bool stillFading(void);

	void updateScreen(void);
	void showFrame(uint16 x, uint16 y, uint32 resId, uint32 frameNo);

	void fnSetParallax(uint32 screen, uint32 resId);
	void fnFlash(uint8 color);
	void fnBorder(uint8 color);

	void showBarsAndNodes(SwordRouter *router);

private:
	// for router debugging
	void drawLine(uint16 x1, uint16 y1, uint16 x2, uint16 y2);
	void vline(uint16 x, uint16 y1, uint16 y2);
	void hline(uint16 x1, uint16 x2, uint16 y);
	void bsubline_1(uint16 x1, uint16 y1, uint16 x2, uint16 y2);
	void bsubline_2(uint16 x1, uint16 y1, uint16 x2, uint16 y2);
	void bsubline_3(uint16 x1, uint16 y1, uint16 x2, uint16 y2);
	void bsubline_4(uint16 x1, uint16 y1, uint16 x2, uint16 y2);

	void verticalMask(uint16 x, uint16 y, uint16 bWidth, uint16 bHeight);
	void blitBlockClear(uint16 x, uint16 y, uint8 *data);
	void renderParallax(uint8 *data);
	void processImage(uint32 id);
	void spriteClipAndSet(uint16 *pSprX, uint16 *pSprY, uint16 *sprWidth, uint16 *sprHeight, uint16 *incr);
	void drawSprite(uint8 *sprData, uint16 sprX, uint16 sprY, uint16 sprWidth, uint16 sprHeight, uint16 sprPitch);
	void decompressRLE7(uint8 *src, uint32 compSize, uint8 *dest);
	void decompressRLE0(uint8 *src, uint32 compSize, uint8 *dest, uint16 width);
	void decompressTony(uint8 *src, uint32 compSize, uint8 *dest);
	void fastShrink(uint8 *src, uint32 width, uint32 height, uint32 scale, uint8 *dest);
	int32 inRange(int32 a, int32 b, int32 c);
	void fadePalette(void);

	OSystem *_system;
	ResMan *_resMan;
	ObjectMan *_objMan;
	SwordText *_textMan;

    uint16 _currentScreen;
	uint8  *_screenBuf;
	uint8  *_screenGrid;
	uint16 *_layerGrid[4];
	uint8  *_layerBlocks[4];
	uint8  *_parallax[2];
	uint8  _rleBuffer[RLE_BUFFER_SIZE];
	uint8  _shrinkBuffer[SHRINK_BUFFER_SIZE];
	bool   _fullRefresh;
	uint16 _oldScrollX, _oldScrollY; // for drawing additional frames

	uint32  _foreList[MAX_FORE];
	uint32  _backList[MAX_BACK];
	SortSpr _sortList[MAX_SORT];
	uint8   _foreLength, _backLength, _sortLength;
	uint16  _scrnSizeX, _scrnSizeY, _gridSizeX, _gridSizeY;
	
	static RoomDef _roomDefTable[TOTAL_ROOMS]; // from ROOMS.C (not const, see fnSetParallax)

	uint8 _targetPalette[256 * 4];
	uint8 _currentPalette[256 * 4]; // for fading
	uint8 _fadingStep;
	int8  _fadingDirection; // 1 for fade up, -1 for fade down
};

#endif //BSSCREEN_H


--- NEW FILE: sound.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/sound.cpp,v 1.1 2003/12/16 02:09:25 lavosspawn Exp $
 *
 */

#include "stdafx.h"
#include "sound.h"
#include "common/util.h"
#include "resman.h"
#include "logic.h"

#define SOUND_SPEECH_ID 1
#define SPEECH_FLAGS (SoundMixer::FLAG_16BITS | SoundMixer::FLAG_AUTOFREE | SoundMixer::FLAG_LITTLE_ENDIAN)

SwordSound::SwordSound(const char *searchPath, SoundMixer *mixer, ResMan *pResMan) {
	strcpy(_filePath, searchPath);
	_mixer = mixer;
	_resMan = pResMan;
	_cowHeader = NULL;
	initCowSystem();
	_endOfQueue = 0;
}

int SwordSound::addToQueue(int32 fxNo) {
	bool alreadyInQueue = false;
	for (uint8 cnt = 0; (cnt < _endOfQueue) && (!alreadyInQueue); cnt++)
		if (_fxQueue[cnt].id == fxNo)
			alreadyInQueue = true;
	if (!alreadyInQueue) {
		if (_endOfQueue == MAX_FXQ_LENGTH)
			error("Sound queue overflow");
		_resMan->resOpen(_fxList[fxNo].sampleId);
		_fxQueue[_endOfQueue].id = fxNo;
		if (_fxList[fxNo].type == FX_SPOT)
			_fxQueue[_endOfQueue].delay = _fxList[fxNo].delay + 1;
		else
			_fxQueue[_endOfQueue].delay = 1;
		_endOfQueue++;
		return 1;
	}
	return 0;
}

void SwordSound::engine(void) {
	// first of all, add any random sfx to the queue...
	for (uint16 cnt = 0; cnt < TOTAL_FX_PER_ROOM; cnt++) {
		uint16 fxNo;
		if (fxNo = _roomsFixedFx[SwordLogic::_scriptVars[SCREEN]][cnt]) {
			if (_fxList[fxNo].type == FX_RANDOM) {
				if (_rnd.getRandomNumber(_fxList[fxNo].delay) == 0)
					addToQueue(fxNo);
			}
		} else
			break;
	}
	// now process the queue
	for (uint8 cnt = 0; cnt < _endOfQueue; cnt++) {
		if (_fxQueue[cnt].delay > 0) {
			_fxQueue[cnt].delay--;
			if (_fxQueue[cnt].delay == 0)
				playSample(_fxQueue[cnt]);
		} else {
			if (!_fxQueue[cnt].handle) { // sound finished
				_resMan->resClose(_fxQueue[cnt].id);
				if (cnt != _endOfQueue-1)
					_fxQueue[cnt] = _fxQueue[_endOfQueue - 1];
				_endOfQueue--;
			}
		}
	}
}

bool SwordSound::amISpeaking(void) {
	return true;
}

void SwordSound::clearAllFx(void) {
	warning("Stub: SwordSound::clearAllFx()");
}

void SwordSound::closeCowSysten(void) {
	warning("stub: SwordSound::closeCowSystem()");
}

void SwordSound::fnStopFx(int32 fxNo) {
	warning("stub: SwordSound::fnStopFx(%d)", fxNo);
}

bool SwordSound::speechFinished(void) {
	//warning("stub: SwordSound::speechFinished()");
	//return true;
    return (_speechHandle == 0);
}

void SwordSound::startFxForScreen(uint16 screen) { // do we need this?
	warning("stub: SwordSound::startFxForScreen(%d)", screen);
}

void SwordSound::playSample(QueueElement elem) {

	uint8 *sampleData = (uint8*)_resMan->fetchRes(_fxList[elem.id].sampleId);
	for (uint16 cnt = 0; cnt < MAX_ROOMS_PER_FX; cnt++) {
		if (_fxList[elem.id].roomVolList[cnt].roomNo) {
			if ((_fxList[elem.id].roomVolList[cnt].roomNo == SwordLogic::_scriptVars[SCREEN]) ||
				(_fxList[elem.id].roomVolList[cnt].roomNo == -1)) {

					uint8 volL = _fxList[elem.id].roomVolList[cnt].leftVol * 10;
					uint8 volR = _fxList[elem.id].roomVolList[cnt].rightVol * 10;
					int8 pan = (volR - volL) / 2;
					uint8 volume = (volR + volL) / 2;
					uint32 size = READ_LE_UINT32(sampleData + 0x28);
					uint8 flags;
					if (READ_LE_UINT16(sampleData + 0x22) == 16)
						flags = SoundMixer::FLAG_16BITS | SoundMixer::FLAG_LITTLE_ENDIAN;
					else
						flags = SoundMixer::FLAG_UNSIGNED;
					_mixer->playRaw(&elem.handle, sampleData + 0x2C, size, 11025, flags, elem.id, volume, pan);
			}
		} else
			break;
	}
}

uint32 SwordSound::uncompressedSize(uint8 *data) {
	return READ_LE_UINT32(data + 0x28);
}

bool SwordSound::startSpeech(uint16 roomNo, uint16 localNo) {
	if (_cowHeader == NULL) {
		warning("SwordSound::startSpeech: COW file isn't open!");
		return false;
	}

	uint32 locIndex = _cowHeader[roomNo] >> 2;
	uint32 sampleSize = _cowHeader[locIndex + (localNo * 2)];
	uint32 index = _cowHeader[locIndex + (localNo * 2) - 1];
	debug(4, "startSpeech(%d, %d): locIndex %d, sampleSize %d, index %d", roomNo, localNo, locIndex, sampleSize, index);
	if (sampleSize) {
		_cowFile.seek(index + _cowHeaderSize);
		uint8 *buf = (uint8*)malloc(sampleSize);
		_cowFile.read(buf, sampleSize);
		uint8 *smpBuf = (uint8*)malloc(uncompressedSize(buf));
        uint32 size = expandSpeech(buf, smpBuf, sampleSize);
		free(buf);
		if (!size) {
			free(smpBuf);
			return false;
		}
		_mixer->playRaw(&_speechHandle, smpBuf, size, 11025, SPEECH_FLAGS, SOUND_SPEECH_ID);
		return true;
	} else
		return false;
}

uint32 SwordSound::expandSpeech(void *src, void *dest, uint32 srcSize) {
	int16 *compData = (int16*)src;
	if (READ_BE_UINT32(compData + 0x12) != 'data') {
		warning("SwordSound::expandSpeech: 'data' tag not found in wave header");
		return 0;
	}
	srcSize >>= 1;
	int16 *expData = (int16*)dest;
	compData += 0x16;
	srcSize -= 0x16;

	uint32 srcPos = 0;
	while (srcPos < srcSize) {
		if (compData[srcPos] < 0) {
			uint16 len = (uint16)(-compData[srcPos]);
			for (uint32 cnt = 0; cnt < len; cnt++)
				*expData++ = compData[srcPos + 1];
			srcPos += 2;
		} else {
			uint32 len = (uint32)compData[srcPos];
			memcpy(expData, compData + srcPos + 1, len * 2);
			expData += len;
			srcPos += len + 1;
		}
	}
	return (uint8*)expData - (uint8*)dest;
}

void SwordSound::stopSpeech(void) {
	_mixer->stopID(SOUND_SPEECH_ID);
}

void SwordSound::initCowSystem(void) {
	_cowFile.open("SPEECH.CLU");
	if (_cowFile.isOpen()) {
		_cowHeaderSize = _cowFile.readUint32LE();
		_cowHeader = (uint32*)malloc(_cowHeaderSize);
		if (_cowHeaderSize & 3)
			error("Unexpected cow header size %d", _cowHeaderSize);
		for (uint32 cnt = 0; cnt < (_cowHeaderSize / 4) - 1; cnt++)
			_cowHeader[cnt] = _cowFile.readUint32LE();
	} else
		warning("SwordSound::initCowSystem: Can't open SPEECH.CLU");	
}

--- NEW FILE: sound.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/sound.h,v 1.1 2003/12/16 02:09:25 lavosspawn Exp $
 *
 */

#ifndef BSSOUND_H
#define BSSOUND_H

#include "object.h"
#include "sworddefs.h"
#include "common/file.h"
#include "sound/mixer.h"
#include "common/util.h"

#define	TOTAL_FX_PER_ROOM	7		// total loop & random fx per room (see fx_list.c)
#define	MAX_ROOMS_PER_FX	7		// max no. of rooms in the fx's room,vol list
#define	MAX_FXQ_LENGTH		32		// max length of sound queue - ie. max number of fx that can be stored up/playing together

#define FX_SPOT 1
#define FX_LOOP 2
#define FX_RANDOM 3

struct QueueElement {
	uint32 id, delay;
	PlayingSoundHandle handle;
	uint16 *data; // FIXME: This is a hack, because our mixer only supports Big endian data (currently)
};

struct RoomVol {
	int32 roomNo, leftVol, rightVol;
};

struct FxDef {
	uint32 sampleId, type, delay;
	RoomVol roomVolList[MAX_ROOMS_PER_FX];
};

class SoundMixer;
class ResMan;

class SwordSound {
public:
	SwordSound(const char *searchPath, SoundMixer *mixer, ResMan *pResMan);
	~SwordSound(void);
	void startFxForScreen(uint16 screen);

	bool startSpeech(uint16 roomNo, uint16 localNo); // this should work more or less.
													 // Maybe we'll need a delay of 3 gameCycles.
	bool speechFinished(void);
	void stopSpeech();
	bool amISpeaking(void); // this is supposed to return if the sounddata is near the ending or very silent...

	void fnStopFx(int32 fxNo);
	void clearAllFx(void);
	int addToQueue(int32 fxNo);
	//void removeFromQueue(int32 fxNo);
	// ^= part of fnPlayFx

	void engine(void);

private:
	void playSample(QueueElement elem);
	void initCowSystem(void);
	void closeCowSysten(void);
	uint32 uncompressedSize(uint8 *data);
	uint32 expandSpeech(void *src, void *dest, uint32 srcSize);
	File		 _cowFile;
	uint32		 *_cowHeader;
	uint32		 _cowHeaderSize;
	PlayingSoundHandle _speechHandle, _fxHandle;
	Common::RandomSource _rnd;
	
	QueueElement _fxQueue[MAX_FXQ_LENGTH];
	uint8		 _endOfQueue;
	SoundMixer *_mixer;
	ResMan *_resMan;
	char _filePath[100];
	static const char _musicList[270];
	static const uint16 _roomsFixedFx[TOTAL_ROOMS][TOTAL_FX_PER_ROOM];
	static const FxDef _fxList[312];
};

#endif //BSSOUND_H

--- NEW FILE: staticres.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/staticres.cpp,v 1.1 2003/12/16 02:09:25 lavosspawn Exp $
 *
[...5983 lines suppressed...]
	{0},											// 81
	{0},											// 82
	{0},											// 83
	{0},											// 84
	{0},											// 85
	{0},											// 86
	{0},											// 87
	{0},											// 88
	{0},											// 89
	{0},											// 90
	{0},											// 91
	{0},											// 92
	{0},											// 93
	{0},											// 94
	{0},											// 95
	{0},											// 96
	{0},											// 97
	{0},											// 98
	{0},											// 99
};

--- NEW FILE: sword1.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/sword1.cpp,v 1.1 2003/12/16 02:09:25 lavosspawn Exp $
 *
 */

#include "stdafx.h"
#include "sword1.h"

#include "backends/fs/fs.h"

#include "base/plugins.h"
#include "common/config-manager.h"
#include "common/file.h"
#include "common/timer.h"

#include "memman.h"
#include "resman.h"
#include "objectman.h"
#include "mouse.h"
#include "logic.h"
#include "sound.h"
#include "screen.h"
#include "swordres.h"
#include "menu.h"
#include "music.h"

// taken from Sword2.cpp
struct Sword1GameSettings {
	const char *name;
	const char *description;
	uint32 features;
	const char *detectname;
	GameSettings toGameSettings() const {
		GameSettings dummy = { name, description, features };
		return dummy;
	}
};

static const Sword1GameSettings sword1_settings[] = {
	/* Broken Sword 1 */
	{"sword1", "Broken Sword I", GF_DEFAULT_TO_1X_SCALER, "swordres.rif" },
	{NULL, NULL, 0, NULL}
};

GameList Engine_SWORD1_gameList() {
	const Sword1GameSettings *g = sword1_settings;
	GameList games;
	while (g->name) {
		games.push_back(g->toGameSettings());
		g++;
	}
	return games;
}

GameList Engine_SWORD1_detectGames(const FSList &fslist) {
	GameList detectedGames;
	const Sword1GameSettings *g;

	for (g = sword1_settings; g->name; ++g) {
		// Iterate over all files in the given directory
		for (FSList::ConstIterator file = fslist.begin(); file != fslist.end(); ++file) {
			const char *gameName = file->displayName().c_str();

			if (0 == scumm_stricmp(g->detectname, gameName)) {
				// Match found, add to list of candidates, then abort inner loop.
				detectedGames.push_back(g->toGameSettings());
				break;
			}
		}
	}
	return detectedGames;
}

Engine *Engine_SWORD1_create(GameDetector *detector, OSystem *syst) {
	return new SwordEngine(detector, syst);
}

REGISTER_PLUGIN("Broken Sword", Engine_SWORD1_gameList, Engine_SWORD1_create, Engine_SWORD1_detectGames)

SystemVars SwordEngine::_systemVars;

void SwordEngine::errorString(const char *buf1, char *buf2) {
	strcpy(buf2, buf1);
}

extern uint16 _debugLevel;

SwordEngine::SwordEngine(GameDetector *detector, OSystem *syst)
	: Engine(syst) {

	_detector = detector;
	_system = syst;
	_debugLevel = ConfMan.getInt("debuglevel");
	
	if (!_mixer->bindToSystem(syst))
		warning("Sound initialization failed");
}

SwordEngine::~SwordEngine() {
}

void SwordEngine::initialize(void) {
	_system->init_size(640, 480);
	debug(5, "Starting memory manager");
	_memMan = new MemMan();
	debug(5, "Starting resource manager");
	_resMan = new ResMan("swordres.rif", _memMan);
	debug(5, "Starting object manager");
	_objectMan = new ObjectMan(_resMan);
	_mixer->setVolume(255);
	_mouse = new SwordMouse(_system, _resMan, _objectMan);
	_screen = new SwordScreen(_system, _resMan, _objectMan);
	_music = new SwordMusic(_system, _mixer);
	_sound = new SwordSound("", _mixer, _resMan);
	_menu = new SwordMenu(_screen, _mouse);
	_logic = new SwordLogic(_objectMan, _resMan, _screen, _mouse, _sound, _music, _menu);
	_mouse->useLogic(_logic);

	_systemVars.justRestoredGame = _systemVars.currentCD = 
		_systemVars.gamePaused = _systemVars.saveGameFlag = 
		_systemVars.deathScreenFlag = _systemVars.currentMusic = 0;
	_systemVars.snrStatus = 0;
	_systemVars.rate = 8;
	_systemVars.language = 2;
	_systemVars.playSpeech = 1;
	//- start.c:
	// todo: move these to somewhere else
	SwordLogic::_scriptVars[GEORGE_CDT_FLAG] = GEO_TLK_TABLE;
	SwordLogic::_scriptVars[CHANGE_X] = 481;
	SwordLogic::_scriptVars[CHANGE_Y] = 413;
	SwordLogic::_scriptVars[CHANGE_DIR] = DOWN;
	SwordLogic::_scriptVars[CHANGE_PLACE] = FLOOR_1;
	
	SwordLogic::_scriptVars[NEW_SCREEN] = 1;
	_objectMan->fetchObject(PLAYER)->o_screen = 1;
	_objectMan->megaEntering(1);

	SwordLogic::_scriptVars[CHANGE_STANCE] = STAND;
	_mouseState = 0;
}

void SwordEngine::go(void) {
	
	initialize();
	// check if we have savegames. if we do, show control panel, else start intro.
	do {
        mainLoop();
		// mainLoop was left, show control panel
	} while (true);
}

void SwordEngine::mainLoop(void) {
	uint32 newTime, frameTime;
	do {
		// do we need the section45-hack from sword.c here?
		// todo: ensure right cd is inserted
		_screen->newScreen(SwordLogic::_scriptVars[NEW_SCREEN]);
		_logic->newScreen(SwordLogic::_scriptVars[NEW_SCREEN]);
		SwordLogic::_scriptVars[SCREEN] = SwordLogic::_scriptVars[NEW_SCREEN];
		//		 let swordSound start room sfx
		do {
			_music->stream();
			frameTime = _system->get_msecs();
			_systemVars.saveGameFlag = 0;
			debug(5, "\n\nNext logic cycle");
			_logic->engine();
			_logic->updateScreenParams(); // sets scrolling

			_screen->recreate();
			_screen->spritesAndParallax();
			_mouse->animate();

			newTime = _system->get_msecs();
			/*if ((newTime - frameTime < 50) && (!SwordLogic::_scriptVars[NEW_PALETTE])) {
				RenderScreenGDK();
				BlitMenusGDK();
				BlitMousePm();
				if (newTime - frameTime < 40)
					_system->delay_msecs(40 - (newTime - frameTime));
				FlipScreens();
			}*/

			_sound->engine();
			_screen->showBarsAndNodes(_logic->giveRouter());
			_screen->updateScreen();
		//-
			_menu->refresh(MENU_TOP);
			_menu->refresh(MENU_BOT);

			newTime = _system->get_msecs();
			if (newTime - frameTime < 80)
				delay(80 - (newTime - frameTime));
			else
				delay(0);

			/*FlipScreens(); this is done in SwordScreen::updateScreen() now.
			if (SwordLogic::_scriptVars[NEW_PALETTE]) {
				SwordLogic::_scriptVars[NEW_PALETTE] = 0;
				startFadePaletteUp();
			}*/

			_mouse->engine( _mouseX, _mouseY, _mouseState);
			_mouseState = 0;
			// do something smart here to implement pausing the game. If we even want that, that is.
		} while ((SwordLogic::_scriptVars[SCREEN] == SwordLogic::_scriptVars[NEW_SCREEN]) &&
			(_systemVars.saveGameFlag < 2));	// change screen

		if (SwordLogic::_scriptVars[SCREEN] != 53)	// don't fade down after syria pan
			_screen->fadeDownPalette();
		while (_screen->stillFading()) {
			_screen->updateScreen();
			delay(1000/12);
			// todo: fade sfx?
		}

		_screen->quitScreen(); // close graphic resources
		_objectMan->closeSection(SwordLogic::_scriptVars[SCREEN]); // close the section that PLAYER has just left, if it's empty now
        // todo: stop sfx, clear sfx queue, free sfx memory
	} while (_systemVars.saveGameFlag < 2);
}

void SwordEngine::delay(uint amount) { //copied and mutilated from sky.cpp

	OSystem::Event event;

	uint32 start = _system->get_msecs();
	uint32 cur = start;
	uint16 _key_pressed = 0;	//reset

	do {
		while (_system->poll_event(&event)) {
			switch (event.event_code) {
			case OSystem::EVENT_KEYDOWN:

				// Make sure backspace works right (this fixes a small issue on OS X)
				if (event.kbd.keycode == 8)
					_key_pressed = 8;
				else
					_key_pressed = (byte)event.kbd.ascii;
				break;
			case OSystem::EVENT_MOUSEMOVE:
				_mouseX = event.mouse.x;
				_mouseY = event.mouse.y;
				break;
			case OSystem::EVENT_LBUTTONDOWN:
				_mouseState |= BS1L_BUTTON_DOWN;
#ifdef _WIN32_WCE
				_mouseX = event.mouse.x;
				_mouseY = event.mouse.y;
#endif
				break;
			case OSystem::EVENT_RBUTTONDOWN:
				_mouseState |= BS1R_BUTTON_DOWN;
				break;
			case OSystem::EVENT_QUIT:
				_system->quit();
				break;
			default:
				break;
			}
		}

		if (amount == 0)
			break;

		{
			uint this_delay = 20; // 1?
#ifdef _WIN32_WCE
			this_delay = 10;
#endif
			if (this_delay > amount)
				this_delay = amount;
			_system->delay_msecs(this_delay);
		}
		cur = _system->get_msecs();
	} while (cur < start + amount);
}

--- NEW FILE: sword1.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/sword1.h,v 1.1 2003/12/16 02:09:25 lavosspawn Exp $
 *
 */

#include <stdio.h>
#include "base/engine.h"
#include "common/util.h"
#include "sound/mixer.h"
#include "base/gameDetector.h"

class SwordScreen;
class SwordSound;
class SwordLogic;
class SwordMouse;
class ResMan;
class MemMan;
class ObjectMan;
class SwordMenu;
class SwordMusic;

struct SystemVars {
	// todo: move these to a better place
	uint32	currentCD;			// starts at zero, then either 1 or 2 depending on section being played
	uint32	justRestoredGame;	// see main() in sword.c & New_screen() in gtm_core.c
	uint32	gamePaused;			// 1 when paused
	uint32	rate;				// game rate  => what's this for?
	//uint32	textNumber;		// holds last text_no displayed => I think it was only for debugging
	//uint32	endOfQ;				// next available slot in sound fx queue
	//uint8	debug;				// toggles tdebug file

	uint8	saveGameFlag;		// controls save game loop							0=off 1=save game 2=restore game 3=restart 4=quit to dos
	uint8	deathScreenFlag;	// 1 death screen version of the control panel, 2 = successful end of game
	uint8	playSpeech;
	uint8   showText;
	uint8   snrStatus;
			// ^=> move into SwordControl... or whatever it will be.
	//uint8	displayText;		// toggles debug text display						on "t"
	//uint8	displayGrid;		// toggles debug grid display						on "g"
	//uint8	displayMouse;		// toggles debug mouse display 					on "m"
	//uint8	framesPerSecond;	// toggles one frame pre second mode		on "1"
	//uint8	writingPCXs;		// writing a PCX every frame						on "f"
	//int16	parallaxOn;			I think we don't need this.
    uint8	language;
	int32	currentMusic;
	//uint32	gameCycle;
};

class SwordEngine : public Engine {
	void errorString(const char *buf_input, char *buf_output);
public:
	SwordEngine(GameDetector *detector, OSystem *syst);
	virtual ~SwordEngine();
	static SystemVars _systemVars;
protected:
	void go();
private:
	void delay(uint amount);
	void initialize(void);
	void mainLoop(void);
	void fnCheckCd(uint32 newScreen);

	uint16 _mouseX, _mouseY, _mouseState;

	GameDetector *_detector;
	OSystem		*_system;

	MemMan		*_memMan;
	ResMan		*_resMan;
	ObjectMan	*_objectMan;
	SwordScreen	*_screen;
	SwordMouse	*_mouse;
	SwordLogic	*_logic;
	SwordSound	*_sound;
	SwordMenu	*_menu;
	SwordMusic  *_music;
};
--- NEW FILE: sworddefs.h ---
#ifndef SWORDDEFS_H
#define SWORDDEFS_H

#include "scummsys.h"

#define LOOPED 1

#define	FRAME_RATE			12						// number of frames per second (max rate)
#define	SCREEN_WIDTH		640
#define	SCREEN_DEPTH		400
#define	SCREEN_LEFT_EDGE	128
#define	SCREEN_RIGHT_EDGE	(128+SCREEN_WIDTH-1)
#define	SCREEN_TOP_EDGE		128
#define	SCREEN_BOTTOM_EDGE	(128+SCREEN_DEPTH-1)
#define TYPE_FLOOR 1
#define TYPE_MOUSE 2
#define TYPE_SPRITE 3
#define TYPE_NON_MEGA 4
#define TYPE_MEGA 5
[...1352 lines suppressed...]
#define SCR_exit0 (0*0x10000 + 7)
#define SCR_exit1 (0*0x10000 + 8)
#define SCR_exit2 (0*0x10000 + 9)
#define SCR_exit3 (0*0x10000 + 10)
#define SCR_exit4 (0*0x10000 + 11)
#define SCR_exit5 (0*0x10000 + 12)
#define SCR_exit6 (0*0x10000 + 13)
#define SCR_exit7 (0*0x10000 + 14)
#define SCR_exit8 (0*0x10000 + 15)
#define SCR_exit9 (0*0x10000 + 16)
#define LEFT_SCROLL_POINTER 8388610
#define RIGHT_SCROLL_POINTER 8388611
#define FLOOR_63 4128768
#define ROOF_63 4128779
#define GUARD_ROOF_63 4128781
#define LEFT_TREE_POINTER_71 4653058
#define RIGHT_TREE_POINTER_71 4653059


#endif //SWORDDEFS_H
--- NEW FILE: swordres.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/swordres.h,v 1.1 2003/12/16 02:09:25 lavosspawn Exp $
 *
[...5177 lines suppressed...]
#define R79PAL 					 0x0E090001
#define EKSTD79 				 0x0E090002
#define EKSTD79CDT 				 0x0E090003
#define FIGHT79 				 0x0E090004
#define FIGHT79CDT 				 0x0E090005
#define GEOANG79 				 0x0E090006
#define GEOANG79CDT 			 0x0E090007
#define GEOTLK79 				 0x0E090008
#define GEOTLK79CDT 			 0x0E090009
#define NICSTD79 				 0x0E09000A
#define NICSTD79CDT 			 0x0E09000B
#define ROSENT79 				 0x0E09000C
#define ROSENT79CDT 			 0x0E09000D
#define ROSSHOT 				 0x0E09000E
#define ROSSHOTCDT 				 0x0E09000F
#define ROSTLK79 				 0x0E090010
#define ROSTLK79CDT 			 0x0E090011
	// 18 entities in TXTs, 18 in datafiles.

#endif //SWORDRES_H

--- NEW FILE: text.cpp ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/text.cpp,v 1.1 2003/12/16 02:09:25 lavosspawn Exp $
 *
 */

#include "stdafx.h"
#include "text.h"
#include "resman.h"
#include "objectman.h"
#include "common/util.h"
#include "swordres.h"
#include "sworddefs.h"

#define OVERLAP 3
#define SPACE ' '
#define BORDER_COL		200
#define LETTER_COL		193
#define NO_COL			0		// sprite background - 0 for transparency
#define MAX_LINES		30


SwordText::SwordText(ObjectMan *pObjMan, ResMan *pResMan, bool czechVersion) {
	_objMan = pObjMan;
	_resMan = pResMan;
	_textCount = 0;
	if (czechVersion)
		_font = (uint8*)_resMan->openFetchRes(CZECH_GAME_FONT);
	else
		_font = (uint8*)_resMan->openFetchRes(GAME_FONT);
	_joinWidth = charWidth( SPACE ) - 2 * OVERLAP;
	_charHeight = _resMan->fetchFrame(_font, 0)->height; // all chars have the same height
	_textBlocks[0] = _textBlocks[1] = 0;
}

uint32 SwordText::lowTextManager(uint8 *ascii, int32 width, uint8 pen) {
	// get rid of that textId thing!
	_textCount++;
	if (_textCount > MAX_TEXT_OBS)
		error("SwordText::lowTextManager: MAX_TEXT_OBS exceeded!");
	uint32 textObjId = (TEXT_sect * ITM_PER_SEC) - 1;
	do {
		textObjId++;
	} while(_objMan->fetchObject(textObjId)->o_status);
	// okay, found a free text object

	_objMan->fetchObject(textObjId)->o_status = STAT_FORE;
	makeTextSprite((uint8)textObjId, ascii, (uint16)width, pen);

	return textObjId;
}

void SwordText::makeTextSprite(uint8 slot, uint8 *text, uint16 maxWidth, uint8 pen) {
	LineInfo lines[MAX_LINES];
	uint16 numLines = analyzeSentence(text, maxWidth, lines);
	
	uint16 sprWidth = 0;
	for (uint16 lineCnt = 0; lineCnt < numLines; lineCnt++)
		if (lines[lineCnt].width > sprWidth)
			sprWidth = lines[lineCnt].width;
	uint16 sprHeight = _charHeight * numLines;
	uint32 sprSize = sprWidth * sprHeight;
	assert(!_textBlocks[slot]); // if this triggers, the speechDriver failed to call SwordText::releaseText.
	_textBlocks[slot] = (FrameHeader*)malloc(sprSize + sizeof(FrameHeader));

	memcpy( _textBlocks[slot]->runTimeComp, "Nu  ", 4);
	_textBlocks[slot]->compSize	= 0;
	_textBlocks[slot]->width	= sprWidth;
	_textBlocks[slot]->height	= sprHeight;
	_textBlocks[slot]->offsetX	= 0;
	_textBlocks[slot]->offsetY	= 0;

	uint8 *linePtr = ((uint8*)_textBlocks[slot]) + sizeof(FrameHeader);
	memset(linePtr, NO_COL, sprSize);
	for (uint16 lineCnt = 0; lineCnt < numLines; lineCnt++) {
		uint8 *sprPtr = linePtr + (sprWidth - lines[lineCnt].width) / 2; // center the text
		for (uint16 pos = 0; pos < lines[lineCnt].length; pos++)
			sprPtr += copyChar(*text++, sprPtr, sprWidth, pen) - OVERLAP;
		text++; // skip space at the end of the line
		linePtr += _charHeight * sprWidth;
	}
}

uint16 SwordText::charWidth(uint8 ch) {
	if (ch < SPACE)
		ch = 64;
	return _resMan->fetchFrame(_font, ch - SPACE)->width;
}

uint16 SwordText::analyzeSentence(uint8 *text, uint16 maxWidth, LineInfo *line) {
	uint16 lineNo = 0;

	bool firstWord = true;
	while (*text) {
		uint16 wordWidth = 0;
		uint16 wordLength = 0;

		while ((*text != SPACE) && *text) {
			wordWidth += charWidth(*text) - OVERLAP;
			wordLength++;
			text++;
		}
		if (*text == SPACE)
			text++;

		wordWidth += OVERLAP; // no overlap on final letter of word!
		if( firstWord )	{ // first word on first line, so no separating SPACE needed
			line[0].width = wordWidth;
			line[0].length = wordLength;
			firstWord = false;
		} else {
			// see how much extra space this word will need to fit on current line
			// (with a separating space character - also overlapped)
			uint16 spaceNeeded = _joinWidth + wordWidth;

			if (line[lineNo].width + spaceNeeded <= maxWidth ) {
				line[lineNo].width += spaceNeeded;
				line[lineNo].length += 1 + wordLength; // NB. space+word characters
			} else {	// put word (without separating SPACE) at start of next line
				lineNo++;
				assert( lineNo < MAX_LINES );
				line[lineNo].width = wordWidth;
				line[lineNo].length = wordLength;
			}
		}
	}
	return lineNo+1;	// return no of lines
}

uint16 SwordText::copyChar(uint8 ch, uint8 *sprPtr, uint16 sprWidth, uint8 pen) {
	FrameHeader *chFrame = _resMan->fetchFrame(_font, ch - SPACE);
	uint8 *chData = ((uint8*)chFrame) + sizeof(FrameHeader);
	uint8 *dest = sprPtr;
	for (uint16 cnty = 0; cnty < chFrame->height; cnty++) {
		for (uint16 cntx = 0; cntx < chFrame->width; cntx++) {
			if (*chData == LETTER_COL)
				dest[cntx] = pen;
			else if ((*chData == BORDER_COL) && (!dest[cntx])) // don't do a border if there's already a color underneath (chars can overlap)
				dest[cntx] = BORDER_COL;
			chData++;
		}
		dest += sprWidth;
	}
	return chFrame->width;
}

FrameHeader *SwordText::giveSpriteData(uint32 textTarget) {
	// textTarget is the resource ID of the Compact linking the textdata.
	// that's 0x950000 for slot 0 and 0x950001 for slot 1. easy, huh? :)
	textTarget &= ITM_ID;
	assert(textTarget <= 1);

	return _textBlocks[textTarget];
}

void SwordText::releaseText(uint32 id) {
	id &= ITM_ID;
	assert(id <= 1);
	free(_textBlocks[id]);
	_textBlocks[id] = NULL;
	_textCount--;
}

--- NEW FILE: text.h ---
/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003 The ScummVM project
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/sword1/text.h,v 1.1 2003/12/16 02:09:25 lavosspawn Exp $
 *
 */

#ifndef BSTEXT_H
#define BSTEXT_H

#define MAX_TEXT_OBS 2

#include "object.h"
#include "sworddefs.h"
class ObjectMan;
class ResMan;

struct LineInfo {
	uint16	width;	// width of line in pixels
	uint16	length;	// length of line in characters
};

class SwordText {
public:
	SwordText(ObjectMan *pObjMan, ResMan *pResMan, bool czechVersion);
	~SwordText(void);
	FrameHeader *giveSpriteData(uint32 textTarget);
	uint32 lowTextManager(uint8 *text, int32 width, uint8 pen);
	void releaseText(uint32 id);

private:
	void makeTextSprite(uint8 slot, uint8 *text, uint16 maxWidth, uint8 pen);
	uint16 analyzeSentence(uint8 *text, uint16 maxWidth, LineInfo *info);
	uint16 charWidth(uint8 ch);
	uint16 copyChar(uint8 ch, uint8 *sprPtr, uint16 sprWidth, uint8 pen);
	uint8 *_font;
	uint8 _textCount;
	uint16 _charHeight, _joinWidth;
	ObjectMan *_objMan;
	ResMan *_resMan;
	FrameHeader *_textBlocks[MAX_TEXT_OBS];
};

#endif //BSTEXT_H





More information about the Scummvm-git-logs mailing list