/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "mohawk/cursors.h"
#include "mohawk/myst.h"
#include "mohawk/myst_areas.h"
#include "mohawk/myst_card.h"
#include "mohawk/myst_graphics.h"
#include "mohawk/myst_state.h"
#include "mohawk/myst_sound.h"
#include "mohawk/video.h"
#include "mohawk/myst_stacks/stoneship.h"

#include "common/events.h"
#include "common/system.h"
#include "common/textconsole.h"

namespace Mohawk {
namespace MystStacks {

Stoneship::Stoneship(MohawkEngine_Myst *vm) :
		MystScriptParser(vm, kStoneshipStack),
		_state(vm->_gameState->_stoneship) {
	setupOpcodes();

	_tunnelRunning = false;
	_tunnelNextTime = 0;
	_tunnelAlarmSound = 0;
	_tunnelImagesCount = 0;

	_state.lightState = 0;
	_state.generatorDepletionTime = 0;
	_state.generatorDuration = 0;
	_cabinMystBookPresent = 0;
	_siriusDrawerDrugsOpen = 0;
	_chestDrawersOpen = 0;
	_chestAchenarBottomDrawerClosed = 1;

	_brotherDoorOpen = 0;

	// Drop key
	if (_state.trapdoorKeyState == 1)
		_state.trapdoorKeyState = 2;

	// Power is not available when loading
	if (_state.sideDoorOpened)
		_state.generatorPowerAvailable = 2;
	else
		_state.generatorPowerAvailable = 0;

	_batteryCharging = false;
	_batteryDepleting = false;
	_batteryNextTime = 0;
	_batteryLastCharge = 0;
	_batteryGaugeRunning = false;
	_batteryGauge = nullptr;

	_hologramTurnedOn = 0;
	_hologramDisplay = nullptr;
	_hologramSelection = nullptr;
	_hologramDisplayPos = 0;

	_telescopeRunning = false;
	_telescopePosition = 0;
	_telescopePanorama = 0;
	_telescopeOldMouse = 0;
	_telescopeLighthouseOff = 0;
	_telescopeLighthouseOn = 0;
	_telescopeLighthouseState = false;
	_telescopeNexTime = 0;

	_cloudOrbMovie = nullptr;
	_cloudOrbSound = 0;
	_cloudOrbStopSound = 0;
}

Stoneship::~Stoneship() {
}

void Stoneship::setupOpcodes() {
	// "Stack-Specific" Opcodes
	REGISTER_OPCODE(100, Stoneship, o_pumpTurnOff);
	REGISTER_OPCODE(101, Stoneship, o_brotherDoorOpen);
	REGISTER_OPCODE(102, Stoneship, o_cabinBookMovie);
	REGISTER_OPCODE(103, Stoneship, o_drawerOpenSirius);
	REGISTER_OPCODE(104, Stoneship, o_drawerClose);
	REGISTER_OPCODE(105, Stoneship, o_telescopeStart);
	REGISTER_OPCODE(106, Stoneship, o_telescopeMove);
	REGISTER_OPCODE(107, Stoneship, o_telescopeStop);
	REGISTER_OPCODE(108, Stoneship, o_generatorStart);
	REGISTER_OPCODE(109, Stoneship, NOP);
	REGISTER_OPCODE(110, Stoneship, o_generatorStop);
	REGISTER_OPCODE(111, Stoneship, o_drawerOpenAchenar);
	REGISTER_OPCODE(112, Stoneship, o_hologramPlayback);
	REGISTER_OPCODE(113, Stoneship, o_hologramSelectionStart);
	REGISTER_OPCODE(114, Stoneship, o_hologramSelectionMove);
	REGISTER_OPCODE(115, Stoneship, o_hologramSelectionStop);
	REGISTER_OPCODE(116, Stoneship, o_compassButton);
	REGISTER_OPCODE(117, Stoneship, o_chestValveVideos);
	REGISTER_OPCODE(118, Stoneship, o_chestDropKey);
	REGISTER_OPCODE(119, Stoneship, o_trapLockOpen);
	REGISTER_OPCODE(120, Stoneship, o_sideDoorsMovies);
	REGISTER_OPCODE(121, Stoneship, o_cloudOrbEnter);
	REGISTER_OPCODE(122, Stoneship, o_cloudOrbLeave);
	REGISTER_OPCODE(125, Stoneship, o_drawerCloseOpened);

	// "Init" Opcodes
	REGISTER_OPCODE(200, Stoneship, o_hologramDisplay_init);
	REGISTER_OPCODE(201, Stoneship, o_hologramSelection_init);
	REGISTER_OPCODE(202, Stoneship, o_battery_init);
	REGISTER_OPCODE(203, Stoneship, o_tunnelEnter_init);
	REGISTER_OPCODE(204, Stoneship, o_batteryGauge_init);
	REGISTER_OPCODE(205, Stoneship, o_tunnel_init);
	REGISTER_OPCODE(206, Stoneship, o_tunnelLeave_init);
	REGISTER_OPCODE(207, Stoneship, o_chest_init);
	REGISTER_OPCODE(208, Stoneship, o_telescope_init);
	REGISTER_OPCODE(209, Stoneship, o_achenarDrawers_init);
	REGISTER_OPCODE(210, Stoneship, o_cloudOrb_init);

	// "Exit" Opcodes
	REGISTER_OPCODE(300, Stoneship, NOP);
}

void Stoneship::disablePersistentScripts() {
	_batteryCharging = false;
	_batteryDepleting = false;
	_batteryGaugeRunning = false;
	_telescopeRunning = false;
}

void Stoneship::runPersistentScripts() {
	if (_batteryCharging)
		chargeBattery_run();

	if (_telescopeRunning)
		telescope_run();

	if (_batteryGaugeRunning)
		batteryGauge_run();

	if (_batteryDepleting)
		batteryDeplete_run();

	if (_tunnelRunning)
		tunnel_run();
}

uint16 Stoneship::getVar(uint16 var) {
	switch(var) {
	case 0: // Water Drained From Lighthouse / Right Button Of Pump
		return _state.pumpState == 4;
	case 1: // Water Drained From Tunnels To Brothers' Rooms / Middle Button Of Pump
		return _state.pumpState == 2;
	case 2: // Water Drained From Ship Cabin Tunnel / Left Button Of Pump
		return _state.pumpState == 1;
	case 3: // Lighthouse Chest Floating
		return _state.pumpState != 4 && !_state.chestValveState && !_state.chestWaterState;
	case 4: // Lighthouse State - Close Up
		if (_state.pumpState == 4) {
			return 1; // Drained
		} else {
			if (_state.chestValveState || _state.chestWaterState)
				return 0; // Flooded
			else
				return 2; // Flooded, Chest Floating
		}
	case 5: // Lighthouse Trapdoor State
		return _state.trapdoorState;
	case 6: // Chest valve state
		return _state.chestValveState;
	case 7: // Lighthouse Chest Unlocked
		return _state.chestOpenState;
	case 8: // Lighthouse Chest Key Position
		return _state.trapdoorKeyState;
	case 11: // Lighthouse Key State
		if (_state.chestOpenState) {
			if (_state.trapdoorKeyState == 1)
				return 1;
			else if (_state.trapdoorKeyState == 2)
				return 2;
			else
				return 3;
		} else {
			return 0;
		}
	case 12: // Trapdoor can be unlocked
		return _state.trapdoorKeyState == 1 && _state.trapdoorState == 2;
	case 13: // State Of Tunnels To Brothers' Rooms - Close Up
		if (_state.generatorPowerAvailable != 1) {
			if (_state.pumpState != 2)
				return 0; // Dark, Flooded
			else
				return 1; // Dark, Drained
		} else {
			if (_state.pumpState != 2)
				return 2; // Lit, Flooded
			else
				return 3; // Lit, Drained
		}
	case 14: // State Of Tunnels lights To Brothers' Rooms - Far
		return _state.generatorPowerAvailable;
	case 15: // Side Door in Tunnels To Brother's Rooms Open
		if (_state.generatorPowerAvailable == 1)
			return _state.sideDoorOpened;
		else
			return 0;
	case 16: // Ship Chamber Light State
		return _state.lightState;
	case 17: // Sirrus' Room Drawer with Drugs Open
		return _siriusDrawerDrugsOpen;
	case 18: // Brother Room Door Open
		return _brotherDoorOpen;
	case 19: // Brother Room Door State
		if (_brotherDoorOpen) {
			if (_state.lightState)
				return 2; // Open, Light On
			else
				return 1; // Open, Light Off
		} else {
			return 0; // Closed
		}
	case 20: // Ship Chamber Table/Book State
		return _cabinMystBookPresent;
	case 21: // Brothers Rooms' Chest Of Drawers Drawer State
		return _chestDrawersOpen;
	case 28: // Telescope Angle Position
		return 0;
	case 29: // Achenar's Room Rose/Skull Hologram Button Lit
		return _hologramTurnedOn;
	case 30: // Light State in Tunnel to Compass Rose Room
		if (_state.generatorPowerAvailable == 1) {
			if (_state.lightState)
				return 0;
			else
				return 1;
		} else {
			return 2;
		}
	case 31: // Lighthouse Lamp Room Battery Pack Indicator Light
		return batteryRemainingCharge() >= 10;
	case 32: // Lighthouse Lamp Room Battery Pack Meter Level
		return 0;
	case 33: // State of Side Door in Tunnels to Compass Rose Room
		if (_state.sideDoorOpened)
			return 2;
		else
			return _state.generatorPowerAvailable == 1;
	case 34: // Achenar's Room Drawer with Torn Note Closed
		return _chestAchenarBottomDrawerClosed;
	case 35: // Sirrus' Room Drawer #4 (Bottom) Open and Red Page State
		if (_chestDrawersOpen == 4)
			return getVar(102);
		else
			return 2;
	case 36: // Ship Chamber Door State
		if (_tempVar) {
			if (_state.lightState)
				return 2; // Open, Light On
			else
				return 1; // Open, Light Off
		} else {
			return 0; // Closed
		}
	case 102: // Red page
		return !(_globals.redPagesInBook & 8) && (_globals.heldPage != kRedStoneshipPage);
	case 103: // Blue page
		return !(_globals.bluePagesInBook & 8) && (_globals.heldPage != kBlueStoneshipPage);
	default:
		return MystScriptParser::getVar(var);
	}
}

void Stoneship::toggleVar(uint16 var) {
	switch(var) {
	case 0: // Water Drained From Lighthouse / Right Button Of Pump
		if (_state.pumpState == 4)
			_state.pumpState = 0;
		else
			_state.pumpState = 4;
		break;
	case 1: // Water Drained From Tunnels To Brothers' Rooms / Middle Button Of Pump
		if (_state.pumpState == 2)
			_state.pumpState = 0;
		else
			_state.pumpState = 2;
		break;
	case 2: // Water Drained From Ship Cabin Tunnel / Left Button Of Pump
		if (_state.pumpState == 1)
			_state.pumpState = 0;
		else
			_state.pumpState = 1;
		break;
	case 6: // Chest valve state
		_state.chestValveState = (_state.chestValveState + 1) % 2;
		break;
	case 8:  // Lighthouse Chest Key Position
		if (_state.trapdoorKeyState) {
			if (_state.trapdoorKeyState == 1)
				_state.trapdoorKeyState = 2;
			else
				_state.trapdoorKeyState = 1;
		}
		break;
	case 10: // Chest water state
		_state.chestWaterState = 0;
		break;
	case 11:
		if (_state.chestOpenState)
			_state.trapdoorKeyState = _state.trapdoorKeyState != 1;
		break;
	case 20: // Ship Chamber Table/Book State
		_cabinMystBookPresent = (_cabinMystBookPresent + 1) % 2;
		break;
	case 29: // Achenar's Room Rose/Skull Hologram Button Lit
		_hologramTurnedOn = (_hologramTurnedOn + 1) % 2;
		break;
	case 102: // Red page
		if (!(_globals.redPagesInBook & 8)) {
			if (_globals.heldPage == kRedStoneshipPage)
				_globals.heldPage = kNoPage;
			else
				_globals.heldPage = kRedStoneshipPage;
		}
		break;
	case 103: // Blue page
		if (!(_globals.bluePagesInBook & 8)) {
			if (_globals.heldPage == kBlueStoneshipPage)
				_globals.heldPage = kNoPage;
			else
				_globals.heldPage = kBlueStoneshipPage;
		}
		break;
	default:
		MystScriptParser::toggleVar(var);
		break;
	}
}

bool Stoneship::setVarValue(uint16 var, uint16 value) {
	bool refresh = false;

	switch (var) {
	case 5: // Lighthouse Trapdoor State
		_state.trapdoorState = value;
		break;
	case 7:
		if (_state.chestOpenState != value)
			_state.chestOpenState = value;
		break;
	case 8: // Lighthouse Chest Key Position
		_state.trapdoorKeyState = value;
		break;
	case 15: // Side Door in Tunnels To Brother's Rooms Open
		if (_state.sideDoorOpened != value) {
			if (!value && _state.generatorPowerAvailable == 2)
				_state.generatorPowerAvailable = 0;
			_state.sideDoorOpened = value;
			refresh = true;
		}
		break;
	case 17: // Sirrus' Room Drawer with Drugs Open
		if (_siriusDrawerDrugsOpen != value) {
			_siriusDrawerDrugsOpen = value;
			refresh = true;
		}
		break;
	case 18: // Brother Room Door Open
		if (_brotherDoorOpen != value) {
			_brotherDoorOpen = value;
			refresh = true;
		}
		break;
	case 21: // Brothers Rooms' Chest Of Drawers Drawer State
		if (_chestDrawersOpen != value) {
			_chestDrawersOpen = value;
			refresh = true;
		}
		break;
	case 29: // Achenar's Room Rose/Skull Hologram Button Lit
		_hologramTurnedOn = value;
		break;
	case 34: // Achenar's Room Drawer with Torn Note Closed
		_chestAchenarBottomDrawerClosed = value;
		break;
	default:
		refresh = MystScriptParser::setVarValue(var, value);
		break;
	}

	return refresh;
}

void Stoneship::o_pumpTurnOff(uint16 var, const ArgumentsArray &args) {
	if (_state.pumpState) {
		uint16 buttonVar = 0;

		switch (_state.pumpState) {
		case 1:
			buttonVar = 2;
			break;
		case 2:
			buttonVar = 1;
			break;
		case 4:
			buttonVar = 0;
			break;
		default:
			warning("Incorrect pump state");
		}

		for (uint i = 0; i < _vm->getCard()->_resources.size(); i++) {
			MystArea *resource = _vm->getCard()->_resources[i];
			if (resource->hasType(kMystAreaImageSwitch) && resource->getImageSwitchVar() == buttonVar) {
				static_cast<MystAreaImageSwitch *>(resource)->drawConditionalDataToScreen(0, true);
				break;
			}
		}
	}
}

void Stoneship::o_brotherDoorOpen(uint16 var, const ArgumentsArray &args) {
	_brotherDoorOpen = 1;
	_vm->getCard()->redrawArea(19, 0);
	animatedUpdate(args, 5);
}

void Stoneship::o_cabinBookMovie(uint16 var, const ArgumentsArray &args) {
	uint16 startTime = args[0];
	uint16 endTime = args[1];

	VideoEntryPtr book = _vm->playMovie("bkroom", kStoneshipStack);
	book->moveTo(159, 99);
	book->setBounds(Audio::Timestamp(0, startTime, 600), Audio::Timestamp(0, endTime, 600));

	_vm->waitUntilMovieEnds(book);
}

void Stoneship::o_drawerOpenSirius(uint16 var, const ArgumentsArray &args) {
	MystAreaImageSwitch *drawer = _vm->getCard()->getResource<MystAreaImageSwitch>(args[0]);

	if (drawer->getImageSwitchVar() == 35) {
		drawer->drawConditionalDataToScreen(getVar(102), 0);
	} else {
		drawer->drawConditionalDataToScreen(0, 0);
	}

	TransitionType transition = kTransitionTopToBottom;
	if (args.size() == 2 && args[1])
		transition = kTransitionCopy;

	_vm->_gfx->runTransition(transition, drawer->getRect(), 25, 5);
}

void Stoneship::o_drawerClose(uint16 var, const ArgumentsArray &args) {
	drawerClose(args[0]);
}

void Stoneship::o_telescopeStart(uint16 var, const ArgumentsArray &args) {
	const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();
	_telescopeOldMouse = mouse.x;
	_vm->_cursor->setCursor(700);
}

void Stoneship::o_telescopeMove(uint16 var, const ArgumentsArray &args) {
	MystAreaDrag *display = getInvokingResource<MystAreaDrag>();
	const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();

	// Compute telescope position
	_telescopePosition = (_telescopePosition - (mouse.x - _telescopeOldMouse) / 2 + 3240) % 3240;
	_telescopeOldMouse = mouse.x;

	// Copy image to screen
	Common::Rect src = Common::Rect(_telescopePosition, 0, _telescopePosition + 112, 112);
	_vm->_gfx->copyImageSectionToScreen(_telescopePanorama, src, display->getRect());

	// Draw lighthouse
	telescopeLighthouseDraw();
}

void Stoneship::o_telescopeStop(uint16 var, const ArgumentsArray &args) {
	_vm->refreshCursor();
}

void Stoneship::o_generatorStart(uint16 var, const ArgumentsArray &args) {
	MystAreaDrag *handle = getInvokingResource<MystAreaDrag>();

	uint16 soundId = handle->getList1(0);
	if (soundId)
		_vm->_sound->playEffect(soundId);

	if (_state.generatorDuration)
		_state.generatorDuration -= _vm->getTotalPlayTime() - _state.generatorDepletionTime;

	// Start charging the battery
	_batteryDepleting = false;
	_batteryCharging = true;
	_batteryNextTime = _vm->getTotalPlayTime() + 1000;

	// Start handle movie
	MystAreaVideo *movie = static_cast<MystAreaVideo *>(handle->getSubResource(0));
	movie->playMovie();

	soundId = handle->getList2(0);
	if (soundId)
		_vm->_sound->playEffect(soundId, true);
}

void Stoneship::o_generatorStop(uint16 var, const ArgumentsArray &args) {
	_batteryCharging = false;

	if (_state.generatorDuration) {
		// Clip battery power
		if (_state.generatorDuration > 600000)
			_state.generatorDuration = 600000;

		// Start depleting power
		_state.generatorDepletionTime = _vm->getTotalPlayTime() + _state.generatorDuration;
		_state.generatorPowerAvailable = 1;
		_batteryDepleting = true;
		_batteryNextTime = _vm->getTotalPlayTime() + 60000;
	}

	// Pause handle movie
	MystAreaDrag *handle = getInvokingResource<MystAreaDrag>();
	MystAreaVideo *movie = static_cast<MystAreaVideo *>(handle->getSubResource(0));
	movie->pauseMovie(true);

	uint16 soundId = handle->getList3(0);
	if (soundId)
		_vm->_sound->playEffect(soundId);
}

void Stoneship::chargeBattery_run() {
	uint32 time = _vm->getTotalPlayTime();

	if (time > _batteryNextTime) {
		_batteryNextTime = time + 1000;
		_state.generatorDuration += 30000;
	}
}

uint16 Stoneship::batteryRemainingCharge() {
	uint32 time = _vm->getTotalPlayTime();

	if (_state.generatorDepletionTime > time) {
		return (_state.generatorDepletionTime - time) / 7500;
	} else {
		return 0;
	}
}

void Stoneship::batteryDeplete_run() {
	uint32 time = _vm->getTotalPlayTime();

	if (time > _batteryNextTime) {
		if (_state.generatorDuration > 60000) {
			_state.generatorDuration -= 60000;
			_batteryNextTime = time + 60000;
		} else { // Battery depleted
			_state.generatorDuration = 0;
			_state.generatorDepletionTime = 0;

			if (_state.sideDoorOpened)
				_state.generatorPowerAvailable = 2;
			else
				_state.generatorPowerAvailable = 0;

			_batteryDepleting = false;
		}
	}
}

void Stoneship::o_drawerOpenAchenar(uint16 var, const ArgumentsArray &args) {
	MystAreaImageSwitch *drawer = _vm->getCard()->getResource<MystAreaImageSwitch>(args[0]);
	drawer->drawConditionalDataToScreen(0, 0);
	_vm->_gfx->runTransition(kTransitionTopToBottom, drawer->getRect(), 25, 5);
}

void Stoneship::o_hologramPlayback(uint16 var, const ArgumentsArray &args) {
	// Used for Card 2013 (Achenar's Rose-Skull Hologram)
	uint16 startPoint = args[0];
	uint16 endPoint = args[1];
	// uint16 direction = args[2];

	_hologramDisplay->setBlocking(false);
	VideoEntryPtr displayMovie = _hologramDisplay->playMovie();

	if (_hologramTurnedOn) {
		if (_hologramDisplayPos)
			endPoint = _hologramDisplayPos;
		displayMovie->setBounds(Audio::Timestamp(0, startPoint, 600), Audio::Timestamp(0, endPoint, 600));
	} else {
		displayMovie->setBounds(Audio::Timestamp(0, startPoint, 600), Audio::Timestamp(0, endPoint, 600));
	}

	_vm->waitUntilMovieEnds(displayMovie);
}

void Stoneship::o_hologramSelectionStart(uint16 var, const ArgumentsArray &args) {
	//_vm->_cursor->setCursor(0);
}

void Stoneship::o_hologramSelectionMove(uint16 var, const ArgumentsArray &args) {
	MystAreaDrag *handle = getInvokingResource<MystAreaDrag>();
	const Common::Point &mouse = _vm->_system->getEventManager()->getMousePos();

	if (handle->getRect().contains(mouse)) {
		int16 position = mouse.x - 143;
		position = CLIP<int16>(position, 0, 242);

		// Draw handle movie frame
		uint16 selectionPos = position * 1500 / 243;

		VideoEntryPtr handleMovie = _hologramSelection->playMovie();
		_vm->_video->drawVideoFrame(handleMovie, Audio::Timestamp(0, selectionPos, 600));

		_hologramDisplayPos = position * 1450 / 243 + 350;

		// Draw display movie frame
		if (_hologramTurnedOn) {
			_hologramDisplay->setBlocking(false);
			VideoEntryPtr displayMovie = _hologramDisplay->playMovie();
			_vm->_video->drawVideoFrame(displayMovie, Audio::Timestamp(0, _hologramDisplayPos, 600));
		}
	}
}

void Stoneship::o_hologramSelectionStop(uint16 var, const ArgumentsArray &args) {
	_vm->refreshCursor();
}

void Stoneship::o_compassButton(uint16 var, const ArgumentsArray &args) {
	// Used on Card 2111 (Compass Rose)
	// Called when Button Clicked.
	uint16 correctButton = args[0];

	if (correctButton) {
		// Correct Button -> Light On Logic
		_state.lightState = 1;
	} else {
		// Wrong Button -> Power Failure Logic
		_state.generatorPowerAvailable = 2;
		_state.lightState = 0;
		_state.generatorDepletionTime = 0;
		_state.generatorDuration = 0;

		_batteryDepleting = false;
	}

	o_redrawCard(var, args);
}

void Stoneship::o_chestValveVideos(uint16 var, const ArgumentsArray &args) {
	_vm->_sound->playEffect(2132);

	if (_state.chestValveState) {
		// Valve closing
		VideoEntryPtr valve = _vm->playMovie("ligspig", kStoneshipStack);
		valve->moveTo(97, 267);
		valve->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 350, 600));

