

class TurnToVelocity extends SqRootScript
{
	function Proceed()
	{
		local t = SetOneShotTimer("PendGoal",0.2);
		if(IsDataSet("turnTimer"))
			KillTimer(GetData("turnTimer"));
		SetData("turnTimer",t);
	}
	
	function ProceedOn()
	{
		SetGoal();
		if(!IsDataSet("rot_goal"))
			return;
		local goal = GetData("rot_goal");
		
		local res = goal - Object.Facing(self).z;
		
		while (res > 180) {res-=360}
		while (res < -180) {res+=360}
		
		if("Debug" in userparams())
			DarkUI.TextMessage(res);
		
		TurnAround(res < 0);
	}

	function SetGoal()
	{
		local vel = vector(0);
		Physics.GetVelocity(self,vel);
		
		local dir = vel.GetNormalized();
		local goal = M.GetAngleFromDir(dir).z;
		SetData("rot_goal", goal)
	}

	function TurnAround(dir)
	{
		if(!IsDataSet("rot_goal"))
			return;

		if(dir)
			Object.Teleport(self,vector(0),vector(0,0,-2),self);
		else
			Object.Teleport(self,vector(0),vector(0,0,2),self);
			
		local goal = GetData("rot_goal");
		local my_rot = Object.Facing(self);
		local res = abs(goal - my_rot.z);
		
		while (res > 360) {res-=360}
		
		if(res <= 10 || res >= 350)
			Object.Teleport(self,Object.Position(self),vector(my_rot.x,my_rot.y,goal));
		else
		{
			SetGoal();
			local t = SetOneShotTimer("Turn",0.08,dir);
			if(IsDataSet("turnTimer"))
				KillTimer(GetData("turnTimer"));
			SetData("turnTimer",t);
		}
	}

	function OnTimer()
	{
		if(message().name == "Turn")
			TurnAround(message().data);
			
		if(message().name == "PendGoal")
			ProceedOn();
	}
	
	function OnMovingTerrainWaypoint()
	{
		Proceed();
	}
	
	function OnTweqComplete()
	{
		if(message().Type == eTweqType.kTweqTypeFlicker)
			Proceed();
	}
}

class TellMessage extends SqRootScript
{
	function OnMessage()
	{
		print(">>>>>>>>>>");
		DarkUI.TextMessage(message().message);
		print(message().message);
		print(message().from);
		print(message().to);
		print(message().data);
		print(message().data2);
		print(message().data3);
		print("<<<<---------------");
	}
}


//Two items are the same but only one is necessary and you don't want stacks nor inv flooding?
//Use this script! Set ScriptParams : Duplet from an object to the others and the others
//won't go into the player's inventory.
class OneIsEnough extends SqRootScript
{
	function OnContained()
	{
		if(message().container == ObjID("Player") && message().event == 2)
		{
			Link.BroadcastOnAllLinksData(self,"CantWorldMove","ScriptParams","Duplet");
			Link.BroadcastOnAllLinksData(self,"CantWorldMove","~ScriptParams","Duplet");
		}
		else if(message().container == ObjID("Player") && message().event == 3)
		{
			Link.BroadcastOnAllLinksData(self,"CanWorldMove","ScriptParams","Duplet");
			Link.BroadcastOnAllLinksData(self,"CanWorldMove","~ScriptParams","Duplet");
		}
	}
	
	function OnCantWorldMove()
	{
		local bits = GetProperty("FrobInfo", "World Action");
		if((bits | 1) == bits)
			SetProperty("FrobInfo","World Action",bits^1);
	}
	
	function OnCanWorldMove()
	{
		local bits = GetProperty("FrobInfo", "World Action");
		SetProperty("FrobInfo","World Action",bits|1);
	}
}



//Synchronize locked doors states
//
//Made for locked Double doors since TG doesn't handle this right
class SynchLocks extends SqRootScript
{
	function OnNowUnlocked()
	{
		Link.BroadcastOnAllLinksData(self,"Unlock","ScriptParams","Double");
		Link.BroadcastOnAllLinksData(self,"Unlock","~ScriptParams","Double");
	}
	
		function OnNowLocked()
	{
		Link.BroadcastOnAllLinksData(self,"Lock","ScriptParams","Double");
		Link.BroadcastOnAllLinksData(self,"Lock","~ScriptParams","Double");
	}
	
