DIFF

Torch.c

class FlammableBase : ItemBase
{
	const float PARAM_FULL_HEAT_RADIUS 				= 0.5;
	const float PARAM_HEAT_RADIUS 					= 1.0;
	const int 	TIMER_HEATING_UPDATE_INTERVAL 		= 1;		//! update interval duration of heating process (seconds)
	const float PARAM_MAX_TRANSFERED_TEMPERATURE	= 5;		//! maximum value for temperature that will be transfered to player (environment)
	const float PARAM_DRY_MODIFIER					= 1.125;
	
	void FlammableBase()
	{
		Init();
	}
	
	private SoundOnVehicle	m_LoopSoundEntity;
	Particle 				m_FireParticle;
	bool					m_CanReceiveUpgrade; // Synchronized variable
	bool					m_IsBeingDestructed = false;
	
	float 					m_BurnTimePerRagEx;
	float 					m_BurnTimePerFullLardEx;
	float 					m_BurnTimePerFullFuelDoseEx;
	float 					m_MaxConsumableLardQuantityEx;
	float 					m_MaxConsumableFuelQuantityEx;
	float 					m_WaterEvaporationByFireIntensityEx = 0.001;
	int 					m_StartFadeOutOfLightAtQuantityEx = 3;
	
	int 					m_RagsUpgradedCount;//how many rags were upgraded with fuel/lard
	bool					m_ConsumeRagFlipFlop;//are we burning rag or fuel/lard
	vector 					m_ParticleLocalPos = Vector(0, 0.50, 0);
	
	string					m_DecraftResult = "WoodenStick";
	TorchLight				m_Light;
	bool					m_WasLit;//was this item ever lit ? (used for correct material setting after reconnect for extinguished flammable items)
	
	protected ref UniversalTemperatureSource m_UTSource;
	protected ref UniversalTemperatureSourceSettings m_UTSSettings;
	protected ref UniversalTemperatureSourceLambdaConstant m_UTSLConstant;
	
	override void DeferredInit()
	{
		if(m_RagsUpgradedCount)
		{
			LockRags(true);
		}
	}
	
	void Init()
	{
		if ( m_BurnTimePerRagEx == 0 || m_BurnTimePerFullLardEx == 0 || m_MaxConsumableLardQuantityEx == 0 || m_MaxConsumableFuelQuantityEx == 0 )
		{
			string cfg_path = "CfgVehicles " + GetType();
			m_BurnTimePerRagEx = g_Game.ConfigGetFloat( cfg_path + " burnTimePerRag" );
			m_BurnTimePerFullLardEx = g_Game.ConfigGetFloat( cfg_path + " burnTimePerFullLardDose" );
			m_BurnTimePerFullFuelDoseEx = g_Game.ConfigGetFloat( cfg_path + " burnTimePerFullFuelDose" );
			m_MaxConsumableLardQuantityEx = g_Game.ConfigGetFloat( cfg_path + " maxConsumableLardDose" );
			m_MaxConsumableFuelQuantityEx = g_Game.ConfigGetFloat( cfg_path + " maxConsumableFuelDose" );
		}
		RegisterNetSyncVariableBool("m_CanReceiveUpgrade");
	}
	
	override void EEInit()
	{		
		super.EEInit();
		
		if (g_Game.IsServer() || !g_Game.IsMultiplayer())
		{
 			m_UTSSettings 						= new UniversalTemperatureSourceSettings();
			m_UTSSettings.m_Updateable			= true;
			m_UTSSettings.m_UpdateInterval		= TIMER_HEATING_UPDATE_INTERVAL;
			m_UTSSettings.m_TemperatureItemCap 	= GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_MIDDLE;
			m_UTSSettings.m_TemperatureCap		= PARAM_MAX_TRANSFERED_TEMPERATURE;
			m_UTSSettings.m_RangeFull			= PARAM_FULL_HEAT_RADIUS;
			m_UTSSettings.m_RangeMax			= PARAM_HEAT_RADIUS;
			m_UTSSettings.m_ItemDryModifier		= PARAM_DRY_MODIFIER;
			
			m_UTSLConstant					= new UniversalTemperatureSourceLambdaConstant();
			m_UTSource						= new UniversalTemperatureSource(this, m_UTSSettings, m_UTSLConstant);
		}

	}
	