		_vm->waitUntilMovieEnds(valve);
	} else if (_state.chestWaterState) {
		// Valve opening, spilling water
		VideoEntryPtr valve = _vm->playMovie("ligspig", kStoneshipStack);
		valve->moveTo(97, 267);
		valve->setBounds(Audio::Timestamp(0, 350, 600), Audio::Timestamp(0, 650, 600));

		_vm->waitUntilMovieEnds(valve);

		_vm->_sound->playEffect(3132);

		for (uint i = 0; i < 25; i++) {
			valve = _vm->playMovie("ligspig", kStoneshipStack);
			valve->moveTo(97, 267);
			valve->setBounds(Audio::Timestamp(0, 650, 600), Audio::Timestamp(0, 750, 600));
			_vm->waitUntilMovieEnds(valve);
		}

		_vm->_sound->resumeBackground();
	} else {
		// Valve opening
		VideoEntryPtr valve = _vm->playMovie("ligspig", kStoneshipStack);
		valve->moveTo(97, 267);
		valve->seek(Audio::Timestamp(0, 350, 600));
		valve->setRate(-1);

		_vm->waitUntilMovieEnds(valve);
	}
}

void Stoneship::o_chestDropKey(uint16 var, const ArgumentsArray &args) {
	// If holding Key to Lamp Room Trapdoor, drop to bottom of
	// Lighthouse...
	if (_state.trapdoorKeyState == 1) {
		_vm->setMainCursor(_savedCursorId);
		_state.trapdoorKeyState = 2;
	}
}

