/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#include "titanic/npcs/parrot.h"
#include "titanic/core/project_item.h"
#include "titanic/carry/carry.h"
#include "titanic/carry/chicken.h"
#include "titanic/game_manager.h"
#include "titanic/translation.h"

namespace Titanic {

BEGIN_MESSAGE_MAP(CParrot, CTrueTalkNPC)
	ON_MESSAGE(ActMsg)
	ON_MESSAGE(MouseButtonDownMsg)
	ON_MESSAGE(MovieEndMsg)
	ON_MESSAGE(EnterViewMsg)
	ON_MESSAGE(TrueTalkTriggerActionMsg)
	ON_MESSAGE(MouseDragStartMsg)
	ON_MESSAGE(LeaveViewMsg)
	ON_MESSAGE(ParrotSpeakMsg)
	ON_MESSAGE(NPCPlayTalkingAnimationMsg)
	ON_MESSAGE(NPCPlayIdleAnimationMsg)
	ON_MESSAGE(FrameMsg)
	ON_MESSAGE(MovieFrameMsg)
	ON_MESSAGE(PutParrotBackMsg)
	ON_MESSAGE(PreEnterViewMsg)
	ON_MESSAGE(PanningAwayFromParrotMsg)
	ON_MESSAGE(LeaveRoomMsg)
	ON_MESSAGE(TrueTalkNotifySpeechStartedMsg)
	ON_MESSAGE(TrueTalkNotifySpeechEndedMsg)
END_MESSAGE_MAP()

bool CParrot::_eatingChicken;
bool CParrot::_takeOff;
bool CParrot::_unused;
ParrotState CParrot::_state;
bool CParrot::_coreReplaced;

CParrot::CParrot() : CTrueTalkNPC() {
	_unused1 = 0;
	_carryParrot = "CarryParrot";
	_canDrag = true;
	_unused2 = 25;
	_lastSpeakTime = 0;
	_newXp = 73;
	_newXc = 58;
	_triedEatChicken = false;
	_eatOffsetX = 0;
	_panTarget = nullptr;

	_assetName = "z454.dlg";
	_assetNumber = 0x13880;
}

void CParrot::save(SimpleFile *file, int indent) {
	file->writeNumberLine(1, indent);
	file->writeNumberLine(_assetNumber, indent);

	file->writeQuotedLine(_assetName, indent);
	file->writeNumberLine(_unused1, indent);
	file->writeNumberLine(_eatingChicken, indent);
	file->writeNumberLine(_takeOff, indent);
	file->writeNumberLine(_unused, indent);

	file->writeQuotedLine(_carryParrot, indent);
	file->writeNumberLine(_canDrag, indent);
	file->writeNumberLine(_unused2, indent);
	file->writeNumberLine(_lastSpeakTime, indent);
	file->writeNumberLine(_newXp, indent);
	file->writeNumberLine(_newXc, indent);
	file->writeNumberLine(_triedEatChicken, indent);
	file->writeNumberLine(_eatOffsetX, indent);
	file->writeNumberLine(_state, indent);
	file->writeNumberLine(_coreReplaced, indent);

	CTrueTalkNPC::save(file, indent);
}

void CParrot::load(SimpleFile *file) {
	file->readNumber();
	_assetNumber = file->readNumber();

	_assetName = file->readString();
	_unused1 = file->readNumber();
	_eatingChicken = file->readNumber();
	_takeOff = file->readNumber();
	_unused = file->readNumber();

	_carryParrot = file->readString();
	_canDrag = file->readNumber();
	_unused2 = file->readNumber();
	_lastSpeakTime = file->readNumber();
	_newXp = file->readNumber();
	_newXc = file->readNumber();
	_triedEatChicken = file->readNumber();
	_eatOffsetX = file->readNumber();
	_state = (ParrotState)file->readNumber();
	_coreReplaced = file->readNumber();

	CTrueTalkNPC::load(file);
}

bool CParrot::ActMsg(CActMsg *msg) {
	if (msg->_action == "Chicken") {
		// Nothing to do
	} else if (msg->_action == "CarryParrotLeftView") {
		if (!_takeOff)
			setEatingChicken(false);
	} else if (msg->_action == "StartChickenDrag") {
		if (_state == PARROT_IN_CAGE) {
			stopMovie();
			startTalking(this, 280275, findView());
			_triedEatChicken = false;
		}
	} else if (msg->_action == "EnteringFromTOW" &&
			(_state == PARROT_IN_CAGE || _state == PARROT_ESCAPED)) {
		if (_takeOff) {
			_state = PARROT_ESCAPED;
		} else {
			setVisible(true);
			CTreeItem *cageBar = getRoot()->findByName("CageBar");
			detach();
			attach(cageBar);

			_state = PARROT_IN_CAGE;
			CActMsg actMsg1("OpenNow");
			actMsg1.execute("ParrotCage");
			CActMsg actMsg2("GainParrot");
			actMsg2.execute("ParrotLobbyController");
		}
	}

	return true;
}

bool CParrot::MouseButtonDownMsg(CMouseButtonDownMsg *msg) {
	if (!(_npcFlags & NPCFLAG_TAKE_OFF) && _speechCounter == 0) {
		CTrueTalkTriggerActionMsg triggerMsg(280250, 280250, 1);
		triggerMsg.execute(this);
	}

	return true;
}

bool CParrot::MovieEndMsg(CMovieEndMsg *msg) {
	if ((_npcFlags & NPCFLAG_TAKE_OFF) && clipExistsByEnd("Take Off", msg->_endFrame)) {
		setVisible(false);
		moveUnder(findRoom());
		stopMovie();

		CActMsg actMsg1("LoseParrot");
		actMsg1.execute("ParrotLobbyController");

		if (_panTarget) {
			CActMsg actMsg2("PanAwayFromParrot");
			actMsg2.execute(_panTarget);
			_panTarget = nullptr;
		} else {
			CActMsg actMsg2("Shut");
			actMsg2.execute("ParrotCage");
		}

		_npcFlags &= ~NPCFLAG_TAKE_OFF;
		_state = PARROT_ESCAPED;
	} else if (_npcFlags & NPCFLAG_MOVING) {
		if (_npcFlags & NPCFLAG_MOVE_START) {
			// Parrot is about to loop
			_npcFlags = (_npcFlags & ~NPCFLAG_MOVE_START) | NPCFLAG_MOVE_LOOP;
			if (_npcFlags & NPCFLAG_MOVE_LEFT) {
				playClip("Walk Left Loop", MOVIE_NOTIFY_OBJECT);
				movieEvent(236);
			} else {
				playClip("Walk Right Loop", MOVIE_NOTIFY_OBJECT);
			}
		} else if (_npcFlags & NPCFLAG_MOVE_LOOP) {
			// In progress movement loop
			int xp = _bounds.left + _bounds.width() / 2;

			if (_npcFlags & NPCFLAG_MOVE_LEFT) {
				if ((xp - _newXc) > 32) {
					setPosition(Point(_bounds.left - 40, _bounds.top));
					playClip("Walk Left Loop", MOVIE_NOTIFY_OBJECT);
					movieEvent(236);
				} else {
					setPosition(Point(_bounds.left - 10, _bounds.top));
					playClip("Walk Left Outro", MOVIE_NOTIFY_OBJECT);
					_npcFlags = (_npcFlags & ~NPCFLAG_MOVE_LOOP) | NPCFLAG_MOVE_FINISH;
				}
			} else {
				if ((_newXc - xp) > 32) {
					playClip("Walk Right Loop", MOVIE_NOTIFY_OBJECT);
					movieEvent(244);
				} else {
					playClip("Walk Right Outro", MOVIE_NOTIFY_OBJECT);
					_npcFlags = (_npcFlags & ~NPCFLAG_MOVE_LOOP) | NPCFLAG_MOVE_FINISH;
				}
			}
		} else if (_npcFlags & NPCFLAG_MOVE_FINISH) {
			// Finishing movement
			loadFrame(0);
			if (_npcFlags & NPCFLAG_MOVE_LEFT)
				setPosition(Point(_bounds.left - 30, _bounds.top));
			else
				setPosition(Point(_bounds.left + 14, _bounds.top));

			_npcFlags &= ~(NPCFLAG_MOVING | NPCFLAG_MOVE_FINISH | NPCFLAG_MOVE_LEFT | NPCFLAG_MOVE_RIGHT);
			CTrueTalkNPC::MovieEndMsg(msg);
		}
	} else if (_npcFlags & NPCFLAG_CHICKEN_OUTSIDE_CAGE) {
		Point pt = getMousePos();
		if (pt.x > 70 || pt.y < 90 || pt.y > 280) {
			stopMovie();
			loadFrame(0);
			_npcFlags &= ~NPCFLAG_CHICKEN_OUTSIDE_CAGE;
		}

		if (clipExistsByEnd("Walk Left Loop", msg->_endFrame)) {
			playClip("Lean Over To Chicken", MOVIE_NOTIFY_OBJECT);
			setPosition(Point(_bounds.left - 55, _bounds.top));
			_eatOffsetX = (-100 - _bounds.left) / 5;
			movieEvent(261);
			movieEvent(262);
			movieEvent(265);
			movieEvent(268);
			movieEvent(271);
			return true;

		} else if (clipExistsByEnd("Lean Over To Chicken", msg->_endFrame)) {
			// WORKAROUND: Do what the original obviously intended but got
			// wrong.. only flag chicken as eaten if it's still being dragged
			CTreeItem *dragItem = getGameManager()->_dragItem;
			CCarry *chicken = dynamic_cast<CCarry *>(dragItem);

			if (chicken)
				playClip("Eat Chicken");
			playClip("Eat Chicken 2", MOVIE_NOTIFY_OBJECT);

			if (chicken) {
				setEatingChicken(true);

				CTrueTalkTriggerActionMsg actionMsg;
				actionMsg._action = 280266;
				actionMsg._param2 = 1;
				actionMsg.execute(this);

				CActMsg actMsg("Eaten");
				actMsg.execute(chicken);
			}

			_npcFlags &= ~NPCFLAG_CHICKEN_OUTSIDE_CAGE;
			return true;
		}
	}

	if (clipExistsByEnd("Eat Chicken 2", msg->_endFrame)) {
		// Parrot has finished eating Chicken
		setEatingChicken(false);

		if (_takeOff) {
			// Perch has been taken, so take off
			loadMovie(TRANSLATE("z168.avi", "z191.avi"), false);
			playClip("Take Off", MOVIE_NOTIFY_OBJECT);
			setPosition(Point(20, 10));
			_npcFlags |= NPCFLAG_TAKE_OFF;
		} else {
			// Resetting back to standing
			_npcFlags &= ~(NPCFLAG_MOVING | NPCFLAG_MOVE_START | NPCFLAG_MOVE_LOOP
				| NPCFLAG_MOVE_FINISH | NPCFLAG_MOVE_LEFT | NPCFLAG_MOVE_RIGHT);
			_npcFlags |= NPCFLAG_MOVE_END;
			stopMovie();
			loadFrame(0);
			setPosition(Point(-90, _bounds.top));
		}
	} else {
		return CTrueTalkNPC::MovieEndMsg(msg);
	}

	return true;
}

bool CParrot::EnterViewMsg(CEnterViewMsg *msg) {
	static const char *const NAMES[] = {
		"Talking0", "Talking1", "Talking2", "Talking3", "Talking4",
		"Talking5", "Talking6", "Talking7", nullptr
	};

	if (_state == PARROT_IN_CAGE) {
		setPosition(Point(_newXp, _bounds.top));
		_canDrag = true;
		_npcFlags &= ~(NPCFLAG_MOVING | NPCFLAG_MOVE_START | NPCFLAG_MOVE_LOOP
			| NPCFLAG_MOVE_FINISH | NPCFLAG_MOVE_LEFT | NPCFLAG_MOVE_RIGHT | NPCFLAG_MOVE_END);
		loadFrame(0);
		setTalking(this, true, findView());

		if (_speechCounter > 0) {
			playRandomClip(NAMES, MOVIE_NOTIFY_OBJECT);
		} else {
			startTalking(this, 280258, findView());
		}

		petSetArea(PET_CONVERSATION);
		_triedEatChicken = false;
		_npcFlags |= NPCFLAG_START_IDLING;
	}

	return true;
}

bool CParrot::TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg) {
	if (_state != PARROT_MAILED) {
		CViewItem *view = msg->_param2 ? findView() : nullptr;
		startTalking(this, msg->_action, view);
	}

	return true;
}