	function OnUnlock()
	{
		if(GetProperty("Locked"))
			SetProperty("Locked",false);
	}
	
	function OnLock()
	{
		if(!GetProperty("Locked"))
			SetProperty("Locked",true);
	}
}

//Make the SFX group fading out completely
//
// Warning : result not convincing. Use at your own risk
class SFXDecay extends SqRootScript
{
	function SFXDecays()
	{
		if(HasProperty("ParticleGroup"))
		{
			local particlesAlpha = GetProperty("ParticleGroup","alpha");
			particlesAlpha -= 1;
			if(particlesAlpha <= 0)
				Object.Destroy(self);
			else
				SetProperty("ParticleGroup","alpha",particlesAlpha)
		}
		
		if(IsDataSet("DecayCheck"))
		{
			KillTimer(GetData("DecayCheck"));
			ClearData("DecayCheck");
		}
		local t = SetOneShotTimer("DecayCheck",1);
		SetData("DecayCheck",t);
	}
	
	function OnTweqComplete()
	{
		SFXDecays();	
	}
	
	function OnTimer()
	{
		if(message().name == "DecayCheck")
			SFXDecays();
	}
}

// Change the SFX shape so it creates a line between the one who created
// this SFX group and the SFX group itself
class SFXCulpritPointer extends SqRootScript
{
	function OnTweqComplete()
	{
		FindCulprit();
	}
	function FindCulprit()
	{
		//If we have a culprit link
		//we're going to adjust the gravity
		//so our particles move toward our boy
		
		local culprit_link = Link.GetOne("~CulpableFor",self);
		
		//We should be a SFX and have a culprit link
		if(HasProperty("ParticleGroup") && culprit_link != 0)
		{
			local culprit = LinkDest(culprit_link);
			local distance = (Object.Position(culprit) - Object.Position(self));
			
			//In case there's already cool gravity params which could fit this effect,
			//let's keep them
			distance += GetProperty("ParticleGroup","gravity vector");
			SetProperty("ParticleGroup","gravity vector",distance);
		}
	}
}

// Make this projectile follows its target by adjusting its velocity
class AutoAimProj extends SqRootScript
{
	function ScanForTarget()
	{
		//Our variables
		local MAX_SPEED = 60;
		local culprit = 0;
		local culprit_link = Link.GetOne("~CulpableFor",self);
		local target = 0;
		
		//If we know already the enemy, let's chase them!
		if(IsDataSet("Target"))
			target = GetData("Target");
		
		//Check if a limit is defined in matter of speed
		if(HasProperty("AI_MoveSpeed"))
			MAX_SPEED = GetProperty("AI_MoveSpeed")
			
		//Let's find the dude who shot us so we could see
		//who is the enemy we are supposed to hurt.
		//We skip this part if we already know the enemy.
		if(culprit_link != 0 && target == 0)
			culprit = LinkDest(culprit_link);
		if(culprit != 0)
		{
			local target_link = Link.GetOne("AITarget",culprit);
			if(target_link != 0)
				target = LinkDest(target_link);
			//We will never forget you!
			if(target != 0)
				SetData("Target",target);
		}
		
		//We found someone our shooter want to see dead?
		//Fair enough let's chase!
		if(target != 0)
		{
			local current_velocity = vector(0);
			Physics.GetVelocity(self,current_velocity);
			
			local target_n_me_dist = (Object.Position(target) - Object.Position(self));
			local target_n_me_dir = target_n_me_dist.GetNormalized();
			
			current_velocity += target_n_me_dir*2;
			
			local target_n_me_len = current_velocity.Length();
			
			if(target_n_me_len > MAX_SPEED && target_n_me_len != 0)
			{
				local coef = MAX_SPEED / target_n_me_len;
				current_velocity *= coef;
			}
			Physics.SetVelocity(self,current_velocity);
			
			if(IsDataSet("TargetCheck"))
			{
				KillTimer(GetData("TargetCheck"));
				ClearData("TargetCheck");
			}
			local t = SetOneShotTimer("SearchTarget",0.07);
			SetData("TargetCheck",t);
		}
	}

	function OnBeginScript()
	{
		if(!IsDataSet("TargetCheck"))
		{
			local t = SetOneShotTimer("SearchTarget",0.15);
			SetData("TargetCheck",t);
		}
	}
	function OnTimer()
	{
		if(message().name == "SearchTarget")
			ScanForTarget();
	}
}