void Stoneship::o_trapLockOpen(uint16 var, const ArgumentsArray &args) {
	VideoEntryPtr lock = _vm->playMovie("openloc", kStoneshipStack);
	lock->moveTo(187, 71);
	lock->setBounds(Audio::Timestamp(0, 0, 600), Audio::Timestamp(0, 750, 600));
	_vm->waitUntilMovieEnds(lock);

	_vm->_sound->playEffect(2143);

	lock = _vm->playMovie("openloc", kStoneshipStack);
	lock->moveTo(187, 71);
	lock->setBounds(Audio::Timestamp(0, 750, 600), Audio::Timestamp(0, 10000, 600));
	_vm->waitUntilMovieEnds(lock);

	if (_state.pumpState != 4)
		_vm->_sound->playEffect(4143);
}

void Stoneship::o_sideDoorsMovies(uint16 var, const ArgumentsArray &args) {
	// Used for Cards 2285, 2289, 2247, 2251 (Side Doors in Tunnels Down To Brothers Rooms)
	uint16 movieId = args[0];

	_vm->_cursor->hideCursor();
	_vm->_sound->pauseBackground();

	switch (movieId) {
	case 0:
		// Card 2251
		_vm->playMovieBlocking("tunaup", kStoneshipStack, 149, 161);
		break;
	case 1:
		// Card 2247
		_vm->playMovieBlocking("tunadown", kStoneshipStack, 218, 150);
		break;
	case 2:
		// Card 2289
		_vm->playMovieBlocking("tuncup", kStoneshipStack, 259, 161);
		break;
	case 3:
		// Card 2285
		_vm->playMovieBlocking("tuncdown", kStoneshipStack, 166, 150);
		break;
	default:
		warning("Opcode 120 MovieId Out Of Range");
		break;
	}

	_vm->_sound->resumeBackground();
	_vm->_cursor->showCursor();
}