bool CParrot::MouseDragStartMsg(CMouseDragStartMsg *msg) {
	if (_canDrag && _state == PARROT_IN_CAGE && checkPoint(msg->_mousePos, false, true)) {
		setVisible(false);
		CRoomItem *room = findRoom();

		moveUnder(room);
		startTalking(this, 280129);
		performAction(true);

		CCarry *item = dynamic_cast<CCarry *>(getRoot()->findByName(_carryParrot));
		if (item) {
			item->_canTake = true;
			CPassOnDragStartMsg passMsg;
			passMsg._mousePos = msg->_mousePos;
			passMsg.execute(item);
			msg->_dragItem = item;

			CActMsg actMsg("LoseParrot");
			actMsg.execute("ParrotLobbyController");
			return true;
		}
	}

	return false;
}

bool CParrot::LeaveViewMsg(CLeaveViewMsg *msg) {
	performAction(true);
	_npcFlags &= ~NPCFLAG_START_IDLING;

	return true;
}

bool CParrot::ParrotSpeakMsg(CParrotSpeakMsg *msg) {
	static const char *const ROOM_NAMES[] = {
		"SGTState", "SGTLittleLift", "SecClassLittleLift", "SecClassState",
		"Lift", "ServiceElevator", "Dome", "Home", "MoonEmbLobby", nullptr
	};

	if (!stateGetParrotMet() || _state == PARROT_MAILED || compareViewNameTo("Titania.Node 18.N"))
		return true;

	// Check for rooms not to speak in
	for (const char *const *s = &ROOM_NAMES[0]; *s; ++s) {
		if (isEquals(*s))
			return true;
	}

	// Don't have the parrot speak too often
	if ((getTicksCount() - _lastSpeakTime) < 20000 || _speechCounter)
		return true;

	playSound(TRANSLATE("z#475.wav", "z#212.wav"), 50);

	if (msg->_target == "Bomb") {
		startTalking("PerchedParrot", 280236);
	} else if (msg->_target == "Announcements") {
		startTalking("PerchedParrot", 280263);
	} else if (msg->_target == "Television") {
		startTalking("PerchedParrot", 280264);
	} else if (msg->_target == "Barbot") {
		if (msg->_action == "AskForDrink")
			startTalking("PerchedParrot", 280262);
	} else if (msg->_target == "SuccUBus") {
		if (msg->_action == "TurnOn")
			startTalking("PerchedParrot", 80161);
		else if (msg->_action == "EnterView")
			startTalking("PerchedParrot", 80159);
	} else if (msg->_target == "Cellpoints") {
		if (getRandomNumber(2) == 0) {
			switch (getRandomNumber(2)) {
			case 0:
				startTalking("PerchedParrot", 80193);
				break;
			case 1:
				startTalking("PerchedParrot", 80197);
				break;
			case 2:
				startTalking("PerchedParrot", 80198);
				break;
			default:
				break;
			}
		} else if (msg->_action == "DoorBot") {
			startTalking("PerchedParrot", 80195);
		} else if (msg->_action == "DeskBot") {
			startTalking("PerchedParrot", 80194);
		} else if (msg->_action == "BarBot") {
			startTalking("PerchedParrot", 80191);
		} else if (msg->_action == "BellBot") {
			startTalking("PerchedParrot", 80192);
		} else if (msg->_action == "LiftBot") {
			startTalking("PerchedParrot", 80196);
		}
	}

	_lastSpeakTime = getTicksCount();
	return true;
}