//If this projectile hurt a living target, add +5 hp to the projectile launcher
class LifeDrain extends SqRootScript
{
	function GoodHit(hit_obj)
	{
		//Should be a valid object
		if(hit_obj <= 0)
			return false;
		//Any
		return (Object.InheritsFrom(hit_obj,ObjID("Avatar")) || (Object.InheritsFrom(hit_obj,ObjID("Creature")) && Property.Get(hit_obj,"AI_Mode") != 5));
	}
	function OnBeginScript()
	{
	  Physics.SubscribeMsg(self, ePhysScriptMsgType.kCollisionMsg);
	}
	function OnEndScript()
	{
	  Physics.UnsubscribeMsg(self, ePhysScriptMsgType.kCollisionMsg);
	}
	function OnPhysCollision()
	{
		local WhatIHit = message().collObj;
		local culprit = 0;
		local culprit_link = Link.GetOne("~CulpableFor",self);
		
		if(culprit_link != 0)
			culprit = LinkDest(culprit_link);
		
		if(GoodHit(WhatIHit) && culprit > 0)
			Property.SetSimple(culprit,"HitPoints",(Property.Get(culprit,"HitPoints")+5));
		
	}
}

// Projectile goes directly to player's position
class TeleportToTarget extends SqRootScript
{
	function Firer()
	{
		if(Link.AnyExist("Firer",self))
			return LinkDest(Link.GetOne("Firer",self));
		if(IsDataSet("Dad"))
			return GetData("Dad");
		return 0;
	}
	
	function Target()
	{
		local f = Firer();
		if(f == 0)
			return 0;
		if(Link.AnyExist("AITarget",f))
			return LinkDest(Link.GetOne("AITarget",f));
		if(IsDataSet("Foe"))
			return GetData("Foe");
		return 0;
	}

	function OnLaunch()
	{
		if(Firer()==0)
			return;
		SetData("Dad",Firer());
		SetData("Foe",Target());
		SetOneShotTimer("Tp",0.01)
	}
	
	function OnTimer()
	{
		if(message().name)
			Object.Teleport(self,vector(0),vector(0),Target());
	}
}

// Create and attach something on the target hurt by the projectile
class AttacherProj extends SqRootScript
{
	function GoodHit(hit_obj,flags)
	{
		//Should be a valid object
		if(hit_obj <= 0)
			return false;
		//Any
		if(flags == 0)
			return true;
		//Players
		if((flags | 1) == flags && (hit_obj == ObjID("Player")))
			return (hit_obj == ObjID("Player"));
		//Creatures
		if((flags | 2) == flags)
			return Object.InheritsFrom(hit_obj,ObjID("Creature"));
		return false;
	}
	function OnBeginScript()
	{
	  Physics.SubscribeMsg(self, ePhysScriptMsgType.kCollisionMsg);
	}
	function OnEndScript()
	{
	  Physics.UnsubscribeMsg(self, ePhysScriptMsgType.kCollisionMsg);
	}
	function OnPhysCollision()
	{
		local WhatIHit = message().collObj;
		local new_obj = 0;
		local culprit = 0;
		local culprit_link = Link.GetOne("~CulpableFor",self);
		local flags = 0;
		
		//Who shot me?
		if(culprit_link != 0)
			culprit = LinkDest(culprit_link);
			
		if("Flags" in userparams())
				flags = userparams().Flags;
		
		if(GoodHit(WhatIHit,flags))
		{
			//DarkUI.TextMessage("HIT VALID : "+ WhatIHit + " FLAGS : " + flags);
			if("AttachedItem" in userparams())
					new_obj = Object.Create(userparams().AttachedItem);
			else
				new_obj = Object.Create("SmokePuff");

			if(new_obj > 0)
			{
				//Let's never forget who sent me.
				//Just in case it's supposed to hurt and kill...
				if(culprit != 0)
					Link.Create("CulpableFor",culprit,new_obj);
				Link.Create("DetailAttachement",new_obj,WhatIHit);
			}
		}
		Reply(ePhysMessageResult.kPM_Slay);
   }
}

// Banners Animation for opening and closing and also destruction
//	use the replace banner models
class NewBanner extends SqRootScript
{
	//Default BANNER dead ModelName
	bandead = "BANNWCUT";
		