void Stoneship::o_cloudOrbEnter(uint16 var, const ArgumentsArray &args) {
	_vm->_sound->playEffect(_cloudOrbSound, true);
	_cloudOrbMovie->playMovie();
}

void Stoneship::o_cloudOrbLeave(uint16 var, const ArgumentsArray &args) {
	_cloudOrbMovie->pauseMovie(true);
	_vm->_sound->playEffect(_cloudOrbStopSound);
	_vm->_gfx->runTransition(kTransitionTopToBottom, getInvokingResource<MystArea>()->getRect(), 4, 0);
}

void Stoneship::o_drawerCloseOpened(uint16 var, const ArgumentsArray &args) {
	uint16 drawerOpen = getVar(var);
	if (drawerOpen)
		drawerClose(args[0] + drawerOpen - 1);
}

void Stoneship::drawerClose(uint16 drawer) {
	_chestDrawersOpen = 0;
	_vm->getCard()->drawBackground();
	_vm->getCard()->drawResourceImages();

	MystArea *res = _vm->getCard()->getResource<MystArea>(drawer);
	_vm->_gfx->runTransition(kTransitionBottomToTop, res->getRect(), 25, 5);
}

void Stoneship::o_hologramDisplay_init(uint16 var, const ArgumentsArray &args) {
	_hologramDisplay = getInvokingResource<MystAreaVideo>();

	_hologramDisplayPos = 0;
}