bool CParrot::NPCPlayTalkingAnimationMsg(CNPCPlayTalkingAnimationMsg *msg) {
	static const char *const NAMES[] = {
		"Talking0", "Talking1", "Talking2", "Talking3", "Talking4",
		"Talking5", "Talking6", "Talking7", nullptr
	};

	if (!(_npcFlags & (NPCFLAG_MOVING | NPCFLAG_MOVE_START | NPCFLAG_MOVE_LOOP | NPCFLAG_MOVE_FINISH 
			| NPCFLAG_MOVE_LEFT | NPCFLAG_MOVE_RIGHT | NPCFLAG_MOVE_END))
			&& _visible && _state == PARROT_IN_CAGE) {
		if (compareViewNameTo("ParrotLobby.Node 1.N"))
			msg->_names = NAMES;
	}

	return true;
}

bool CParrot::NPCPlayIdleAnimationMsg(CNPCPlayIdleAnimationMsg *msg) {
	static const char *const NAMES[] = {
		"Idle0", "Idle1", "Peck At Feet", "Peck At Feet Left"
		"Peck At Feet Right", nullptr
	};

	if (!(_npcFlags & (NPCFLAG_MOVING | NPCFLAG_MOVE_START | NPCFLAG_MOVE_LOOP | NPCFLAG_MOVE_FINISH 
			| NPCFLAG_MOVE_LEFT | NPCFLAG_MOVE_RIGHT | NPCFLAG_MOVE_END))
			&& _visible && _state == PARROT_IN_CAGE && compareViewNameTo("ParrotLobby.Node 1.N")) {
		CGameObject *dragItem = getDraggingObject();
		if (!dragItem || dragItem->getName() == "Chicken") {
			if (!_coreReplaced || getRandomNumber(3) != 0) {
				if (getRandomNumber(1)) {
					startTalking(this, 280267, findView());
				} else {
					msg->_names = NAMES;
				}
			} else {
				int id = -1;
				switch (getParrotResponse()) {
				case 0:
					id = 280107;
					break;
				case 1:
					id = 280106;
					break;
				case 2:
					id = 280115;
					break;
				case 3:
					id = 280114;
					break;
				case 4:
					id = 280113;
					break;
				case 5:
					id = 280112;
					break;
				case 6:
					id = 280111;
					break;
				case 7:
					id = 280110;
					break;
				case 8:
					id = 280109;
					break;
				case 9:
					id = 280108;
					break;
				case 10:
					id = 280105;
					break;
				case 11:
					id = 280000;
					break;
				default:
					break;
				}

				if (id != -1)
					startTalking(this, id, findView());

				CActMsg actMsg("FlashCore");
				actMsg.execute("PerchCoreHolder");
			}
		}
	}

	return true;
}