	//Check if something is between these two vectors
	function IsBetween(v1,v2,tocheck,margin)
	{
		return ((tocheck.x >= (v1.x - margin)) && (tocheck.y >= (v1.y - margin)) && (tocheck.z >= (v1.z - margin))) && ((tocheck.x <= (v2.x + margin)) && (tocheck.y <= (v2.y + margin)) && (tocheck.z <= (v2.z + margin)));
	}
	
	//Check if the player is still in the "area" of the banner and then decide if
	//it can close or stay opened
	function IsSomeoneStillThere()
	{
		local plr_pos = Object.Position(Object.Named("Player"));
		local self_pos = Object.Position(self);
		local self_dim = M.StringToVec(GetData("self_dim"))/2;//(GetProperty("PhysDims","Size"))/2;
		local self_offset = M.StringToVec(GetData("self_offset"));//GetProperty("PhysDims","Offset 1");
		/*print(self_dim);
		print(self_offset);*/
		return IsBetween((self_pos + self_offset - self_dim),(self_pos + self_offset + self_dim),plr_pos,2);
	}
	
	//Interrupt animations to close or open if player tries
	//to be silly and play with banners animation
	function LaunchNewTransitionMsg(delay,data)
	{
		if(IsDataSet("Transitionning"))
		{
			KillTimer(GetData("Transitionning"));
			if(delay < 0)
			{
				ClearData("Transitionning");
				return;
			}
		}
		if(delay < 0)
			return;
		local timer = SetOneShotTimer("TransitState",delay,data);
		SetData("Transitionning",timer);
	}
	
	function MakePhys()
	{
		SetProperty("CollisionType",1);
		SetProperty("PhysType","Type",0);
		SetProperty("BlockFrob",true);
		SetProperty("PhysDims","Size",M.StringToVec(GetData("self_dim")));
		SetProperty("PhysDims","Offset 1",M.StringToVec(GetData("self_offset")));
	}
	
	function MakeNonePhys()
	{
		SetProperty("CollisionType",0);
		SetProperty("CollisionType",0);
		SetProperty("PhysType","Type",3);
		SetProperty("BlockFrob",false);
	}
	
	function BanIsDead()
	{
		if(IsDataSet("Transitionning"))
		{
			KillTimer(GetData("Transitionning"));
			ClearData("Transitionning");
		}
		local dead_model = bandead;
		if("CorpseModel" in userparams())
			dead_model = userparams().CorpseModel;
		SetProperty("ModelName",dead_model);
		
		MakeNonePhys();

		Physics.UnsubscribeMsg(self,ePhysScriptMsgType.kCollisionMsg);
		Physics.LaunchProjectile(self,Object.Named("ExBanner"),0,0,vector(0));
	}
	
	function Collect_frames(last_frame)
	{
		// Not IT friendly but we start from 1 NOT 0 -> 0 is reserved for first frame
		// Also since we can't check if files exists in a reliable ways
		// (did tries with Version services and it was very meh)
		// we'll suppose if you choose SomeModel_9, you also made SomeModel_8/7/6/...
		// if you didn't, well you'll see Dromed's default cheese 
		// and will be the only one to blame!!
		
		local arr = split(last_frame,"_");
		arr.resize(2,"0");
		try
		{
			SetData("frame_base_name",arr[0]);
			return arr[1].tointeger();
		}
		catch(err)
		{
			if(IsDataSet("frame_base_name"))
				ClearData("frame_base_name");
			return 1; // Direct from 1st frame to last one
			// and no number manipulation
		}
		SetData("frame_base_name","bannwO_");
		return 7;
	}
	
		
	function PrepareCustomization()
	{
		local dead_model = bandead;
		if("CorpseModel" in userparams())
			dead_model = userparams().CorpseModel;
		if(GetProperty("HitPoints") < 1 || GetProperty("ModelName") == dead_model)
			return true;

		local first_frame = "bannew";
		if(HasProperty("ModelName"))
			first_frame = GetProperty("ModelName");
		SetData("first_frame",first_frame);
		
		local last_frame = "bannwO_7";
		if("LastFrameModel" in userparams())
			last_frame = userparams().LastFrameModel;
		SetData("last_frame",last_frame);
		
		SetData("frames",Collect_frames(last_frame));
		
		return false;
	}
	
	//Change the model into a cut model and set to non-physical
	//Create an ExBanner marker so AI notice the now destroyed banner
	function OnSlain()
	{
		BanIsDead();
	}
	