	override vector GetUniversalTemperatureSourcePosition()
	{
		if (GetHierarchyRoot())
		{
			return GetHierarchyRoot().GetPosition();
		}

		return super.GetPosition();
	}
	
	override void EEDelete(EntityAI parent)
	{
		super.EEDelete(parent);
		if ( m_LoopSoundEntity != NULL && g_Game != NULL )
		{
			g_Game.ObjectDelete( m_LoopSoundEntity );
		}
		
		StopAllParticles();
	}

	override bool CanReceiveAttachment(EntityAI attachment, int slotId)
	{
		ItemBase att = ItemBase.Cast(GetInventory().FindAttachment(slotId));
		if (att && att.IsFullQuantity())
			return false;
		
		return super.CanReceiveAttachment(attachment, slotId);
	}
	
	override bool CanPutInCargo( EntityAI parent )
	{
		if( !super.CanPutInCargo(parent) ) {return false;}
		return CanBeTakenAsCargo();
	}
	
	override bool CanReleaseAttachment(EntityAI attachment)
	{
		if( !super.CanReleaseAttachment( attachment ) )
			return false;
		return !GetCompEM().IsWorking();
	}
	
	override bool CanRemoveFromCargo(EntityAI parent)
	{
		return CanBeTakenAsCargo();
	}
	
	override bool CanPutAsAttachment (EntityAI parent)
	{
		return !GetCompEM().IsWorking();
	}
	
	bool CanBeTakenAsCargo()
	{
		// Don't let players burn their pockets!
		return !GetCompEM().IsWorking();
	}
	
	override bool IsIgnited()
	{
		return GetCompEM().IsWorking();
	}
	
	override bool CanIgniteItem(EntityAI ignite_target = NULL)
	{
		return GetCompEM().IsWorking();
	}
	
	override bool HasFlammableMaterial()
	{
		return true;
	}
	
	// Checkes if Torch can be ignited
	override bool CanBeIgnitedBy(EntityAI igniter = NULL)
	{
		if ( !GetCompEM().CheckWetness() )
			return false;
		
		ItemBase rag = GetRag();
				
		if (rag  &&  GetCompEM().GetEnergy() < GetCompEM().GetEnergyUsage() * GetCompEM().GetUpdateInterval() )
		{			
			if (IsRagDryEnough(rag))
				return false;
		}
		
		if ( !GetCompEM().CanWork() )
			return false;
		
		if ( GetCompEM().GetEnergy() < 3 )
			return false;
		
		PlayerBase player = PlayerBase.Cast(GetHierarchyRootPlayer());
		if (player)
		{
			if (this != player.GetItemInHands())//we are in player's inventory, but not in his hands
			{
				return false;
			}
		}
		
		return true;
	}
	
	bool IsRagDryEnough(ItemBase rag)
	{
		float wetness = rag.GetWet();
		bool is_dry_enough = wetness <= 1-GetCompEM().GetWetnessExposure();
		return is_dry_enough;
	}
	
	void UpdateCheckForReceivingUpgrade()
	{
		if ( g_Game.IsServer() || !g_Game.IsMultiplayer() )
		{
			m_CanReceiveUpgrade = GetRagQuantity() > 0 && m_RagsUpgradedCount < GetRagQuantity() || (m_BurnTimePerRagEx * (m_RagsUpgradedCount + GetRagQuantity()) - GetCompEM().GetEnergy()) > 1;
			SetSynchDirty();
		}
	}
	
	override void OnIgnitedThis(EntityAI fire_source)
	{
		if ( !GetCompEM().HasEnoughStoredEnergy() )
		{
			ConsumeRag();
		}
		
		GetCompEM().SwitchOn();
	}
	
