/*
	Mrs T.c
	Formerly part of enemies.c
   Started by Chris Wilson 2/2000
*/


// SFX notes for Mr T
//	Footsteps (surprise!)

// SFX notes for Mrs T
//	Footsteps (surprise!)



#include <limits.h>

#include "global.h"
#include "maths.h"
#include "bff_load.h"
#include "lights.h"
#include "timer.h"
#include "collide.h"
#include "overlays.h"
#include "main.h"
#include "inventory.h"
#include "map_draw.h"
#include "puzzles.h"
#include "enemies.h"
#include "camera.h"
#include "debris.h"
#include "deth.h"
#include "loadsnd.h"
#include "sound.h"
#include "dualshock.h"
#include "gametext.h"
//#include "spotlite.h"

// CPW: #include <islpoly.h>

#define MAP_SCALE_DEPTH_DOWN 3
// ==== JS : This is in PSX_PC.h now; included via global.h
/*#define gte_stotz_cpu(r)\
asm(\
  "mfc2 %0, $7;"\
  :\
  : "r" (r)\
)*/

#define MRT_BUZZ()	{dsEvent_Add(1, 1, 1, 200, 0, 20, FALSE);}


#include "charactr.h"

//extern TextureType	*buble;
extern TextureType	*gravy;

enum
{
	ANIM_MRST_WALK,
	ANIM_MRST_STOP,
	ANIM_MRST_PONDER,
	ANIM_MRST_SEARCH,
	ANIM_MRST_SCOWL,
	ANIM_MRST_LOOKRIGHT,
	ANIM_MRST_LOOKLEFT,
};


enum
{
/*
	ANIM_MRT_WALK,
	ANIM_MRT_SEARCH,
	ANIM_MRT_CASLOOK,
	ANIM_MRT_QUICKLOOK,
	ANIM_MRT_TOOLS,
*/
	ANIM_MRT_WALK,
	ANIM_MRT_SEARCH,
	ANIM_MRT_CASLOOK,
	ANIM_MRT_PERSUIT,
	ANIM_MRT_FLINCH,
	ANIM_MRT_HEADSHAKE,
	ANIM_MRT_KILLING,
	ANIM_MRT_TOOLS,
};

//#define ANIM_MRT_SCOWL ANIM_MRT_SEARCH


void enemyMrsTInitPatrol(ENEMY *pE)
{
	pE->readData.pHead = psiObjectScan(pE->readData.pActor->psiData.object, "MRST_HEAD");
	pE->view_range_current = pE->view_range_rqd = MRST_SIGHT_RANGE;
	pE->view_fov_current = pE->view_fov_rqd = MRST_SIGHT_FOV;
}


void enemyMrsTweedyStartPersuit(ENEMY *pE)
{
	SETSTATE(STATE_GROWLING);	// !
}


void enemyMrsTweedyCollide(ENEMY *pE,void *pWith, int withtype)
{
	switch(withtype)
	{
	case COLLIDE_WITH_MAINCHAR:
// What if you collide with him and you're in a welly?
// (ie, should he turn round amd be confused when he can't see anything if you've managed to hide?)
		if(pE->state != STATE_GROWLING)
		{
				SETSTATE(STATE_GROWLING);
		}
		break;

	case COLLIDE_WITH_SPROUT:
		break;
	}

}


int MrsTweedyCanSeeCheck(ENEMY *pE)
{
	VECTOR v1;
	VECTOR v2;
	COLLBOX hitBox;
	int rv;

	if(!characterVars.pMainChar)
		return 0;
	if(enemyCanSeeCheckWellyTest(pE, &characterVars.pMainChar->pEnemy->pos, MRST_SIGHT_FOV,MRST_SIGHT_RANGE) >= MRST_SIGHT_RANGE)
		return 0;

	v1 = characterVars.pMainChar->pEnemy->pos;
	v2 = pE->pos;

	v1.vy -= 400;	// Ginger's head
	v2.vy -= 750;	// Mrs Tweedy's head

	v1.vx = v1.vx <<9;
	v1.vy = v1.vy <<9;
	v1.vz = v1.vz <<9;

	v2.vx = v2.vx <<9;
	v2.vy = v2.vy <<9;
	v2.vz = v2.vz <<9;

	rv = collideBoxIsectCheck(&v1,&v2);

	if(rv)
		return 0;

	return 1;

}


void MrTweedyCanSeeChicken(ENEMY *pE,VECTOR *position)
{
	hourglass2Inform(HOURGLASS_IN_MRT_FOV,position);
	enemiesInformAboutPosition(position);
}

int MrTweedyCanSeeCheck(ENEMY *pE, CHARACTER *pC)
{
	VECTOR v1;
	VECTOR v2;
	COLLBOX hitBox;
	int rv;

	if(!pC)
		return 0;
	if(!(pC->pEnemy->runFlags & RUNFLAGS_VISIBLE))
		return 0;
	if(enemyCanSeeCheckWellyTest(pE, &pC->pEnemy->pos, pE->view_fov_current,pE->view_range_current) >= pE->view_range_current)
		return 0;

	v1 = pC->pEnemy->pos;
	v2 = pE->pos;

	v1.vy -= 400;	// Ginger's head
	v2.vy -= 700;	// Mr Tweedy's head

	v1.vx = v1.vx <<9;
	v1.vy = v1.vy <<9;
	v1.vz = v1.vz <<9;

	v2.vx = v2.vx <<9;
	v2.vy = v2.vy <<9;
	v2.vz = v2.vz <<9;

	rv = collideBoxIsectCheck(&v1,&v2);

	if(rv)
		return 0;


	return 1;
}