	//Gather data for first animation frame (in case of custom model/vanilla banner model)
	//Also remember the default dim and offset vectors
	function OnBeginScript()
	{
		Physics.SubscribeMsg(self,ePhysScriptMsgType.kCollisionMsg);
		if(!IsDataSet("self_dim") || !IsDataSet("self_offset"))
		{
			local is_dead = PrepareCustomization();
			if(is_dead)
			{
				Damage.Slay(self,0);
				return;
			}
		
			local self_dim = M.VecToString(GetProperty("PhysDims","Size"));
			local self_offset = M.VecToString(GetProperty("PhysDims","Offset 1"));
			SetData("self_dim",self_dim);
			SetData("self_offset",self_offset);			
		}		
	}

	
	function OnEndScript()
	{
		Physics.UnsubscribeMsg(self,ePhysScriptMsgType.kCollisionMsg);
	}
	
	//Start opening animation on touch
	function OnPhysCollision()
	{
		if(!IsDataSet("Transitionning"))
		{
			/*local timer = SetOneShotTimer("TransitState",0.02,0);
			SetData("Transitionning",timer);*/
			/*print("first frame = " + GetData("first_frame"));
			print("last frame = " + GetData("last_frame"));
			print("number of frames = " + GetData("frames"));
			print("base name of frames = " + GetData("frame_base_name"));
			print("----------------------------------------------------------");*/
			if(HasProperty("StTweqModels"))
			{
				SetData("former_anims",GetProperty("StTweqModels","AnimS"));
				SetProperty("StTweqModels","AnimS",0);
			}
			SetProperty("ModelName",GetData("first_frame"));
			SetData("current_id",0);
			LaunchNewTransitionMsg(0.02,1);
			Sound.HaltSchema;
			Sound.PlayEnvSchema(self,"Event StateChange, " + (GetProperty("Class Tags","1: Tags")) + ", OpenState Opening",self);
		}
	}
	
	function OnTimer()
	{
		if(message().name == "TransitState")
		{
			if(message().data != null)
			{
				local curmodel = GetProperty("ModelName");
				local curidx = GetData("current_id") + message().data;
				SetData("current_id",curidx);
				
				//No transition animation demanded
				//Just check where the player is to decide
				//what to do next
				if(message().data == 0)
				{
					if(IsSomeoneStillThere())
						LaunchNewTransitionMsg(0.5,0);
					else
					{
						LaunchNewTransitionMsg(0.1,-1);
						Sound.HaltSchema;
						Sound.PlayEnvSchema(self,"Event StateChange, " + (GetProperty("Class Tags","1: Tags")) + ", OpenState Closing",self);
					}
				}
				
				//Open the banner
				if(message().data == 1)
				{
					if(curmodel != GetData("last_frame") && curidx < GetData("frames"))
					{
						if(curidx <= 0)
						{
							SetProperty("ModelName",GetData("first_frame"));
							curidx = 0;
						}
						else 
						{
							if(IsDataSet("frame_base_name"))
								SetProperty("ModelName",(GetData("frame_base_name")+ "_" + curidx.tostring()));
							else
								SetProperty("ModelName",GetData("last_frame"));
						}
						
							
						if(IsSomeoneStillThere())
							LaunchNewTransitionMsg(0.1,1);
						else
						{
							LaunchNewTransitionMsg(0.1,-1);
							Sound.HaltSchema;
							Sound.PlayEnvSchema(self,"Event StateChange, " + (GetProperty("Class Tags","1: Tags")) + ", OpenState Closing",self);
						}
					}
					else
					{
						SetProperty("ModelName",GetData("last_frame"));
						MakeNonePhys();
						//SetProperty("PhysDims","Size",GetProperty("PhysDims","Size")/2)
						LaunchNewTransitionMsg(0.5,0);
					}
				}
				
				//Close the banner
				if(message().data == -1)
				{
					if(curmodel != GetData("first_frame") && curidx > 0)
					{
						if(curidx >= GetData("frames"))
						{
							SetProperty("ModelName",GetData("last_frame"));
							curidx = GetData("frames");
						}
						else 
						{
							if(IsDataSet("frame_base_name"))
								SetProperty("ModelName",(GetData("frame_base_name")+ "_" + curidx.tostring()));
							else
								SetProperty("ModelName",GetData("first_frame"));
						}
						
						if(!IsSomeoneStillThere())
							LaunchNewTransitionMsg(0.1,-1);
						else
						{
							LaunchNewTransitionMsg(0.1,1);
							Sound.HaltSchema;
							Sound.PlayEnvSchema(self,"Event StateChange, " + (GetProperty("Class Tags","1: Tags")) + ", OpenState Opening",self);
						}
					}
					else
					{
						SetProperty("ModelName",GetData("first_frame"));
						MakePhys();
						if(IsDataSet("former_anims"))
							SetProperty("StTweqModels","AnimS",GetData("former_anims"));
						LaunchNewTransitionMsg(-1,0);
					}
				}
			}
		}
	}
}