void Stoneship::o_hologramSelection_init(uint16 var, const ArgumentsArray &args) {
	_hologramSelection = getInvokingResource<MystAreaVideo>();
}

void Stoneship::batteryGaugeUpdate() {
	uint16 charge = 0;

	if (_state.generatorDepletionTime) {
		charge = batteryRemainingCharge();
	}

	Common::Rect rect = _batteryGauge->getRect();

	rect.top = rect.bottom - charge;

	_batteryGauge->setRect(rect);
}

void Stoneship::o_battery_init(uint16 var, const ArgumentsArray &args) {
	// Used for Card 2160 (Lighthouse Battery Pack Closeup)
	_batteryGauge = getInvokingResource<MystAreaImageSwitch>();

	batteryGaugeUpdate();
}

void Stoneship::o_tunnelEnter_init(uint16 var, const ArgumentsArray &args) {
	o_tunnel_init(var, args);

	_tunnelRunning = true;
	_tunnelNextTime = _vm->getTotalPlayTime() + 1500;
}

void Stoneship::o_batteryGauge_init(uint16 var, const ArgumentsArray &args) {
	_batteryLastCharge = batteryRemainingCharge();
	_batteryGaugeRunning = true;
}

void Stoneship::batteryGauge_run() {
	uint16 batteryCharge = batteryRemainingCharge();

	if (batteryCharge != _batteryLastCharge) {
		batteryGaugeUpdate();

		_batteryLastCharge = batteryCharge;

		// Redraw card
		_vm->getCard()->drawBackground();
		_vm->getCard()->drawResourceImages();
		_vm->_gfx->copyBackBufferToScreen(Common::Rect(544, 333));
	}
}