bool CParrot::FrameMsg(CFrameMsg *msg) {
	if (!compareViewNameTo("ParrotLobby.Node 1.N"))
		return false;
	if (_state != PARROT_IN_CAGE)
		return true;

	Point pt = getMousePos();
	CGameObject *dragObject = getDraggingObject();
	int xp = _bounds.left + _bounds.width() / 2;
	bool chickenFlag = false;

	if ((_npcFlags & NPCFLAG_MOVE_END) && !hasActiveMovie()) {
		_newXc =  _newXp + _bounds.width() / 2;
		int xDiff = ABS(xp - _newXc);

		if (xDiff < 64) {
			if (_panTarget) {
				CActMsg actMsg("PanAwayFromParrot");
				actMsg.execute(_panTarget);
				_panTarget = nullptr;
			}

			_npcFlags &= ~(NPCFLAG_MOVING | NPCFLAG_MOVE_START | NPCFLAG_MOVE_LOOP
				| NPCFLAG_MOVE_FINISH | NPCFLAG_MOVE_LEFT | NPCFLAG_MOVE_RIGHT | NPCFLAG_MOVE_END);
			return true;
		}

		// WORKAROUND: Prevent panning away from stalling if Parrot was moving
		_npcFlags &= ~NPCFLAG_MOVING;
	} else {
		if (dragObject)
			chickenFlag = dragObject && dragObject->isEquals("Chicken");

		if (_npcFlags & NPCFLAG_CHICKEN_OUTSIDE_CAGE) {
			if (!chickenFlag || pt.x > 70 || pt.y < 90 || pt.y > 280) {
				// A start of eating the chicken outside the cage has to be
				// aborted because the chicken has been moved out of range
				stopMovie();
				loadFrame(0);
				setPosition(Point(-90, _bounds.top));
				_npcFlags &= ~NPCFLAG_CHICKEN_OUTSIDE_CAGE;
			}
		} else {
			if (!chickenFlag)
				return false;
		}

		_newXc = CLIP((int)pt.x, 230, 480);
	}

	if ((_npcFlags & NPCFLAG_MOVING) || hasActiveMovie())
		return true;

	if (ABS(_newXc - xp) > 64) {
		_npcFlags |= NPCFLAG_MOVING | NPCFLAG_MOVE_START;

		if (_newXc >= xp) {
			// WORKAROUND: Original did not properly reset the eating chicken
			// flag when the player turns away from the cage
			setEatingChicken(false);

			setPosition(Point(_bounds.left + 30, _bounds.top));
			_npcFlags |= NPCFLAG_MOVE_RIGHT;
			playClip("Walk Right Intro", MOVIE_NOTIFY_OBJECT);
		} else {
			_npcFlags |= NPCFLAG_MOVE_LEFT;
			playClip("Walk Left Intro", MOVIE_NOTIFY_OBJECT);
		}
	} else if (chickenFlag && pt.y >= 90 && pt.y <= 280 && !_triedEatChicken) {
		CParrotTriesChickenMsg triesMsg;
		triesMsg.execute(dragObject);

		CTrueTalkTriggerActionMsg triggerMsg;
		int &action = triggerMsg._action;
		switch (triesMsg._condiment) {
		case 1:
			action = triesMsg._isHot ? 280034 : 280056;
			break;
		case 2:
			action = triesMsg._isHot ? 280033 : 280055;
			break;
		case 3:
			action = triesMsg._isHot ? 280032 : 280054;
			break;
		default:
			action = triesMsg._isHot ? 280266 : 280053;
			break;
		}

		if (action == 280266) {
			if (pt.x < 75) {
				// Parrot needs to reach outside the cage
				_npcFlags |= NPCFLAG_CHICKEN_OUTSIDE_CAGE;
				playClip("Walk Left Intro", MOVIE_STOP_PREVIOUS);
				playClip("Walk Left Loop", MOVIE_NOTIFY_OBJECT);
				movieEvent(236);
				chickenFlag = false;
			} else if ((pt.x - xp) > 15) {
				_npcFlags |= NPCFLAG_PECKING;
				playClip("Peck At Feet Right", MOVIE_NOTIFY_OBJECT);
				movieEvent(170);
			} else if ((xp - pt.x) > 15) {
				_npcFlags |= NPCFLAG_PECKING;
				playClip("Peck At Feet Left", MOVIE_NOTIFY_OBJECT);
				movieEvent(142);
			} else {
				_npcFlags |= NPCFLAG_PECKING;
				playClip("Peck At Feet", MOVIE_NOTIFY_OBJECT);
				movieEvent(157);
			}
		}

		if (chickenFlag) {
			triggerMsg._param2 = 1;
			triggerMsg.execute(this);
			_triedEatChicken = true;
		}
	}

	return true;
}