//Make gears playing sounds during their tweq and after their tweq
//from DoorType Schema Tags
class GearNormal extends SqRootScript
{
	DoorAction = [
	  "Open",
	  "Closed",
	  "Opening",
	  "Closing",
	  "Halted"
	];
	
	function ToggleTurn()
	{
		if((GetProperty("StTweqRotate","AnimS") | 1) != GetProperty("StTweqRotate","AnimS"))
		{
			Sound.HaltSchema(self);		
			SetProperty("StTweqRotate","AnimS", 	  (GetProperty("StTweqRotate","AnimS")) | 1);
		}
		else
			SetProperty("StTweqRotate","AnimS", 	  (GetProperty("StTweqRotate","AnimS")) ^ 2);
		
		local tweqState = GetProperty("StTweqRotate","AnimS");
		
		SetProperty("StTweqRotate","Axis 1AnimS", tweqState);
		SetProperty("StTweqRotate","Axis 2AnimS", tweqState);
		SetProperty("StTweqRotate","Axis 3AnimS", tweqState);

		if((tweqState | 2) == tweqState)
			Sound.PlayEnvSchema(self,"Event StateChange, OpenState Closing, OldOpenState Closed", self);
		else
			Sound.PlayEnvSchema(self,"Event StateChange, OpenState Opening, OldOpenState Open", self);
	}
	
	function OnTweqComplete()
	{
		if(message().Op == 2)
		{
			if((GetProperty("StTweqRotate","AnimS") | 1) == GetProperty("StTweqRotate","AnimS"))
				SetProperty("StTweqRotate","AnimS", (GetProperty("StTweqRotate","AnimS")) ^ 3);
			Sound.HaltSchema(self);
			Sound.PlayEnvSchema(self,"Event StateChange, OpenState Closed, OldOpenState Opening", self);			
		}
	}
	
	function OnTurnOn()
	{
		if(!IsDataSet("LastState"))
			SetData("LastState",false);
		if(!GetData("LastState"))
		{
			SetData("LastState",true);
			ToggleTurn();
		}
	}
	
	function OnTurnOff()
	{
		if(!IsDataSet("LastState"))
			SetData("LastState",true);
		if(GetData("LastState"))
		{
			SetData("LastState",false);
			ToggleTurn();
		}
	}
}

//Make it possible to turn off the freaking lantern held by AIs
//and also making these responding to such an action
class CarriedLamp extends SqRootScript
{
	function LampTurnedOff()
	{
		if(!IsDataSet("LampOff"))
		{
			SetData("LampOff", GetProperty("SelfLit"));
			SetProperty("SelfLit",0);
			SetProperty("SelfIllum",0);
			SetProperty("FrobInfo","World Action",0);
			//No matter how designers wants the AI to carry the lamp
			//The AI carrying it SHOULD be informed
			Link.BroadcastOnAllLinks(self,"LampIsOff","DetailAttachement");
			Link.BroadcastOnAllLinks(self,"LampIsOff","PhysAttach");
			Link.BroadcastOnAllLinks(self,"LampIsOff","~CreatureAttachment");
		}
	}
	
	function LampTurnedOn()
	{
		SetProperty("FrobInfo","World Action",2);
		SetProperty("SelfIllum",1);
		SetProperty("SelfLit",GetData("LampOff"));
		ClearData("LampOff");		
	}
	
	function OnTurnOn()
	{
		LampTurnedOn();
	}

	function OnFrobWorldBegin()
	{
		LampTurnedOff();
	}
	
	function OnSmokeStimStimulus()
	{
		LampTurnedOff();
	}
	
	function OnKOGasStimulus()
	{
		LampTurnedOff();
	}
	
	function OnWaterStimStimulus()
	{
		LampTurnedOff();
	}
}