	override void OnSwitchOn()
	{
		if (!GetCompEM().HasEnoughStoredEnergy())
		{
			GetCompEM().SwitchOff();
		}
		
		if (g_Game.IsServer() || !g_Game.IsMultiplayer())
		{
			m_UTSource.SetActive(true);
		}
	}
	
	override void OnSwitchOff()
	{
		if (g_Game.IsServer() || !g_Game.IsMultiplayer())
		{
			m_UTSource.SetActive(false);
		}
	}
	
	void SetTorchDecraftResult(string type)
	{
		m_DecraftResult = type; //not persistent for the moment
	}
	
	bool ConsumeRag()
	{
		ItemBase rag = GetRag();
		
		if (rag)
		{
			if (rag.GetQuantity() <= 1)
			{
				LockRags(false); // Unlock attachment slot before deletion. Otherwise it will get stuck locked and unusable.
			}
			
			rag.AddQuantity(-1);
			rag.SetHealth(0);
			//GetCompEM().AddEnergy( m_BurnTimePerRagEx );
			return true;
		}
		
		return false;
	}
	
	void ConsumeLard(Lard lard)
	{
		if (lard)
		{
			float lard_quant = lard.GetQuantity();
			
			float available_lard_quant = lard_quant;
			
			if ( available_lard_quant > m_MaxConsumableLardQuantityEx )
				available_lard_quant = m_MaxConsumableLardQuantityEx;
			
			float available_lard_coef = available_lard_quant / m_MaxConsumableLardQuantityEx;
			
			float add_energy = m_BurnTimePerFullLardEx * available_lard_coef;
			float add_energy_coef = 1;
			
			float energy_limit = GetCompEM().GetEnergyMax() - GetCompEM().GetEnergy();
			
			if (add_energy > energy_limit )
			{
				add_energy_coef = energy_limit / add_energy;
				add_energy = energy_limit;
				available_lard_quant = available_lard_quant * add_energy_coef;
			}
			
			GetCompEM().AddEnergy( add_energy );
			lard.AddQuantity(-available_lard_quant);
			
			CalculateQuantity();
			
			UpdateCheckForReceivingUpgrade();
		}
	}

	void Upgrade(ItemBase source)
	{
		if (!GetRag())
		{
			return;
		}
		RuinRags();
		LockRags(true);
		float torchCurrentEnergy = GetCompEM().GetEnergy();
		float sourceQuantity = 100000;//for upgrade from environment(gas pump)
		
		if (source)
		{
			sourceQuantity = source.GetQuantity();
		}
		
		float maxOverallCapacity = GetRagQuantity() * 2 * m_BurnTimePerRagEx;
		//float maxUpgradeCapacity = GetRagQuantity() * m_BurnTimePerRagEx;
		float currentlyUpgraded =  Math.Max(0, torchCurrentEnergy - (GetRagQuantity() * m_BurnTimePerRagEx));
		//float freeUpgradeCapacity = maxUpgradeCapacity - currentlyUpgraded;
		float freeUpgradeCapacity = maxOverallCapacity - torchCurrentEnergy;
		float upgradeQuantity = Math.Min(freeUpgradeCapacity, sourceQuantity);
		int upgradedRags = Math.Ceil((upgradeQuantity + currentlyUpgraded) / m_BurnTimePerRagEx);
		upgradedRags = Math.Min(GetRagQuantity(), upgradedRags);
		m_RagsUpgradedCount = upgradedRags;
		GetCompEM().AddEnergy(upgradeQuantity);
		m_ConsumeRagFlipFlop = 0;//consume fuel first
		if (source)
		{
			source.AddQuantity(-upgradeQuantity);
		}
		CalculateQuantity();
		UpdateCheckForReceivingUpgrade();
	}
	
	
	