int enemyUpdateMrsTweedy(ENEMY *pE)
{
	ENEMY *ptr;
	int d;


	ASSERT(pE);

// Mrs T's head ain't called "head", by the looks of things. She ain't got eyes, either.
//	enemyLookAtPos(pE, &characterVars.pMainChar->pEnemy->pos);


	switch(pE->state)
	{
	case STATE_NULL:
		pE->points.pointGoingTo = pE->readData.pPoints[pE->points.pointTo].v;	// from & to are initialised to 0 & 1 in the bff linker
			actorAnimate(pE->readData.pActor, ANIM_MRST_WALK, 1, 0, 256, 0, 0);
			SETSTATE(STATE_WANDERING);

			enemySteerTowards(pE, &pE->points.pointGoingTo, 2046);

			break;


// A tweedy persuit is fairly minimal, and amounts to facing the chicken, & glaring at it.
	case STATE_PERSUIT:
	case STATE_GROWLING:
		pE->vel.vx = 0;
		pE->vel.vz = 0;

		if(pE->stateCtr==0 && !enemyEndingLevelFlag && !deathDying)
		{
			actorAnimate(pE->readData.pActor, ANIM_MRST_SCOWL, 0, 0, pE->animSpeed, 0, 512);	// don't loop or queue. Blend

			// Make sure she doesn't mutter to herself whilst simultaneously saying "chickens"
			// (as can so very easily happen)
			soundStopSample(pE->readData.ppSamples[ENEMY_SFX_MRSTMINISCULE]);

			if(gameTextLang == LANG_UK)
			{
				soundPlaySpeech(pE->readData.ppSamples[ENEMY_SFX_MRSTCHICKENS + utilRandomInt(1)], 0);
			}
//			soundPlaySamplePanFade(pE->readData.ppSamples[ENEMY_SFX_MRSTCHICKENS + utilRandomInt(1)], 255, 0, (VECTOR *)&(pE->pos));
			deathKill(characterVars.pMainChar, DEATH_REASON_MRST_LOOM, pE);

		}
		pE->desiredDir = enemyFindAbsAngleTo(pE,&characterVars.pMainChar->pEnemy->pos);

		pE->dir = enemyTendTowards(pE->desiredDir, pE->dir, 32);

// But for now, we'll reset Mrs T.
		if(pE->stateCtr >= 100 && !deathDying)	// Don't stop growling while the death sequence is going on)
		{
			actorAnimate(pE->readData.pActor, ANIM_MRST_WALK, 1, 0, 256, 0, 512);
			pE->runFlags&=(~RUNFLAGS_FORCETOFRONT);	// set it so it's not part of the death sequence any more
			SETSTATE(STATE_WANDERING);
		}


		break;


	case STATE_WANDERING:

		if(pE->points.timer)
			pE->points.timer = 0;	// used as a "enemy just at point" flag

		if(actorReachedFrameRatio(pE->readData.pActor, -1, 1024) == ACTORFRAME_AT)
		{
			enemyPlayEnvironmentFootstepNoDogCheck((VECTOR *)&(pE->pos), 64);
		}
		if(actorReachedFrameRatio(pE->readData.pActor, -1, 3072) == ACTORFRAME_AT)
		{
			enemyPlayEnvironmentFootstepNoDogCheck((VECTOR *)&(pE->pos), 64);
		}

		if(MrsTweedyCanSeeCheck(pE))
		{
			enemyMrsTweedyStartPersuit(pE);
		}

		if(levinfo->level_number == LEVNUMBER_A1_HOUSEXT_N)
		{
			d = 30;
			pE->points.turnspeed_thiscorner = 100;
			pE->turning = 11;	// she's got 1024 of corner to get round (So turn nice & fast)
		}
		else
		{
			if(pE->readData.pPoints[pE->points.pointTo].pause)
			{
				d = 200;	// coz she's got to stop walking
			}
			else
			{
				d = 400;
			}
			pE->points.turnspeed_thiscorner = 40;	//32;
			pE->turning = 26;

		}

		if(enemyArrivedCheck(&pE->points.pointComingFrom, &pE->pos, &pE->points.pointGoingTo, d))
		{
			enemyBeginTrekToNextPoint(pE);
			if(pE->readData.pPoints[pE->points.pointFrom].pause)
			{
				pE->points.timer = pE->readData.pPoints[pE->points.pointFrom].pause;
				SETSTATE(STATE_WAITING);
			}
			else
			{
				pE->points.timer = 1;
			}
		}
		else
		{
			if(pE->turning)
			{
				enemySteerTowards(pE, &pE->points.pointGoingTo, pE->points.turnspeed_thiscorner);
				pE->turning--;
			}
			else
			{
				enemySteerTowards(pE, &pE->points.pointGoingTo, 32);	// do the steering on a permanant basis
			}

		}


		enemyMove(pE, MRST_FORWARD_SPEED, ENEMYMOVE_SET, 0);	// Updates (pE->pos.vx and vz). enemy, desiredspeed, action (set,tendto), accel
		break;


	case STATE_WAITING:
//		pE->knows_youre_in_welly = 0;
		if(MrsTweedyCanSeeCheck(pE))
		{
			enemyMrsTweedyStartPersuit(pE);
			break;
		}

		if(pE->stateCtr==0)
		{
			actorAnimate(pE->readData.pActor, ANIM_MRST_STOP, 0, 1, pE->animSpeed, 0, 512);


			if(gameTextLang == LANG_UK)
			{
				soundPlaySamplePanFade(pE->readData.ppSamples[ENEMY_SFX_MRSTMINISCULE], 255, 0, (VECTOR *)&(pE->pos));
			}



			if(pE->points.timer > 100 && !pE->readData.pPoints[pE->points.pointFrom].lookAtTag)
			{
				actorAnimate(pE->readData.pActor, ANIM_MRST_SEARCH, 0, 1, pE->animSpeed, 0, 512);
				actorAnimate(pE->readData.pActor, ANIM_MRST_PONDER, 1, 1, pE->animSpeed, 0, 0);
			}
			else
			{
				actorAnimate(pE->readData.pActor, ANIM_MRST_PONDER, 1, 1, pE->animSpeed, 0, 512);	// Blend in.
			}
		}

		if(pE->readData.pActor->animation.animData[0].segment == ANIM_MRST_STOP
			|| pE->readData.pActor->animation.animData[0].segment == ANIM_MRST_WALK
			)
		{
			// Keep moving while the walk anim's playing
			enemyMove(pE, MRST_FORWARD_SPEED, ENEMYMOVE_SET, 0);
		}
		else
		{
			pE->vel.vx = 0;
			pE->vel.vz = 0;
		}

		if(pE->points.timer>0)
		{
			// If we've got something that needs looking at, we'd better look at it.
			if(pE->readData.pPoints[pE->points.pointFrom].lookAtTag)
			{
				POSMARK *pMarker;
				pMarker = levinfoFindMarker(pE->readData.pPoints[pE->points.pointFrom].lookAtTag);
				if(pMarker)
				{
					enemyLookAtPos(pE, (VECTOR *)&pMarker->x);
				}
			}
			else
			{
				enemyLookAtPos(pE, NULL);
			}
			pE->points.timer--;
		}
		if(!pE->points.timer)
		{
//			utilPrintf("Return to Wander\n");
			SETSTATE(STATE_WANDERING);
			actorAnimate(pE->readData.pActor, ANIM_MRST_WALK, 1, 0, 256, 0, 512);	// blend the arms back
//			enemyBeginTrekToNextPoint(pE);	// moved to before starting the waiting
		}
		break;
	}

	return 0;
}

// =========================================================================================================================
// We may as well include Mr T in here too...
// Mr T is a pretty unresponsive kinda chap. Basically what he does is to call in a persuit dog if you're caught in
// his torch of doom.

// Then there's a patrolling Mr T, much the same as Mrs.

// And finally, there's the pie machine Mr T, who needs to go between two points in varying degrees of panic
// according to the actions of the rats

void enemyMrTInitPatrol(ENEMY *pE)
{
	MRT_TORCH_STR *ext;

	ext = MALLOC(sizeof(MRT_TORCH_STR));
	FMEMZERO(ext,sizeof(MRT_TORCH_STR));
	pE->extras = ext;

	pE->view_range_current = pE->view_range_rqd = MRT_SIGHT_RANGE;
	pE->view_fov_current = pE->view_fov_rqd = MRT_SIGHT_FOV;
// The range correction for the piebarn will have to be left a while
// (coz the levinfo won't have been read yet)
}