void Stoneship::o_tunnel_init(uint16 var, const ArgumentsArray &args) {
		_tunnelImagesCount = args[0];

		assert(_tunnelImagesCount <= 2 && "Too many images");

		for (uint i = 0; i < _tunnelImagesCount; i++) {
			_tunnelImages[i] = args[i + 1];
		}

		_tunnelAlarmSound = args[args.size() - 1];

		debugC(kDebugScript, "\timage count: %d", _tunnelImagesCount);
		debugC(kDebugScript, "\tsoundIdAlarm: %d", _tunnelAlarmSound);
}

void Stoneship::tunnel_run() {
	uint32 time = _vm->getTotalPlayTime();

	if (time > _tunnelNextTime) {
		_tunnelNextTime = time + 1500;
		if (_state.generatorPowerAvailable == 2) {
			// Draw tunnel black
			if (_tunnelImagesCount) {
				_vm->_gfx->copyImageToScreen(_tunnelImages[1], Common::Rect(544, 333));
			}

			_vm->_sound->playEffect(_tunnelAlarmSound);

			// Draw tunnel dark
			if (_tunnelImagesCount) {
				_vm->_gfx->copyImageToScreen(_tunnelImages[0], Common::Rect(544, 333));
			}
		}
	}
}

void Stoneship::o_tunnelLeave_init(uint16 var, const ArgumentsArray &args) {
	_tunnelRunning = false;
}