	void ConsumeFuelFromBottle(ItemBase vessel)
	{
		if (vessel)
		{
			float vessel_quant = vessel.GetQuantity();
			
			float available_vessel_quant = vessel_quant;
			
			if ( available_vessel_quant > m_MaxConsumableFuelQuantityEx )
				available_vessel_quant = m_MaxConsumableFuelQuantityEx;
			
			float available_vessel_coef = available_vessel_quant / m_MaxConsumableFuelQuantityEx;
			
			float add_energy = m_BurnTimePerFullFuelDoseEx * available_vessel_coef;
			float add_energy_coef = 1;
			
			float energy_limit = GetCompEM().GetEnergyMax() - GetCompEM().GetEnergy();
			
			if (add_energy > energy_limit )
			{
				add_energy_coef = energy_limit / add_energy;
				add_energy = energy_limit;
				available_vessel_quant = available_vessel_quant * add_energy_coef;
			}
			
			GetCompEM().AddEnergy( add_energy );
			vessel.AddQuantity(-available_vessel_quant);
			
			CalculateQuantity();
			
			UpdateCheckForReceivingUpgrade();
		}
	}
	
	void ConsumeFuelFromGasStation()
	{
		float add_energy = m_BurnTimePerFullFuelDoseEx;
		float add_energy_coef = 1;
		
		float energy_limit = GetCompEM().GetEnergyMax() - GetCompEM().GetEnergy();
		
		if (add_energy > energy_limit )
		{
			add_energy_coef = energy_limit / add_energy;
			add_energy = energy_limit;
		}
		
		GetCompEM().AddEnergy( add_energy );
		CalculateQuantity();
		UpdateCheckForReceivingUpgrade();
	}
	
	void RuinRags()
	{
		ItemBase rag = GetRag();
		
		if (rag)
		{
			rag.SetHealth(1); //does not actually ruin rags, combining would be impossible
		}
	}
	
	// Inventory manipulation
	override void OnInventoryExit(Man player)
	{
		super.OnInventoryExit(player);
		
		StandUp();
	}
	
	// Stands up the torch, if possible. Returns true on success.
	bool StandUp()
	{
		string surface_type;
		vector position = GetPosition();
		g_Game.SurfaceGetType ( position[0], position[2], surface_type );
		bool is_surface_soft = g_Game.IsSurfaceDigable(surface_type);
		
		if ( is_surface_soft && !IsRuined() )
		{
			vector ori_rotate = "0 0 0";
			ori_rotate[0] = Math.RandomFloat(0, 360);
			ori_rotate[1] = Math.RandomFloat(0, 10);
			SetOrientation(ori_rotate);
			
			return true; // I am standing up
		}
		
		return false; // I am NOT standing up
	}
	
	void CalculateQuantity()
	{
		if (g_Game.IsServer() || !g_Game.IsMultiplayer())
		{
			SetQuantityNormalized(GetCompEM().GetEnergy0To1());
		}
	}

	bool CanReceiveUpgrade()
	{
		return m_CanReceiveUpgrade;
	}
	
	void CraftingInit(float quantity)
	{
		GetCompEM().SetEnergy(m_BurnTimePerRagEx * quantity);
		m_CanReceiveUpgrade = true;
		SetSynchDirty();
	}
	
	
	override void EEItemAttached( EntityAI item, string slot_name ) 
	{
		super.EEItemAttached( item, slot_name );
		CalculateQuantity();
		UpdateCheckForReceivingUpgrade();
	}
	
	
	override void EEItemDetached( EntityAI item, string slot_name ) 
	{
		super.EEItemDetached( item, slot_name );

		if (m_IsBeingDestructed)
		{
			if (g_Game.IsServer() || !g_Game.IsMultiplayer())
			{
				EntityAI rags = EntityAI.Cast(g_Game.CreateObjectEx(item.GetType(), GetPosition(), ECE_PLACE_ON_SURFACE));
				if( rags )
					MiscGameplayFunctions.TransferItemProperties(item, rags);
			}
			return;
		}
		
		CalculateQuantity();
		UpdateCheckForReceivingUpgrade();
		g_Game.GetCallQueue( CALL_CATEGORY_SYSTEM ).CallLater( TryTransformIntoStick, 100);
	}
	