void enemyMrTInitTorch(ENEMY *pE)
{
	MRT_TORCH_STR *ext;

//	ext = MALLOC(sizeof(MRT_TORCH_STR));
//	FMEMZERO(ext,sizeof(MRT_TORCH_STR));
//	pE->extras = ext;
	enemyMrTInitPatrol(pE);

	ext = (MRT_TORCH_STR *)pE->extras;

	ext->torchlight = EXLIGHT_AddLight();
	ext->torchlight->range = 8000;
	ext->torchlight->flags |= LIGHTFLAG_CONE + LIGHTFLAG_ALERT;


	pE->view_range_current = pE->view_range_rqd = MRT_DARK_SIGHT_RANGE;
	pE->view_fov_current = pE->view_fov_rqd = MRT_DARK_SIGHT_FOV;

// Make sure it's got an initial position (otherwise you get caught straight away)
	ext->torchlight->pos.x = pE->pos.vx;
	ext->torchlight->pos.y = pE->pos.vy-500;
	ext->torchlight->pos.z = pE->pos.vz;
	ext->torchlight->boxsize.x = pE->pos.vx;
	ext->torchlight->boxsize.y = pE->pos.vy;
	ext->torchlight->boxsize.z = pE->pos.vz;

}

// Lights are no longer automatically released at EXLIGHT_Shutdown
// (because they can be sourced from BFF)
void enemyMrTReleaseTorch(ENEMY *pE)
{
	MRT_TORCH_STR *ext;
	ext = pE->extras;

	if(ext->torchlight)
	{
		EXLIGHT_RemoveLight(ext->torchlight);
		FREE(ext->torchlight);
		ext->torchlight = NULL;
	}
	FREE(ext);
}

// Prevent Mr T from permanantly running himself into a welly, and then getting confused
int enemyMrTweedyCheckWellyCollide(ENEMY *pE)
{
	MRT_TORCH_STR *ext;
	ext = (void *)pE->extras;
	if(characterVars.pHideChar)
	{
		if(pE->knows_youre_in_welly || !(characterVars.pHideChar->pEnemy->runFlags & RUNFLAGS_VISIBLE))
		{
			pE->welly_contact_timer = 0;
			return 0;
		}
	}
	if(pE->welly_contact_timer)
	{
		pE->welly_contact_timer--;
		return 0;
	}
	pE->welly_contact_timer = 40;
	return 1;
}

void enemyMrTweedyPatrolCollide(ENEMY *pE,void *pWith, int withtype)
{
	MRT_TORCH_STR *ext;
	ext = (void *)pE->extras;

//	enemyDogFindAndAlert(&pE->pos);
	if(levinfo->level_number == LEVNUMBER_A4_PIEBARN)
	{
		DB("Mr T Patrol Collide Hourglass Trigger\n");
//		nmeDogStartHourglass(2);
		hourglass2Inform(HOURGLASS_MRT_COLLIDE,NULL);

	}
	else
	{
		switch(withtype)
		{
		case COLLIDE_WITH_MAINCHAR:

			switch(pE->state)
			{
			case STATE_WANDERING:
			case STATE_WAITING:
			case STATE_THINKING:
				if(enemyMrTweedyCheckWellyCollide(pE))
				{
					enemyMrTStartPersuit(pE, &((ENEMY *)pWith)->pos, 1);
				}
				break;
			case STATE_PREABANDON:
				break;
			case STATE_ABANDONING:
				if(pE->stateCtr > 100)
				{
					if(enemyMrTweedyCheckWellyCollide(pE))
					{
						enemyMrTStartPersuit(pE, &((ENEMY *)pWith)->pos, 1);
					}
				}
				break;
			default:
				ext->alertpoint = ((ENEMY *)pWith)->pos;
				break;

			}
			break;

		case COLLIDE_WITH_SPROUT:
			switch(pE->state)
			{
			case STATE_WANDERING:
			case STATE_WAITING:
			case STATE_ABANDONING:
			case STATE_THINKING:
	//			enemyDogStartAlert(pE, &characterVars.pMainChar->pEnemy->pos,1);
				enemyMrTStartPersuit(pE,&characterVars.pMainChar->pEnemy->pos, 1);

				actorAnimate(pE->readData.pActor, ANIM_MRT_FLINCH,  1, 0, 256, 0, 2048);
				actorAnimate(pE->readData.pActor, ANIM_MRT_PERSUIT, 1, 1, 256, 0, 0);

				break;

			case STATE_PERSUIT:
				ext->alertpoint = characterVars.pMainChar->pEnemy->pos;
	//			SETSTATE(STATE_STUNNED);
				break;
			}
			break;
		}
	}
}







#define TORCH_OFFSET_X 300