void Stoneship::o_chest_init(uint16 var, const ArgumentsArray &args) {
	_state.chestOpenState = 0;
}

void Stoneship::o_telescope_init(uint16 var, const ArgumentsArray &args) {
	// Used in Card 2218 (Telescope view)
	_telescopePanorama = args[0];
	_telescopeLighthouseOff = args[1];
	_telescopeLighthouseOn = args[2];
	_telescopePosition = 0;

	_telescopeRunning = true;
	_telescopeLighthouseState = false;
	_telescopeNexTime = _vm->getTotalPlayTime() + 1000;
}

void Stoneship::telescope_run() {
	uint32 time = _vm->getTotalPlayTime();

	if (time > _telescopeNexTime) {

		_telescopeNexTime = time + 1000;
		_telescopeLighthouseState = !_telescopeLighthouseState;

		telescopeLighthouseDraw();
	}
}

void Stoneship::telescopeLighthouseDraw() {
	if (_telescopePosition > 1137 && _telescopePosition < 1294) {
		uint16 imageId = _telescopeLighthouseOff;

		if (_state.generatorPowerAvailable == 1 && _telescopeLighthouseState)
			imageId = _telescopeLighthouseOn;

		Common::Rect src(1205, 0, 1205 + 131, 112);
		src.clip(Common::Rect(_telescopePosition, 0, _telescopePosition + 112, 112));
		src.translate(-1205, 0);
		src.clip(131, 112);

		Common::Rect dest(_telescopePosition, 0, _telescopePosition + 112, 112);
		dest.clip(Common::Rect(1205, 0, 1205 + 131, 112));
		dest.translate(-_telescopePosition, 0);
		dest.clip(112, 112);
		dest.translate(222, 112);

		_vm->_gfx->copyImageSectionToScreen(imageId, src, dest);
	}
}

void Stoneship::o_achenarDrawers_init(uint16 var, const ArgumentsArray &args) {
	// Used for Card 2004 (Achenar's Room Drawers)
	if (!_chestAchenarBottomDrawerClosed) {
		uint16 count1 = args[0];
		for (uint16 i = 0; i < count1; i++) {
			debugC(kDebugScript, "Disable hotspot index %d", args[i + 1]);
			_vm->getCard()->setResourceEnabled(args[i + 1], false);
		}
		uint16 count2 = args[count1 + 1];
		for (uint16 i = 0; i < count2; i++) {
			debugC(kDebugScript, "Enable hotspot index %d", args[i + count1 + 2]);
			_vm->getCard()->setResourceEnabled(args[i + count1 + 2], true);
		}
	}
}

void Stoneship::o_cloudOrb_init(uint16 var, const ArgumentsArray &args) {
	_cloudOrbMovie = getInvokingResource<MystAreaVideo>();
	_cloudOrbSound = args[0];
	_cloudOrbStopSound = args[1];
}

} // End of namespace MystStacks
} // End of namespace Mohawk