	bool CanTransformIntoStick()
	{
		if ((g_Game.IsServer() || !g_Game.IsMultiplayer()) && !IsIgnited() && !GetRag() && !IsSetForDeletion() )
			return true;
		else
			return false;
	}
	
	void TryTransformIntoStick()
	{
		PlayerBase player = PlayerBase.Cast(GetHierarchyRootPlayer());
		if ( m_IsBeingDestructed || (player && player.IsPlayerDisconnected()) )
			return;
				
		if ( CanTransformIntoStick() )
		{
			m_IsBeingDestructed = true;
			if (player)
			{
				// Transform object into wooden stick
				StopAllParticles();
				
				TorchLambda lambda = new TorchLambda(this, m_DecraftResult);
				player.ServerReplaceItemInHandsWithNew(lambda);
			}
			else
			{
				// Create wooden stick and delete Torch
				vector pos = GetPosition();
				vector ori = GetOrientation();
				
				if ( GetType() == "WoodenStick" )
					ori = ori + Vector(0,90,0);
				
				ItemBase stick = ItemBase.Cast( g_Game.CreateObjectEx(m_DecraftResult, pos, ECE_PLACE_ON_SURFACE) );
				ApplyResultModifications(stick);
				stick.SetPosition(pos);
				stick.PlaceOnSurface();
				
				if ( stick.GetType() == "LongWoodenStick" )
				{
					pos = stick.GetPosition() + Vector(0,-0.3,0);
					stick.SetPosition(pos);
				}
				
				stick.SetOrientation(ori);
				g_Game.ObjectDelete(this);
			}
		}
	}
	
	
	override void OnWorkStart()
	{
		m_WasLit = true;
		LockRags(true);
		UpdateMaterial();
	}
	
	void StopAllParticles()
	{
		if (m_FireParticle)
		{
			m_FireParticle.Stop();
		}
	}
	
	Rag GetRag()
	{
		return Rag.Cast( GetAttachmentByType(Rag) );
	}
	
	void LockRags(bool do_lock)
	{
		ItemBase rag = GetRag();
		if (rag)
		{
			if (do_lock)
			{
				rag.LockToParent();
			}
			else if (!m_RagsUpgradedCount)
			{
				rag.UnlockFromParent();
			}
		}
	}
	
	void UpdateLight()
	{
		if (!m_Light)
		{
			m_Light = TorchLight.Cast( ScriptedLightBase.CreateLight( TorchLight, Vector(0,0,0), 1 ) );
			m_Light.AttachOnObject(this, m_ParticleLocalPos + Vector (0,0.2,0));
		}
		
		if (m_FireParticle)
		{
			Object direct_particle = m_FireParticle.GetDirectParticleEffect();
			
			if (direct_particle  &&  direct_particle != m_Light.GetAttachmentParent())
			{
				m_Light.AttachOnObject(direct_particle, Vector(0,0.2,0));
			}	
		}
		
		float update_interval = GetCompEM().GetUpdateInterval();
		
		if (GetQuantity() <= m_StartFadeOutOfLightAtQuantityEx)
		{
			float brightness_coef = GetQuantity() / m_StartFadeOutOfLightAtQuantityEx;
			float radius_coef = GetQuantity() / m_StartFadeOutOfLightAtQuantityEx;
			
			if (radius_coef < m_StartFadeOutOfLightAtQuantityEx/10)
				radius_coef = m_StartFadeOutOfLightAtQuantityEx/10;
			
			if (brightness_coef < m_StartFadeOutOfLightAtQuantityEx/10)
				brightness_coef = m_StartFadeOutOfLightAtQuantityEx/10;
			
			m_Light.FadeBrightnessTo(m_Light.m_TorchBrightness * brightness_coef, update_interval);
			m_Light.FadeRadiusTo(m_Light.m_TorchRadius * radius_coef, update_interval);
		}
		else
		{
			m_Light.FadeBrightnessTo(m_Light.m_TorchBrightness, update_interval);
			m_Light.FadeRadiusTo(m_Light.m_TorchRadius, update_interval);
		}
	}