void enemyMrTweedyDrawTorch(ENEMY *pE)
{
//	static int ya;
//	int ya2;
	MRT_TORCH_STR *ext;
	int range;
	int f;
	ANIMATION *pSeg;
	int st,en;

	ext = (void *)pE->extras;

/*
	if(levinfo->level_number == LEVNUMBER_A4_PIEBARN)	// Until I can get hold of enemies.c again, there's only one type of Mr T
	{
		if(ext->torchlight)
		{
			EXLIGHT_RemoveLight(ext->torchlight);
			FREE(ext->torchlight);
			ext->torchlight = NULL;
		}
		return;
	}
*/

//	DB("torch flags = %d\n",ext->torchlight->flags);

	ext->torch_counter = (ext->torch_counter + 0x10) & 4095;

	ext->torch_ya = (((rsin(ext->torch_counter) * 512) >> 12) + 2048 + pE->dir) & 4095;

	f = pE->readData.pActor->animation.animData[0].actualFrame;

//actor->animation.pSegments[
//pSegments[i].animStart
//pSegments[i].animEnd -


//	pSeg	 = pE->readData.pActor->animation.pSegments;
	pSeg	 = (ANIMATION *)(((PSIMODEL *)(
		pE->readData.pActor->psiData.modelName
		))->animSegmentList);	// yuk!
	range = MRT_TORCH_DISTANCE;


	if(f >= pSeg[ANIM_MRT_SEARCH].animStart && f <= pSeg[ANIM_MRT_SEARCH].animEnd)	// search - wide out
	{
		st = pSeg[ANIM_MRT_SEARCH].animStart;
		en = pSeg[ANIM_MRT_SEARCH].animEnd;
		ext->torch_counter = (f - st) * 4096 / (en-st);
		ext->torch_ya = (((rsin(ext->torch_counter) * 256) >> 12) + 2048 + pE->dir) & 4095;
		range = 3000;
	}
	else if(f >= pSeg[ANIM_MRT_WALK].animStart && f <= pSeg[ANIM_MRT_WALK].animEnd)
	{
		st = pSeg[ANIM_MRT_WALK].animStart;
		en = pSeg[ANIM_MRT_WALK].animEnd;
		ext->torch_counter = (f - st) * 4096 / (en-st);
		ext->torch_ya = (((rsin(ext->torch_counter) * 480) >> 12) + 2200 + pE->dir) & 4095;
		range = 1600 - ((rsin(ext->torch_counter) * 600) >> 12);
	}
/*	else if(f >= pSeg[ANIM_MRT_QUICKLOOK].animStart && f <= pSeg[ANIM_MRT_QUICKLOOK].animEnd)
	{
		st = pSeg[ANIM_MRT_QUICKLOOK].animStart;
		en = pSeg[ANIM_MRT_QUICKLOOK].animEnd;
		ext->torch_counter = (f - st) * 4096 / (en-st);
		ext->torch_ya = (((rsin(ext->torch_counter) * 256) >> 12) + 2048 + pE->dir) & 4095;
		range = 1500;
	} */ 
	else if(f >= pSeg[ANIM_MRT_CASLOOK].animStart && f <=  pSeg[ANIM_MRT_CASLOOK].animEnd)	// cas-search - pretty close in
	{
		int mid;
		st = pSeg[ANIM_MRT_CASLOOK].animStart;
		en = pSeg[ANIM_MRT_CASLOOK].animEnd;
		mid = st + (en - st) * 110 /158;
		// 120...278 || 230     158 total, split at 110. 110/158ths then
		if(f >= mid)
			ext->torch_counter = 4096;
		else
			ext->torch_counter = (f - st) * 4096 / (mid-st);
		ext->torch_ya = (((rsin(ext->torch_counter) * 256) >> 12) + 2500 + pE->dir) & 4095;

		range = 1000;
	}
	else if(f >= pSeg[ANIM_MRT_PERSUIT].animStart && f <= pSeg[ANIM_MRT_PERSUIT].animEnd)
	{
		st = pSeg[ANIM_MRT_PERSUIT].animStart;
		en = pSeg[ANIM_MRT_PERSUIT].animEnd;
		ext->torch_counter = (f - st) * 4096 / (en-st);
		ext->torch_counter = (ext->torch_counter-300) & 4095;
		ext->torch_ya = (((rsin(ext->torch_counter) * 240) >> 12) + 2200 + pE->dir) & 4095;
		range = 1700 - ((rsin(ext->torch_counter) * 50) >> 12);
	}


	ext->torchlight->pos.x = pE->pos.vx         - ((TORCH_OFFSET_X * rcos(pE->dir)) >> 12);
	ext->torchlight->pos.y = pE->pos.vy - 500;
	ext->torchlight->pos.z = pE->pos.vz         + ((TORCH_OFFSET_X * rsin(pE->dir)) >> 12);


	ext->torchlight->boxsize.x = (ext->torchlight->pos.x + ((range * rsin(ext->torch_ya)) >> 12));
	ext->torchlight->boxsize.y = 0;
	ext->torchlight->boxsize.z = (ext->torchlight->pos.z + ((range * rcos(ext->torch_ya)) >> 12));
	ext->torchlight->range = 8000;
	ext->torchlight->shadow_darkness = 128;	// this shadow's an extreme one

//	spotliteDraw((VECTOR *)&ext->torchlight->boxsize, 500,800,  *(unsigned int *)&ext->torchlight->col, ext->torch_ya);

}


// Act 4. Mr Tweedy and the leaky gravy machine
// When you press a single button, the leak stream finishes some time before you're allowed to press the button again
#define BUTTON1_INTERVAL	100
#define BUTTON2_INTERVAL	100

#define BUTTON1_LEAKTIME	70
#define BUTTON2_LEAKTIME	70

#define VAR_BUTTON1_COUNTDOWN	1
#define VAR_BUTTON2_COUNTDOWN	2

#define VAR_BUTTON1_LEAKTIME	3
#define VAR_BUTTON2_LEAKTIME	4

#define VAR_TOTAL_LEAKTIME	5

int leak_target_point = 1;

void updateGravyLeak(ENEMY *pE)
{
	CHARACTER *pC;
	if(PuzzleVars.variables[VAR_BUTTON1_COUNTDOWN])
	{
		PuzzleVars.variables[VAR_BUTTON1_COUNTDOWN]--;
	}
	if(PuzzleVars.variables[VAR_BUTTON2_COUNTDOWN])
	{
		PuzzleVars.variables[VAR_BUTTON2_COUNTDOWN]--;
	}

	if(PuzzleVars.variables[VAR_BUTTON1_LEAKTIME])
	{
		leak_target_point = 1;
		if(PuzzleVars.variables[VAR_TOTAL_LEAKTIME])
			leak_target_point = 2;
		PuzzleVars.variables[VAR_TOTAL_LEAKTIME] += PuzzleVars.variables[VAR_BUTTON1_LEAKTIME];
		PuzzleVars.variables[VAR_BUTTON1_LEAKTIME] = 0;

	}
	if(PuzzleVars.variables[VAR_BUTTON2_LEAKTIME])
	{
		leak_target_point = 1;
		if(PuzzleVars.variables[VAR_TOTAL_LEAKTIME])
			leak_target_point = 2;
		PuzzleVars.variables[VAR_TOTAL_LEAKTIME] += PuzzleVars.variables[VAR_BUTTON2_LEAKTIME];
		PuzzleVars.variables[VAR_BUTTON2_LEAKTIME] = 0;
	}

	if(PuzzleVars.variables[VAR_TOTAL_LEAKTIME])
	{
		DEBRISSTR *deb;
		VECTOR pos = {360<<3,-127<<3,-50<<3};

//		overlayShowSphere(pos.vx,pos.vy,pos.vz, 80, 0xffffff);

		if(utilRandomInt(256) < 200)
		{
			//deb = debrisNew( &pos, buble, 100);
			deb = debrisNew( &pos, gravy, 100);
			if(deb)
			{

	//			deb->size=(deb->size*vent->scale)>>4;

				deb->size = 256 + utilRandomInt(256);
				deb->dy=0;
				deb->dx=-12 + utilRandomInt(24);
				deb->dz=-12 + utilRandomInt(24);
				deb->colour=0x60001C40;

				deb->gravity=5;

				deb->flags.whole=DEB_MOVING;

				deb->type = DEBRIS_GRAVY;
				deb->fade_start = 0; // gravy does not fade
				deb->special.gravy.height = 0;	// y for splash
			}
		}

		PuzzleVars.variables[VAR_TOTAL_LEAKTIME]--;
	}

// Mr T should be able to trigger on seeing EITHER rat...

	pE->view_range_current = pE->view_range_rqd = MRT_PIEBARN_SIGHT_RANGE;
	pE->view_fov_current = pE->view_fov_rqd = MRT_PIEBARN_SIGHT_FOV;

	for(pC=characterList.head.next; pC != &characterList.head; pC = pC->next)
	{
		if(pC->pEnemy->runFlags & RUNFLAGS_VISIBLE)
		{
			if(!deathDying && !enemyEndingLevelFlag && pE->state != STATE_GROWLING)
			{
				if(MrTweedyCanSeeCheck(pE, pC))
				{
					SETSTATE(STATE_GROWLING);

	//				soundPlaySamplePanFade(pE->readData.ppSamples[ENEMY_SFX_MRTTHIEVEBUGGRS], 255, 0, (VECTOR *)&(pE->pos));
	//				deathKill(pC,DEATH_REASON_MRT_SEEN,pE);
				}
				else if( (pC->pEnemy->pos.vz > -1750) && ((pE->pos.vx - pC->pEnemy->pos.vx) < 800))
				{
					// (Kill the rats if they jump past Mr T in the piebarn. Nasty, but functional. It might be worth waiting till you're on the ground.
					SETSTATE(STATE_GROWLING);
				}
			}
		}
	}

#ifdef DEBUG
	{
		char temp[100];
		sprintf(temp,"B1 %d, B2 %d. Leak %d\n",
			PuzzleVars.variables[VAR_BUTTON1_COUNTDOWN],
			PuzzleVars.variables[VAR_BUTTON2_COUNTDOWN],
			PuzzleVars.variables[VAR_TOTAL_LEAKTIME]);
#if PALMODE==0
		fontPrint(font, -200,-100, temp, 128,128,64);
#else
		fontPrint(font, -200,-120, temp, 128,128,64);
#endif

	}
#endif
}