bool CParrot::MovieFrameMsg(CMovieFrameMsg *msg) {
	if (_npcFlags & NPCFLAG_PECKING) {
		// Whoopsy, the Parrot got your chicken
		CCarry *chicken = dynamic_cast<CCarry *>(findUnder(getRoot(), "Chicken"));
		if (chicken) {
			CActMsg actMsg("Eaten");
			actMsg.execute(chicken);
		}

		_npcFlags &= ~NPCFLAG_PECKING;
	}

	switch (msg->_frameNumber) {
	case 244:
		setPosition(Point(_bounds.left + 45, _bounds.top));
		break;
	case 261:
	case 262:
	case 265:
	case 268:
	case 271:
		setPosition(Point(_bounds.left + _eatOffsetX, _bounds.top));
		break;
	default:
		break;
	}

	return true;
}

bool CParrot::PutParrotBackMsg(CPutParrotBackMsg *msg) {
	const char *const NAMES[] = {
		"Talking0", "Talking1", "Talking2", "Talking3", "Talking4",
		"Talking5", "Talking6", "Talking7", nullptr
	};

	int xp = CLIP(msg->_value, 230, 480);
	setVisible(true);
	moveToView();
	_state = PARROT_IN_CAGE;

	setPosition(Point(xp - _bounds.width() / 2, _bounds.top));
	playRandomClip(NAMES, MOVIE_NOTIFY_OBJECT);

	CActMsg actMsg("GainParrot");
	actMsg.execute("ParrotLobbyController");

	return true;
}