	override void OnItemInHandsPlayerSwimStart(PlayerBase player)
	{
		GetCompEM().SwitchOff();
	}
	
	
	override void OnWork( float consumed_energy )
	{
		UpdateMaterial();
		if (g_Game.IsServer() || !g_Game.IsMultiplayer())
		{
			if (GetCompEM().GetEnergy() < ((GetRagQuantity() + m_RagsUpgradedCount) - 1) * m_BurnTimePerRagEx)
			{
				if (m_RagsUpgradedCount==0)//always burn rag
				{
					ConsumeRag();
				}
				else if (m_ConsumeRagFlipFlop)//burn rag
				{
					ConsumeRag();
					m_ConsumeRagFlipFlop = !m_ConsumeRagFlipFlop;
				}
				else//burn lard/fuel
				{
					m_RagsUpgradedCount--;
					m_ConsumeRagFlipFlop = !m_ConsumeRagFlipFlop;
				}
			}
			if (GetRag() && GetCompEM().GetEnergy() == 0 && GetRagQuantity() > 0)
			{
				GetRag().SetQuantity(0);
			}
			RuinRags();
			
			CalculateQuantity();
			
			UpdateCheckForReceivingUpgrade();
			
			AddWet( -m_WaterEvaporationByFireIntensityEx * GetCompEM().GetUpdateInterval() );
			
			Rag rag = GetRag();
			
			if ( rag )
			{
				rag.AddWet( -m_WaterEvaporationByFireIntensityEx * GetCompEM().GetUpdateInterval() );
			}
		}
		
		if ( !m_LoopSoundEntity && g_Game && ( !g_Game.IsDedicatedServer() ) )
		{
			m_LoopSoundEntity = PlaySoundLoop(GetSoundName(), 50);
		}
		
		// Effect scaling by fuel
		if ( !g_Game.IsDedicatedServer() )
		{
			UpdateLight();
			UpdateParticle();
		}
	}
	
	
	string GetSoundName()
	{
		return "torchLoop";
	}
	
	void UpdateParticle()
	{
		if ( GetQuantity() < 40 )
		{
			if (!m_FireParticle)
				m_FireParticle = ParticleManager.GetInstance().PlayOnObject(ParticleList.TORCH_T1, this, m_ParticleLocalPos);
			
			float scale = GetQuantity() / 40;
			
			if (scale > 1)
				scale = 1;
			
			if (scale < 0.25)
				scale = 0.25;
			
			m_FireParticle.ScaleParticleParamFromOriginal(EmitorParam.SIZE, scale);
			m_FireParticle.ScaleParticleParamFromOriginal(EmitorParam.VELOCITY, scale);
			m_FireParticle.ScaleParticleParamFromOriginal(EmitorParam.VELOCITY_RND, scale);
		}
		else
		{
			if ( !m_FireParticle  ||  m_FireParticle.GetParticleID() != ParticleList.TORCH_T2 )
			{
				// Executes once when fire particle starts or changes
				
				if (m_FireParticle)
					m_FireParticle.Stop();
				
				m_FireParticle = ParticleManager.GetInstance().PlayOnObject(ParticleList.TORCH_T2, this, m_ParticleLocalPos);
			}
		}
	
	}
	