void enemyMrTStartPersuit(ENEMY *pE,VECTOR *position, int buzzer)
{
	MRT_TORCH_STR *ext;
	ext = (void *)pE->extras;


	if(pE->state == STATE_PERSUIT || pE->state == STATE_GROWLING )
	{
//		DB("Mr T persuit refresh\n");
		ext->alertpoint = *position;
		return;
	}

	if((!triggering_light) || (pE->triggering_light != triggering_light))
	{
		DB("mrT persuit start (state = %d)\n",pE->state);
		pE->turning = 0;	// kill off any previous turn

		ext->alertpoint = *position;
		dogInitRoute(pE,&ext->alertpoint,1);	// Make sure its got something to start with

		pE->view_range_rqd = MRT_EXTRA_SIGHT_RANGE;
		pE->view_fov_rqd = MRT_EXTRA_SIGHT_FOV;
		if(buzzer)
		{
			MRT_BUZZ();
		}
	//	dogInitRoute(pE,&ext->alertpoint,1);

		SETSTATE(STATE_PERSUIT);
	}
}


void MrTBeginTrekToNextPoint(ENEMY *pE)
{
	int d;
	int a;

	MRT_TORCH_STR *ext;
	ext = (void *)pE->extras;


//	ext->corner_angle = enemyAngleCalc(pE,pE->points.pointTo);

//	pat->corner_time = pE->turning = 26;	// number of frames the turn anim takes
//	pE->points.turnspeed_thiscorner = (ABS(pat->corner_angle)) * 60 / 1024;
	pE->points.turnspeed_thiscorner = 60;


	if(pE->state != STATE_WANDERING)
	{
		DB("reverting to wandering\n");
//		actorAnimate(pE->readData.pActor, DOG_WALK, 1, 0, 256, 0, 512);	// yes loop, no queue. Blend in.
		SETSTATE(STATE_WANDERING);
	}

//		DB("angle at corner = %d. Turnspeed = %d\n",a,pE->points.turnspeed_thiscorner);
}


// Starting from wherever the dog happens to be, go to the given patrol point
void enemyMrTStartPatrolling(ENEMY *pE, int first_point)
{
	DB("Start Patrolling\n");
	if(pE->readData.pDef->nPoints < 2)
	{
// Persuit dog. The "Patrolling" state is actually "disabled".
		pE->runFlags &= ~RUNFLAGS_VISIBLE;
		SETSTATE(STATE_TURNEDOFF);
	}
	else
	{
// Make-believe we just arrived at the previous point,
// then start the trek to the next one
		pE->points.pointTo = (first_point + pE->readData.pDef->nPoints - 1) % pE->readData.pDef->nPoints;
		MrTBeginTrekToNextPoint(pE);
	}
}