bool CParrot::PreEnterViewMsg(CPreEnterViewMsg *msg) {
	if (_state == PARROT_IN_CAGE) {
		loadMovie(TRANSLATE("z167.avi", "z190.avi"), false);
		loadFrame(0);
	}

	return true;
}

bool CParrot::PanningAwayFromParrotMsg(CPanningAwayFromParrotMsg *msg) {
	if (_state != PARROT_IN_CAGE) {
		CActMsg actMsg("PanAwayFromParrot");
		actMsg.execute(msg->_target);
		_panTarget = nullptr;
	} else if (_takeOff) {
		_panTarget = msg->_target;
		loadMovie(TRANSLATE("z168.avi", "z191.avi"), false);
		stopMovie();
		playClip("Take Off", MOVIE_NOTIFY_OBJECT);
		_npcFlags |= NPCFLAG_TAKE_OFF;
	} else {
		_npcFlags |= NPCFLAG_MOVE_END;
		_panTarget = msg->_target;
		stopMovie();
	}

	return true;
}

bool CParrot::LeaveRoomMsg(CLeaveRoomMsg *msg) {
	if (_state == PARROT_IN_CAGE)
		startTalking(this, 280259);

	return true;
}

bool CParrot::TrueTalkNotifySpeechStartedMsg(CTrueTalkNotifySpeechStartedMsg *msg) {
	// WORKAROUND: Fix parrot freezing up if you drag the chicken whilst
	// he's still returning to the center from a prior chicken drag
	if (_npcFlags & (NPCFLAG_MOVE_LEFT | NPCFLAG_MOVE_RIGHT))
		_npcFlags &= ~(NPCFLAG_MOVING | NPCFLAG_MOVE_LEFT | NPCFLAG_MOVE_RIGHT);

	return CTrueTalkNPC::TrueTalkNotifySpeechStartedMsg(msg);
}

bool CParrot::TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg) {
	if (msg->_dialogueId == 80022) {
		// WORKAROUND: End of parrot speech after having fixed Titania
		unlockMouse();
		changeView("Titania.Node 18.N", "");
	}

	return CTrueTalkNPC::TrueTalkNotifySpeechEndedMsg(msg);
}

void CParrot::setEatingChicken(bool eating) {
	_eatingChicken = eating;
	CStatusChangeMsg statusMsg;
	statusMsg._newStatus = eating ? 0 : 1;
	statusMsg.execute("PerchCoreHolder");
}

} // End of namespace Titanic