	override void OnWorkStop()
	{
		UpdateMaterial();
		if (m_Light)
			m_Light.FadeOut();
		
		if ( m_LoopSoundEntity && g_Game && ( !g_Game.IsDedicatedServer() ) )
		{
			g_Game.ObjectDelete( m_LoopSoundEntity );
			m_LoopSoundEntity = NULL;
		}
		
		if ( m_FireParticle)
		{
			m_FireParticle.Stop();
			m_FireParticle = NULL;
		}
		
		CalculateQuantity();
		UpdateCheckForReceivingUpgrade();
		
		LockRags(false);
		
		if (g_Game.IsServer() || !g_Game.IsMultiplayer())
		{
			if (GetRag() && GetCompEM().GetEnergy() == 0 && GetRagQuantity() > 0)
			{
				GetRag().SetQuantity(0);
			}
		}
		
		TryTransformIntoStick();
	}
	
	// COMBAT
	// This needs refactor!
	override int GetMeleeMode()
	{
		if ( GetCompEM().IsWorking() )
			return 3; // ???
		else
			return 0; // ???
	}

	override int GetMeleeHeavyMode()
	{
		if ( GetCompEM().IsWorking() )
			return 4; // ???
		else
			return 1; // ???
	}
	
	override int GetMeleeSprintMode()
	{
		if ( GetCompEM().IsWorking() )
			return 5; // ???
		else
			return 2; // ???
	}
	
	override void SetActions()
	{
		super.SetActions();
		
		AddAction(ActionLightItemOnFire);
	}
	
	override void OnAttachmentQuantityChangedEx(ItemBase item, float delta)
	{
		super.OnAttachmentQuantityChangedEx(item, delta);
		if (delta != 0)
		{			
			if (delta > 0 || !GetCompEM().IsWorking())	// dont adjust energy when rag burns out
				GetCompEM().AddEnergy(m_BurnTimePerRagEx * delta);
			
			CalculateQuantity();
			UpdateCheckForReceivingUpgrade();
		}
	}
		
	
	override bool DisassembleOnLastDetach()
	{
		return true;
	}
	
	override void OnDebugSpawn()
	{
		GetInventory().CreateAttachment("Rag");
		CraftingInit(GetRagQuantity());
		CalculateQuantity();
	}
	
	int GetRagQuantity()
	{
		if (GetRag())
		{
			return Math.Round(GetRag().GetQuantity());
		}
		return 0;
	}
	
	string GetBurningMaterial()
	{
		return "";
	}
	
	string GetBurntMaterial()
	{
		return "";
	}
	
	void UpdateMaterial()
	{
		if (g_Game.IsServer() || !g_Game.IsMultiplayer())
		{
			if (GetCompEM().IsWorking())
			{
				if (GetBurningMaterial())
				{
					SetObjectMaterial(0, GetBurningMaterial());
				}
			}
			else if (m_WasLit)
			{
				if (GetBurntMaterial())
				{
					SetObjectMaterial(0, GetBurntMaterial());
				}
			}
		}
	}
	
	
	override void OnStoreSave(ParamsWriteContext ctx)
	{
		super.OnStoreSave(ctx);
		ctx.Write(m_WasLit);
	}
	
	
	override bool OnStoreLoad( ParamsReadContext ctx, int version )
	{
		if (!super.OnStoreLoad(ctx, version))
		{
			return false;
		}
		if (version >= 130)
		{
			if (!ctx.Read( m_WasLit ))
			{
				return false;
			}
		}
		UpdateMaterial();
		return true;
	}
	
	void ApplyResultModifications(ItemBase result)
	{
		result.SetQuantity(1);
	}
	