int enemyUpdateMrTweedyPatrol(ENEMY *pE)
{
	int d;
	MRT_TORCH_STR *ext;
	int persuit_steer_speed;
	ext = (void *)pE->extras;

//	DB("Mr T state %d\n",pE->state);
/*
	{
		int d;
		d = pE->pos.vy - characterVars.pMainChar->pEnemy->pos.vy;
		DB("d = %d\n",d);
	}
*/

/*
// Finding the constants for the pie machine death
	{
		char temp[80];
		sprintf(temp,"%8d (%d)\n"
			,characterVars.pMainChar->pEnemy->pos.vz
			,(pE->pos.vx - characterVars.pMainChar->pEnemy->pos.vx)
			);
		fontPrint(font,-200,100,temp,128,128,64);
	}
*/



	if(overlay_show_collision == DEBUG_OVERLAY_ENEMY_INFO || overlay_show_collision == DEBUG_OVERLAY_ROUTE_FIND)
	{
		if(pE->state == STATE_PERSUIT || pE->state == STATE_ABANDONING)
			routeShowRoute(&pE->pos, &pE->route[0], pE->route_len);
	}

//	DB("Mr T state = %d\n",pE->state);

	if(!triggering_light)
		pE->triggering_light = NULL;

	if(pE->readData.pInfo->nme_type == ENEMY_MRT_TORCH)
	{
		*(unsigned long *)&ext->torchlight->col
			=*(unsigned long *)&ext->torchlight->basecol1
			=*(unsigned long *)&ext->torchlight->basecol2
			= 0x20ffff + (utilRandomInt(64) << 16);

		if(pE->runFlags & RUNFLAGS_NOTLOOKING)
			ext->torchlight->flags  &= ~LIGHTFLAG_ALERT;
		else
			ext->torchlight->flags  |= LIGHTFLAG_ALERT;

	}

	if(levinfo->level_number == LEVNUMBER_A4_PIEBARN)
	{
		updateGravyLeak(pE);
	}

// If he's a non-torch tweedy, then he can just SEE chickens by the power of eyesight alone
// Amended. He can now see chickens in the dark
//	if((levinfo->level_number != LEVNUMBER_A4_PIEBARN) && (pE->readData.pInfo->nme_type != ENEMY_MRT_TORCH))
	if((levinfo->level_number != LEVNUMBER_A4_PIEBARN))
	{
		if(pE->state != STATE_PERSUIT && pE->state != STATE_GROWLING)
		{
			if(MrTweedyCanSeeCheck(pE,characterVars.pMainChar))
			{
				DB("Mr T Sight Hourglass Trigger\n");
	//			nmeDogStartHourglass(2);
	// ohboy did that die in a big way
				MrTweedyCanSeeChicken(pE,&characterVars.pMainChar->pEnemy->pos);
				enemyMrTStartPersuit(pE,&characterVars.pMainChar->pEnemy->pos, 1);
			}
		}
	}

	switch(pE->state)
	{
	case STATE_NULL:

		if(pE->readData.pDef->nPoints > 1)
		{
			if(levinfo->level_number == LEVNUMBER_A4_PIEBARN)	// Coming from point 1 to point 0
			{
				pE->points.pointFrom = 1;
				pE->points.pointTo = 0;
				pE->pos.vx = pE->readData.pPoints[pE->points.pointFrom].v.vx;
				pE->pos.vy = pE->readData.pPoints[pE->points.pointFrom].v.vy - 1000;
				pE->pos.vz = pE->readData.pPoints[pE->points.pointFrom].v.vz;
			}
			pE->points.pointComingFrom = pE->pos;
			pE->points.pointGoingTo = pE->readData.pPoints[pE->points.pointTo].v;	// from & to are initialised to 0 & 1 in the bff linker
			actorAnimate(pE->readData.pActor, ANIM_MRT_WALK, 1, 0, 256, 0, 0);
			SETSTATE(STATE_WANDERING);
		}
		else
		{
//			actorAnimate(pE->readData.pActor, ANIM_MRT_SEARCH, 1, 0, pE->animSpeed, 0, 512);
			actorAnimate(pE->readData.pActor, ANIM_MRT_CASLOOK, 1, 0, pE->animSpeed, 0, 512);
			SETSTATE(STATE_TURNEDOFF);
		}
		break;


	case STATE_TURNEDOFF:
// stationary, dull, boring Mr Tweedy
// (ie, a mr tweedy with 0 or 1 movement points just stands there & waves his torch around)
		break;


	case STATE_WANDERING:
		if(pE->points.timer)
			pE->points.timer = 0;	// used as a "enemy just at point" flag

		if(pE->readData.pPoints[pE->points.pointTo].pause)
		{
			d = 200;	// coz he's got to stop walking
		}
		else
		{
			d = 400;
		}


		if(levinfo->level_number == LEVNUMBER_A4_PIEBARN)
		{
			// If we're heading to point 1, and a rat presses the other button, extend our walk to point 2
			if(pE->points.pointTo == 1 && leak_target_point == 2)
			{
				enemyBeginTrekToSpecificPoint(pE, 2);
			}
		}


		if(enemyArrivedCheck(&pE->points.pointComingFrom, &pE->pos, &pE->points.pointGoingTo, d))
		{
			enemyBeginTrekToNextPoint(pE);

			if(levinfo->level_number == LEVNUMBER_A4_PIEBARN)	// Coming from point 1 to point 0
			{
				pE->points.timer = -1;
				SETSTATE(STATE_WAITING);
			}
			else if(pE->readData.pPoints[pE->points.pointFrom].pause)
			{
				pE->points.timer = pE->readData.pPoints[pE->points.pointFrom].pause;
				SETSTATE(STATE_WAITING);
			}
			else
			{
				pE->points.timer = 1;
			}
			pE->points.turnspeed_thiscorner = 32;
			pE->turning = 26;
		}
		else
		{
			if(pE->turning)
			{
				enemySteerTowards(pE, &pE->points.pointGoingTo, pE->points.turnspeed_thiscorner);
				pE->turning--;
			}
			else
			{
				enemySteerTowards(pE, &pE->points.pointGoingTo, 32);	// do the steering on a permanant basis
			}

		}
		enemyMove(pE, MRT_FORWARD_SPEED, ENEMYMOVE_SET, 0);	// Updates (pE->pos.vx and vz). enemy, desiredspeed, action (set,tendto), accel
		break;


	case STATE_WAITING:
		if(levinfo->level_number == LEVNUMBER_A4_PIEBARN)
		{
			pE->points.timer = -1;	// He waits at both ends for indeterminate amounts of time
		}

		if(pE->stateCtr==0)
		{
			if(levinfo->level_number == LEVNUMBER_A4_PIEBARN)
			{
//				actorAnimate(pE->readData.pActor, ANIM_MRT_HEADSHAKE, 1, 0, pE->animSpeed, 0, 512);
//				actorAnimate(pE->readData.pActor, ANIM_MRT_TOOLS, 1, 0, pE->animSpeed, 0, 512);
//				actorAnimate(pE->readData.pActor, ANIM_MRT_CASLOOK, 1, 1, pE->animSpeed, 0, 0);
				// Leave the animating till we're facing the right way
			}
			else
			{

				if(pE->points.timer > 100 && !pE->readData.pPoints[pE->points.pointFrom].lookAtTag)
				{
					actorAnimate(pE->readData.pActor, ANIM_MRT_CASLOOK, 1, 0, pE->animSpeed, 0, 512);
				}
				else
				{
//					actorAnimate(pE->readData.pActor, ANIM_MRT_QUICKLOOK, 1, 0, pE->animSpeed, 0, 512);	// Blend in.
					actorAnimate(pE->readData.pActor, ANIM_MRT_SEARCH, 1, 0, pE->animSpeed, 0, 512);	// Blend in.
				}
			}
		}

		{
			pE->vel.vx = 0;
			pE->vel.vz = 0;
		}

		if(pE->points.timer>0)
		{
			// If we've got something that needs looking at, we'd better look at it.
			if(pE->readData.pPoints[pE->points.pointFrom].lookAtTag)
			{
				POSMARK *pMarker;
				pMarker = levinfoFindMarker(pE->readData.pPoints[pE->points.pointFrom].lookAtTag);
				if(pMarker)
				{
					enemyLookAtPos(pE, (VECTOR *)&pMarker->x);
				}
			}
			else
			{
				enemyLookAtPos(pE, NULL);
			}
			pE->points.timer--;
		}

		if(levinfo->level_number == LEVNUMBER_A4_PIEBARN)
		{
//			DB("pE->dir = %d. QS = %d\n",pE->dir,pE->readData.pActor->animation.queueSize);

			if(pE->dir == 2048)
			{
				if(pE->stateCtr==0)
				{
					actorAnimate(pE->readData.pActor, ANIM_MRT_HEADSHAKE, 1, 1, pE->animSpeed, 0, 512);
				}
				else if(pE->readData.pActor->animation.queueSize < 2)
				{
					int a;
					a = utilRandomInt(2);
					switch(a)
					{
					case 0:
						actorAnimate(pE->readData.pActor, ANIM_MRT_HEADSHAKE, 1, 1, pE->animSpeed, 0, 512);
						break;
					case 1:
						actorAnimate(pE->readData.pActor, ANIM_MRT_CASLOOK, 1, 1, pE->animSpeed, 0, 512);
						break;
					case 2:
						actorAnimate(pE->readData.pActor, ANIM_MRT_TOOLS, 1, 1, pE->animSpeed* 2/3, 0, 512);	// slow this one down, coz it's horrible
						break;
					}
				}
				

			}


// Mr T needs to face the machine...
			pE->dir = enemyTendTowards(2048, pE->dir, 32);

// Note, the above code leaves the timer alone if it's a -ve number, which is treated as infy delay...
// If the machine's leaking, Mr T goes off to have a look at it...

// now that he's got two points enforced, I'll giv him a minimum wait time
			if(pE->points.timer < 0)
			{
				if((pE->points.pointFrom == 1 || pE->points.pointFrom == 2) && pE->stateCtr >= 100)
				{
					// If it's stopped leaking, head back to the guard point
					if(!PuzzleVars.variables[VAR_TOTAL_LEAKTIME])
					{
						enemyBeginTrekToSpecificPoint(pE, 0);
						pE->points.timer = 0;
					}
				}
				else
				{
					// If it's started leaking, go to play with the leak...
					if(PuzzleVars.variables[VAR_TOTAL_LEAKTIME])
					{
						enemyBeginTrekToSpecificPoint(pE, leak_target_point);
						pE->points.timer = 0;
					}
				}
			}
		}


		if(!pE->points.timer)
		{
//			utilPrintf("Return to Wander\n");
			SETSTATE(STATE_WANDERING);
			actorAnimate(pE->readData.pActor, ANIM_MRT_WALK, 1, 0, 256, 0, 512);	// blend the arms back
//			enemyBeginTrekToNextPoint(pE);	// now done before the wait
		}
		break;






	case STATE_PERSUIT:

		if(pE->stateCtr < 20)
		{
			persuit_steer_speed = 32 + (128-32) * pE->stateCtr / 20;
		}
		else
		{
			persuit_steer_speed = 128;
		}

		hourglass_dog_persuit = 2;
		hourglass_game_is_alert = 1;
		hourglass2Inform(HOURGLASS_MRT_IN_PERSUIT_MODE,NULL);

//		enemyEnsureAnimation(pE, ANIM_MRT_WALK);
		enemyEnsureAnimation(pE, ANIM_MRT_PERSUIT);

		pE->blinkOverride = 2;	// Keep looking real mad, little doggie

		if(actorReachedFrameRatio(pE->readData.pActor, -1, 1024) == ACTORFRAME_AT)
		{
			enemyPlayEnvironmentFootstepNoDogCheck((VECTOR *)&(pE->pos), 64);
		}
		if(actorReachedFrameRatio(pE->readData.pActor, -1, 3072) == ACTORFRAME_AT)
		{
			enemyPlayEnvironmentFootstepNoDogCheck((VECTOR *)&(pE->pos), 64);
		}

		{
			int old;
			old = pE->saw_non_welly_last_time;
			if(MrTweedyCanSeeCheck(pE,characterVars.pMainChar))
			{
				if(!old)
				{
					// Prevent him from carrying on to his old route point, if it was a long stretch
					MrTweedyCanSeeChicken(pE,&characterVars.pMainChar->pEnemy->pos);
					ext->alertpoint = characterVars.pMainChar->pEnemy->pos;
					dogInitRoute(pE,&ext->alertpoint,1);
				}
				else
				{

	//			DB("Mr T Persuit Can See Chicken\n");
					MrTweedyCanSeeChicken(pE,&characterVars.pMainChar->pEnemy->pos);
					ext->alertpoint = characterVars.pMainChar->pEnemy->pos;
				}
			}
		}
		enemyLookAtPos(pE, &ext->alertpoint);

		if(enemyCanSeeCheck(pE, &characterVars.pMainChar->pEnemy->pos, MRT_KILLER_FOV,MRT_KILLER_RANGE) < MRT_KILLER_RANGE)
		{
// If it's a welly, and we're not suspicious of it, just shake our head, and return to path
			if(characterVars.pHideChar && !pE->knows_youre_in_welly)
			{
				if(characterVars.pHideChar->pEnemy->runFlags & RUNFLAGS_VISIBLE)
				{
					overlayDebugMessage("Persuit tweedy hits welly, and gets confused", 25 * 2);
					SETSTATE(STATE_PREABANDON);
					break;
				}
			}

			{
				int d;
				d = pE->pos.vy - characterVars.pMainChar->pEnemy->pos.vy;
				if(!enemyEndingLevelFlag && d < 450)	// Don't catch the chicken if it's too far above Mr T
				{

					DB("Chicken dies horribly by persuit success!\n");
					SETSTATE(STATE_GROWLING);
					break;
				}
			}
		}


		if(
//			pE->stateCtr == 0
//			||
			(
//				!(pE->turning) &&
				enemyArrivedCheck(&pE->points.pointComingFrom, &pE->pos, &pE->points.pointGoingTo, 0)
			)
		)
		{
//			DB("Arr. len = %d\n",pE->route_len);

			pE->points.pointComingFrom = pE->pos;

			// Grab the next point in the existing route as a first bet for the corner estimate
			// (We'll revise our route once we're round the corner)
			if(pE->route_len > 1)
			{
				dogInitRoute(pE,&ext->alertpoint,1);

				pE->points.pointGoingTo.vx = pE->route[0].vx;	// 1
				pE->points.pointGoingTo.vy = pE->pos.vy;
				pE->points.pointGoingTo.vz = pE->route[0].vz;	// 1

				d = enemySteerTowards(pE, &pE->points.pointGoingTo, 32);
				pE->turning = 20;	// number of frames the turn anim takes

//				utilPrintf("Arrived, next pt\n");
//				overlayDebugMessage("Arrived, next pt",20);
			}
			else
			{
// We've arrived at a 1-length route target. Or, to put it another way, we're there.
//				DB("1-length route (Time to Abandon. Triggering light = &%8x)\n",triggering_light);

				pE->points.pointGoingTo.vx = pE->route[0].vx;
				pE->points.pointGoingTo.vy = pE->pos.vy;
				pE->points.pointGoingTo.vz = pE->route[0].vz;
// We've arrived at the target, yet we've not managed to kill the chicken
/*
				if(pE->route_truncated)
				{
					SETSTATE(STATE_GROWLING);
					break;	// don't do the moving bits of the code
				}
*/
//				DB("======= Time For Mr T to abandon! =========\n");

				pE->triggering_light = triggering_light;	// Note that this can be null...
//				SETSTATE(STATE_ABANDONING);
				SETSTATE(STATE_PREABANDON);
//				utilPrintf("Arrived, abandon\n");
//				overlayDebugMessage("Arrived, abandon",20);


			}

		}
		else
		{
			if(pE->turning)
			{
				enemySteerTowards(pE, &pE->points.pointGoingTo, persuit_steer_speed);
				pE->turning--;
				if(!pE->turning)	// Once we've rounded the corner, establish the route
				{

// Okay. We've rounded the corner. Now check to see if we can see the chicken.
//					dogInitRoute(pE,&ext->alertpoint,1);

//					utilPrintf("Corner turned. Route Init\n");
//					overlayDebugMessage("Corner turned. Route Init",20);

				}
			}
			else
			{
//				utilPrintf("Home Run %d\n",pE->route_len);
				if(pE->route_len < 3)	// If we've got direct line of sight, recalculate continually (is this wise?)
				{
//					utilPrintf("Home Run. Route Init %d\n",pE->route_len);
//					overlayDebugMessage("Home Run. Route Init",20);

					dogInitRoute(pE,&ext->alertpoint,0);
				}
				enemySteerTowards(pE, &pE->points.pointGoingTo, persuit_steer_speed);	// do the steering on a permanant basis
			}
		}
		enemyMove(pE, MRT_FORWARD_SPEED, ENEMYMOVE_SET, 0);	// Updates (pE->pos.vx and vz). enemy, desiredspeed, action (set,tendto), accel
		break;


	case STATE_PREABANDON:
		pE->vel.vx = pE->vel.vz = 0;
		if(pE->stateCtr < 1)
		{
			pE->triggering_light = triggering_light;	// Note that this can be null...
			actorAnimate(pE->readData.pActor, ANIM_MRT_HEADSHAKE, 0, 0, pE->animSpeed, 0, 512);
		}
		if(pE->stateCtr > 100)
		{
			SETSTATE(STATE_ABANDONING);
		}
		break;
	case STATE_ABANDONING:
	{
		int dc;
//		pE->knows_youre_in_welly = 0;

		enemyLookAtPos(pE, NULL);

		pE->triggering_light = triggering_light;	// Note that this can be null...

		enemyEnsureAnimation(pE, ANIM_MRT_WALK);

		if(actorReachedFrameRatio(pE->readData.pActor, -1, 1024) == ACTORFRAME_AT)
		{
			enemyPlayEnvironmentFootstepNoDogCheck((VECTOR *)&(pE->pos), 64);
		}
		if(actorReachedFrameRatio(pE->readData.pActor, -1, 3072) == ACTORFRAME_AT)
		{
			enemyPlayEnvironmentFootstepNoDogCheck((VECTOR *)&(pE->pos), 64);
		}

// Don't recalculate the route if we've already got a direct one
//		if(pE->route_len > 1 || pE->stateCtr < 1)
		if(pE->stateCtr < 1)
		{
//			DB("Abandon Init\n");
			pE->triggering_light = triggering_light;	// Note that this can be null...

			pE->view_range_rqd = MRT_SIGHT_RANGE;	// If it's been persuing, reset to normal
			pE->view_fov_rqd = MRT_SIGHT_FOV;

			pE->points.pointComingFrom = pE->pos;
			pE->points.pointTo = routeFindNearestPoint(&pE->pos, &pE->readData.pPoints[0], pE->readData.pDef->nPoints, &pE->route_target);

			dogInitRoute(pE,&pE->route_target,1);

//			if(pE->stateCtr < 1)
			{
				pE->runFlags&=(~RUNFLAGS_FORCETOFRONT);	// set the dog so it's not part of the death sequence any more

//				ext->corner_angle = enemyFindDeltaAngleTo(pE,&pE->points.pointGoingTo);
//				ext->corner_time = pE->turning = 26;
				pE->points.turnspeed_thiscorner = 60;	//(ABS(ext->corner_angle)) * 60 / 1024;
			}
		}
		else
		{
//			DB("Abandoning\n");
		}

//		enemyLookAtPos(pE, &pE->route_target);

		if(pE->readData.pDef->nPoints == 1)
			dc = 0;
		else
			dc = 400;

		if(!pE->turning && enemyArrivedCheck(&pE->points.pointComingFrom, &pE->pos, &pE->points.pointGoingTo, dc))
		{
			int d;
//			DB("abandon arrived\n");

			pE->points.pointComingFrom = pE->pos;

// Grab the next point in the existing route as a first bet for the corner estimate
// (We'll revise our route once we're round the corner)
			if(pE->route_len > 1)
			{
				dogInitRoute(pE,&pE->route_target,1);
				pE->points.pointGoingTo.vx = pE->route[0].vx;		// 1
				pE->points.pointGoingTo.vy = pE->pos.vy;
				pE->points.pointGoingTo.vz = pE->route[0].vz;		// 1
			}
			else
			{
//				DB("abandon arrived at 1-length. Start patrolling\n");
// We've arrived at a 1-length route target. Or, to put it another way, we're there.

//				DB("Time to return to patrol!\n");

				enemyMrTStartPatrolling(pE, (pE->points.pointTo+1) % pE->readData.pDef->nPoints);
			}

			d = enemySteerTowards(pE, &pE->points.pointGoingTo, 32);

//			pat->corner_angle = enemyFindDeltaAngleTo(pE,&pE->points.pointGoingTo);
//			DB("abandon-to-patrol angle %d\n",pat->corner_angle);
//			ext->corner_time = pE->turning = 26;
			pE->points.turnspeed_thiscorner = 60;	//(ABS(ext->corner_angle)) * 60 / 1024;

		}
		else
		{
			if(pE->turning)
			{
				enemySteerTowards(pE, &pE->points.pointGoingTo, pE->points.turnspeed_thiscorner);
				pE->turning--;
//				DB("abandon - post-turn route establish\n");
				// Once we've rounded the corner, establish the route
				if(!pE->turning)
				{
//					dogInitRoute(pE,&pE->route_target,1);
				}
			}
			else
			{
				if(pE->route_len < 3)	// If we've got direct line of sight, recalculate continually
				{
//					DB("abandon - contunial route recalc\n");
					dogInitRoute(pE,&pE->route_target,0);
				}
				enemySteerTowards(pE, &pE->points.pointGoingTo, 32);
			}
		}
		enemyMove(pE, MRT_FORWARD_SPEED, ENEMYMOVE_SET, 0);	// Updates (pE->pos.vx and vz). enemy, desiredspeed, action (set,tendto), accel
		break;
	}










// The Mr T in the piebarn needs to loom over the rats threateningly
	case STATE_GROWLING:
		pE->vel.vx = 0;
		pE->vel.vz = 0;

// tbd - It might not be the currently-main rat that he collides with
		if(pE->stateCtr==0 && !enemyEndingLevelFlag && !deathDying)
		{
//			actorAnimate(pE->readData.pActor, ANIM_MRT_SCOWL, 0, 0, pE->animSpeed, 0, 512);	// don't loop or queue. Blend
			actorAnimate(pE->readData.pActor, ANIM_MRT_KILLING, 0, 0, pE->animSpeed, 0, 512);	// don't loop or queue. Blend

			if(gameTextLang == LANG_UK)
			{
				switch(characterVars.pMainChar->pEnemy->readData.nameCRC)
				{
					// Don't bother with stereo on the death sfx, so we get a decent volume on them
					case CRC_NICK:
					case CRC_FETCHER:
					case CRC_GNOME:
						soundPlaySpeech(pE->readData.ppSamples[ENEMY_SFX_MRTTHIEVEBUGGRS], 0);
						break;
					default:
						soundPlaySpeech(pE->readData.ppSamples[ENEMY_SFX_MRTNOCHICKESCAPES], 0);
						break;
				}
			}
			deathKill(characterVars.pMainChar, DEATH_REASON_MRT_LOOM, pE);
		}
		pE->desiredDir = enemyFindAbsAngleTo(pE,&characterVars.pMainChar->pEnemy->pos);

		pE->dir = enemyTendTowards(pE->desiredDir, pE->dir, 32);

		if(deathDying)
		{
			enemyLookAtPos(pE, NULL);	// In the deathseq, Mr T should be looking at the camera, not the chicken
		}
// But for now, we'll reset Mrs T.
		if(pE->stateCtr >= 100 && !deathDying)	// Don't stop growling while the death sequence is going on)
		{
			actorAnimate(pE->readData.pActor, ANIM_MRT_WALK, 1, 0, 256, 0, 512);
			pE->runFlags&=(~RUNFLAGS_FORCETOFRONT);	// set it so it's not part of the death sequence any more
			SETSTATE(STATE_WANDERING);
		}


		break;

	}
	return 0;
}

// tbd - the piebarn Mr T needs to be woken out of his slumber by dripping gravy