//Launch a timer upon TurnOn - 
//CD linked stuff will be activated at the same time
//However the timer will deactivate once the time is out
class TrapTimed extends SqRootScript
{
	function OnTurnOn()
	{
		Link.BroadcastOnAllLinks(self,"TurnOn","ControlDevice");
		if(IsDataSet("timer"))
		{
			KillTimer(GetData("timer"));
			ClearData("timer");
		}

		local timer = 1000;
		if(HasProperty("ScriptTiming")) {timer = GetProperty("ScriptTiming");}
		local t = SetOneShotTimer("Delay",timer/1000);
		SetData("timer",t);
	}
	
	function OnTurnOff()
	{
		Off();
	}
	
	function OnTimer()
	{
		if(message().name == "Delay")
		{
			Off();
		}
	}
	
	function Off()
	{
		Link.BroadcastOnAllLinks(self,"TurnOff","ControlDevice");
		if(IsDataSet("timer"))
		{
			KillTimer(GetData("timer"));
			ClearData("timer");
		}
	}
}

//Make Loot items get the ReplaceTextures properties for the newly stolen items
//so Loot using Replace Textures will keep their custom texture
//instead of displaying the ugly replace texture
class ResLoot extends SqRootScript
{
	function OnCombine()
	{
		//print("COMBINE : " +(message().combiner).tostring() + " " + self.tostring());
		local o = message().combiner;
		if(Property.Possessed(o,"OTxtRepr0"))
			SetProperty("OTxtRepr0",Property.Get(o,"OTxtRepr0"));
		if(Property.Possessed(o,"OTxtRepr1"))
			SetProperty("OTxtRepr1",Property.Get(o,"OTxtRepr1"));
		if(Property.Possessed(o,"OTxtRepr2"))
			SetProperty("OTxtRepr2",Property.Get(o,"OTxtRepr2"));
		if(Property.Possessed(o,"OTxtRepr3"))
			SetProperty("OTxtRepr3",Property.Get(o,"OTxtRepr3"));
	}
}

// Once the elevator reach its point, it will play all its tweqs
class PlayTweqOnWayPoint extends SqRootScript
{
	function OnMovingTerrainWaypoint()
	{
		if((GetProperty("TrapFlags") | 2) == GetProperty("TrapFlags"))
		{
			ActReact.React("tweq_control",1.0,self,0,eTweqType.kTweqTypeAll,eTweqDo.kTweqDoReset);
			Object.Teleport(self,Object.Position(self),Object.Facing(message().waypoint));
		}
		else
			ActReact.React("tweq_control",1.0,self,0,eTweqType.kTweqTypeAll,eTweqDo.kTweqDoForward);
		SetProperty("TrapFlags", GetProperty("TrapFlags") ^ 2);
	}
	
	function OnTweqComplete()
	{
		if(GetProperty("MovingTerrain","Active"))
			return;
		if(message().Dir == eTweqDirection.kTweqDirForward)
			Link.BroadcastOnAllLinks(self,"TurnOn","ControlDevice");
	}
}


// Let's rewrite LGS code here
// so we could make our own code derivated from it
class Legible extends SqRootScript
{
   function ShowText()
   {
      if(Property.Possessed(self,"book"))
      {
         local bookname=Property.Get(self,"book");

         // we are so wacky.  We will code the possibility of qvar-dependent
         // books straight into the core legible script.
         if(Property.Possessed(self,"TrapQVar"))
         {
            local qvar=Property.Get(self,"TrapQVar");
            local index=Quest.Get(qvar);
            // use sprintf to adhere to usual naming convention for books.
            local buf = bookname + index.tostring();
            bookname=string(buf);
         }

         if(Property.Possessed(self,"bookart"))
         {
            local bookart=Property.Get(self,"bookart");

            DarkUI.ReadBook(bookname,bookart);
         }
         else
         {
            bookname=string("..\\Books\\")+bookname;
            local popup=Data.GetString(bookname,"Page_0");
            DarkUI.TextMessage(popup);
         }
      }
   }
}

class StdBook extends Legible
{
	function OnFrobWorldEnd()
	{
		 ShowText();
	}
}

class StdScroll extends Legible
{
	function OnFrobInvEnd()
	{
		 ShowText();
	}
}