	//-------------
	// DEBUG BELLOW
	//-------------
	#ifdef DEVELOPER
	override void GetDebugActions(out TSelectableActionInfoArrayEx outputList)
	{
		outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.ACTIVATE_ENTITY, "Ignite", FadeColors.LIGHT_GREY));
		outputList.Insert(new TSelectableActionInfoWithColor(SAT_DEBUG_ACTION, EActions.SEPARATOR, "___________________________", FadeColors.RED));
		
		super.GetDebugActions(outputList);
	}
	
	override bool OnAction(int action_id, Man player, ParamsReadContext ctx)
	{
		if (super.OnAction(action_id, player, ctx))
			return true;
		if (g_Game.IsServer() || !g_Game.IsMultiplayer())
		{
			if (action_id == EActions.ACTIVATE_ENTITY)
			{
				OnIgnitedThis(null);
			}
			
		}
		return false;
	}

	override string GetDebugText()
	{
		string debug_output;

		debug_output = super.GetDebugText();
		
		if( g_Game.IsDedicatedServer())
		{
			debug_output+="m_RagsUpgradedCount:"+m_RagsUpgradedCount+"\n";
			debug_output+="m_ConsumeRagFlipFlop:"+m_ConsumeRagFlipFlop+"\n";
			if (IsIgnited() && m_ConsumeRagFlipFlop)
			{
				debug_output+="Burning rag \n";
			}
			else if (IsIgnited())
			{
				debug_output+="Burning lard/fuel \n";
			}
		}
		else
		{
			
		}
		return debug_output;
	}
	#endif
}


class Torch : FlammableBase
{
	//legacy vars which cannot be moved/removed
	static float 			m_BurnTimePerRag;
	static float 			m_BurnTimePerFullLard;
	static float 			m_BurnTimePerFullFuelDose;
	static float 			m_MaxConsumableLardQuantity;
	static float 			m_MaxConsumableFuelQuantity;
	static float 			m_WaterEvaporationByFireIntensity = 0.001;
	static int 				m_StartFadeOutOfLightAtQuantity = 3;
	

	override void Init()
	{
		super.Init();
		
		//for legacy reasons
		m_BurnTimePerRag = m_BurnTimePerRagEx;
		m_BurnTimePerFullLard = m_BurnTimePerFullLardEx;
		m_BurnTimePerFullFuelDose = m_BurnTimePerFullFuelDoseEx;
		m_MaxConsumableLardQuantity = m_MaxConsumableLardQuantityEx;
		m_MaxConsumableFuelQuantity = m_MaxConsumableFuelQuantityEx;
	}
	
	override void SetActions()
	{
		super.SetActions();
		
		AddAction(ActionUpgradeTorchFromGasPump);
		AddAction(ActionRefuelTorch);
	}
	
	// !Called on CHILD when it's attached to parent.
	override void OnWasAttached( EntityAI parent, int slot_id )
	{
		super.OnWasAttached(parent, slot_id);
		if (g_Game.IsServer() || !g_Game.IsMultiplayer())
			LockRags(true);
	}
		
	// !Called on CHILD when it's detached from parent.
	override void OnWasDetached( EntityAI parent, int slot_id )
	{
		super.OnWasDetached(parent, slot_id);
		if (g_Game.IsServer() || !g_Game.IsMultiplayer())
			LockRags(false);
	}
	
	
	override void OnStoreSave(ParamsWriteContext ctx)
	{
		super.OnStoreSave(ctx);
		ctx.Write(m_ConsumeRagFlipFlop);
		ctx.Write(m_RagsUpgradedCount);
	}
	
	
	override bool OnStoreLoad( ParamsReadContext ctx, int version )
	{
		if (!super.OnStoreLoad(ctx, version))
		{
			return false;
		}
		
		if (version >= 129)
		{
			if (!ctx.Read( m_ConsumeRagFlipFlop ))
			{
				return false;
			}
		
			if (!ctx.Read( m_RagsUpgradedCount ))
			{
				return false;
			}
		}
		UpdateCheckForReceivingUpgrade();
		return true;
	}
};

class TorchLambda : ReplaceItemWithNewLambdaBase
{
	override void CopyOldPropertiesToNew (notnull EntityAI old_item, EntityAI new_item)
	{
		super.CopyOldPropertiesToNew(old_item, new_item);

		ItemBase stick;
		FlammableBase flammable = FlammableBase.Cast(old_item);
		Class.CastTo(stick, new_item);
		if (stick && flammable)
		{
			flammable.ApplyResultModifications(stick);
		}
	}
};