// Let's do some plagiarism to make a base of legible
// using exclusively the on screen text without any bookart
// Handy to "reverse" this property when you want to change 
// a book or scroll type into plaque
class ScreenLegible extends SqRootScript
{
	function SetReadingTimer(yes)
	{
		if(IsDataSet("Refresh_Reading"))
		 {
			KillTimer(GetData("Refresh_Reading"));
			ClearData("Refresh_Reading");
			
		 }
		 if(yes)
		 {
			 local t = SetOneShotTimer("RefreshReading",1);
			 SetData("Refresh_Reading",t);
		 }
	}
	
	function Read()
	{
		ShowText();
		SetReadingTimer(true);
	}

	function ShowText()
	{
		if(Property.Possessed(self,"book"))
		{
			local bookname=Property.Get(self,"book");
			bookname=string("..\\Books\\")+bookname;
			local popup=Data.GetString(bookname,"Page_0");
			DarkUI.TextMessage(popup);
		}
	}
	
	function OnTimer()
	{
		if(message().name == "RefreshReading")
			Read();
	}
}

// Frob it once then the text won't despawn 
// as long as you don't look away
class StdPlaque extends ScreenLegible
{
	function OnFrobWorldEnd()
	{
		 Read();
	}
	
	function OnWorldDeSelect()
	{
		if(!IsDataSet("Refresh_Reading"))
		 return;
		SetReadingTimer(false);
		ShowText();
		
	}
}

// Let's be original : plaque in inventory !
// As long as you don't close your inventory
// or swich to another item, the text will
// still display after you frobbed it once
class StdTablet extends ScreenLegible
{
	function OnFrobInvEnd()
	{
		if(IsDataSet("Refresh_Reading"))
		{
			SetReadingTimer(false);
			ShowText();
			return;
		}
		Read();
	}
	
	function OnInvDeSelect()
	{
		if(!IsDataSet("Refresh_Reading"))
		 return;
		SetReadingTimer(false);
		ShowText();
	}
	
	function OnInvDeFocus()
	{
		if(!IsDataSet("Refresh_Reading"))
		 return;
		SetReadingTimer(false);
		ShowText();
	}
}

class SpecialDropDetail extends SqRootScript
{
	function DropCopy(obj)
	{
		local o = Object.Create(obj);
		local loc = Object.Position(self);
		local rot = Object.Facing(self);
		local scale = Property.Get(o,"Scale");
		local size = Property.Get(o,"PhysDims","Radius 1");
		
		if((Object.GetName(obj) + "_offset") in userparams())
			loc += M.StringToVec(userparams()[(Object.GetName(obj) + "_offset")]);
		if((Object.GetName(obj) + "_rot") in userparams())
			rot = M.StringToRVec(userparams()[(Object.GetName(obj) + "_rot")]) + vector(0,0,rot.z);
		if((Object.GetName(obj) + "_scale") in userparams())
			scale = M.StringToVec(userparams()[(Object.GetName(obj) + "_scale")]);
		if((Object.GetName(obj) + "_size") in userparams())
		{
			try
			{
				size = (userparams()[(Object.GetName(obj) + "_size")]).tofloat();
			}
			catch(err)
				size = 0.1;
		}

		Property.SetSimple(o,"Scale",scale);
		Property.Set(o,"PhysDims","Radius 1",size);
		Object.Teleport(o,loc,rot);
	}
	
	function OnDrop()
	{
		if(!message().data)
			return;
		local ls = Link.GetAll("ControlDevice",self);
		foreach(l in ls)
		{
			DropCopy(LinkDest(l));
		}
	}
}

class BlockFrobOnState extends SqRootScript
{
	function OnSim()
	{
		if(message().starting)
			StopBlockingFrob(false);
	}

	function StopBlockingFrob(yes)
	{
		SetProperty("BlockFrob",!yes);
		foreach(l in Link.GetAll("ScriptParams",self))
		{
			Property.SetSimple(LinkDest(l),"BlockFrob",!yes);
			if(LinkTools.LinkGetData(l,"") == "protect")
			{
				if(yes)
					Property.Set(LinkDest(l),"FrobInfo","World Action",3);
				else
					Property.Set(LinkDest(l),"FrobInfo","World Action",0);
			}
		}
	}
	
	// You've opened the LID!!
	function OnDoorOpening()
	{
		StopBlockingFrob(true);
	}
	
	// Lid closed.
	function OnDoorClose()
	{
		StopBlockingFrob(false);
	}
}
