DIFF

constructionparttyped.c

//! static parts info, lives on EntityType level. Instanced data in 'ConstructionPart' class
class ConstructionPartTypeData
{
	protected string 	m_Name;				//un-localized text name that is displayed ingame. Localized via getter method.
	protected string 	m_PartName;			//config class name
	protected string 	m_MainPartName;		//main (parent) config class name
	protected string 	m_PartPath; //raw part path, stored for deferred init
	protected typename 	m_CustomInstanceTypename; //set only for custom types, contains type of custom part instances
	protected int		m_Id;				//a number used for synchronization and persistence purposes, must be unique and withing sync limit (total number of bits in all sync/persistence variables)
	protected int 		m_BuildActionTypeMask; //values from EConstructionTools
	protected int 		m_BuildIndicationTypeMask; //values from EConstructionTools, used for indication only!
	protected int 		m_DismantleActionTypeMask; //values from EConstructionTools
	protected int 		m_MaterialType; //used for determinig effect type (wood vs. metal sounds, for example)
	protected int 		m_HandFBAnimOverride = -1; //override ID of the FB animation for hand construction (tool anims are driven by tools)
	protected bool 		m_IsBase;			//defines if this part is the foundation of the whole construction
	protected bool 		m_IsGate;			//defines part gate state
	protected bool 		m_IsUtilityPart; //! Special helper parts with invalid IDs
	protected bool 		m_DamageHandsOnBuild;
	protected bool 		m_CanPartDecayConfig; //! determined by, in sequence: 'can_decay_general' in class Construction > 'can_decay' on the part itself
	protected float 	m_PartDecayThresholdConfig;
	protected float 	m_PartDecayRateConfig;
	protected ref array<string> m_RequiredPartTypes; //list of part types required by this part
	protected ref array<string> m_ConflictedPartTypes; //list of part types conflicting with this one
	protected ref array<string> m_CollisionData; //Names of min/max memory point selections
	protected ref array<string> m_InsiderBoxPairNames; //Names of min/max pairs for insider box considerations
	protected ref array<string> m_ItemFallingData; //Names of min/max memory point selections
	protected ref array<string> m_EssentialAttachmentSlots; //Names of att. slots that are tied to the constructed part in some way
	protected ref array<string> m_RelatedGUICategoryNames; //listing of related 'GUIInventoryAttachmentsProps' subclasses (part is required to display them, in this iteration)
	protected ref array<ref ConstructionMaterialData> m_MaterialsData;
	
	//rebuilding data below
	protected string m_BuildTextOverride = "";
	protected string m_DismantleTextOverride = "";
	protected ref array<string> m_PhxGeomNames;	//used in 'Handle<operation>Physics' methods instead m_PartName
	protected ref array<int> m_PhxGeomBehaviorInverted;	//dictates behavior of geom selections from 'm_PhxGeomNames'. 0 == matches the phase of the animation, non-zero == inverted
	protected ref array<string> m_ProxyRoadwayNames;	//used in 'Handle<operation>ProxyRoadways' methods instead m_PartName
	protected ref array<int> m_ProxyRoadwayBehaviorInverted;	//dictates behavior of ProxyRoadway from 'm_ProxyRoadwayNames'. 0 == matches the phase of the animation, non-zero == inverted
	protected ref array<string> m_AnimSourceNameOverrides;	//used by 'SetAnimationPhase' instead of m_PartName
	protected ref array<int> m_AnimSourceBehaviorOverridesInverted;	//dictates behavior of animSources from 'm_AnimSourceNameOverrides'. 0 == matches the hide/show state of the animation, non-zero == inverted
	protected ref array<string> m_UtilityAutomaticBuild;
	protected ref TConstructionPartVariantArray m_ReqPartVariants;
	protected ref ConstructionPartStaticsSupportData m_StaticsData;
	protected ref ConstructionPartEffectsData m_EffectsData;
	
	void InitPartTypeData(PartTypeInitData initData)
	{
		m_PartPath = initData.m_PartPath;
		
		InitBasicStrings(initData);
		InitRequiredParts();
		InitActionMasks();
		InitPartMaterials();
		InitMaterialType();
		InitConflictedParts();
		InitCollisionData();
		InitInsiderBoxData();
		InitItemFallingData();
		InitPartDecayData();
		InitHandAnimOverride();
		InitEssentialAttachmentSlots();
		InitGuiAttachmentCategoryLinks();
		InitConstructionActionDamage();
		InitUtilityPartInfo();
		InitUtilityBuildData();
		InitRequiredPartVariants();
		InitStaticsSupportPartData();
		InitPartEffectsData();
		InitOptionalOverrides();
		InitCustomPartTypeProperties(initData);
	}
	
	/////////////////
	//Protected Inits
	/////////////////
	protected void InitBasicStrings(PartTypeInitData partTypeData)
	{
		string name = "";
		g_Game.ConfigGetTextRaw(m_PartPath + " name", name);
		g_Game.FormatRawConfigStringKeys(name);
		m_Name = name;
		m_PartName = partTypeData.m_PartName;
		m_MainPartName = partTypeData.m_MainPartName;
		m_Id = g_Game.ConfigGetInt(m_PartPath + " id");
		m_IsBase = g_Game.ConfigGetInt(m_PartPath + " is_base");
		m_IsGate = g_Game.ConfigGetInt(m_PartPath + " is_gate");
	}
	
	protected void InitRequiredParts()
	{
		string cfgPath = m_PartPath + " required_parts";
		m_RequiredPartTypes = new array<string>();
		g_Game.ConfigGetTextArray(cfgPath, m_RequiredPartTypes);
	}
	
	protected void InitActionMasks()
	{
		string path = m_PartPath + " build_action_type";
		if (g_Game.ConfigIsExisting(path))
		{
			m_BuildActionTypeMask = g_Game.ConfigGetInt(path);
			SanitizeBuildIndicationMask();
		}
		
		path = m_PartPath + " dismantle_action_type";
		if (g_Game.ConfigIsExisting(path))
			m_DismantleActionTypeMask = g_Game.ConfigGetInt(path);
	}
	
	protected void InitPartMaterials()
	{
		m_MaterialsData = new array<ref ConstructionMaterialData>();
		
		string path = m_PartPath + " Materials";
		if (g_Game.ConfigIsExisting(path))
		{
			int	count = g_Game.ConfigGetChildrenCount(path);
			for (int i = 0; i < count; ++i)
			{
				string childName;
				g_Game.ConfigGetChildName(path, i, childName);
				
				string matPath = path + " " + childName;
				ConstructionMaterialData dataObj = new ConstructionMaterialData(matPath);
				m_MaterialsData.Insert(dataObj);
			}
		}
	}
	
	protected void InitMaterialType()
	{
		m_MaterialType = ConstructionMaterialType.MATERIAL_NONE;
		string path = m_PartPath + " material_type";
		if (g_Game.ConfigIsExisting(path))
		{
			m_MaterialType = g_Game.ConfigGetInt(path);
		}
	}
	
	protected void InitConflictedParts()
	{
		string path = m_PartPath + " conflicted_parts";
		m_ConflictedPartTypes = new array<string>();
		g_Game.ConfigGetTextArray(path, m_ConflictedPartTypes);
	}
	
	//! collision checks when building, if configured
	protected void InitCollisionData()
	{
		//collision box data
		m_CollisionData = new array<string>();
		string path = m_PartPath + " collision_data";
		if (g_Game.ConfigIsExisting(path))
		{
			g_Game.ConfigGetTextArray(path, m_CollisionData);
		}
	}
	
	//! 'inside' box data to help determine whether the character is inside. Modelspace.
	protected void InitInsiderBoxData()
	{
		//insider box data
		string path = m_PartPath + " insider_minMaxs";
		if (g_Game.ConfigIsExisting(path))
		{
			//read from config and validate
			array<string> tmp = new array<string>();
			g_Game.ConfigGetTextArray(path, tmp);
			
			int count = tmp.Count();
			if (count == 0)
			{
				tmp = null;
				return;
			}
			else if (count % 2 != 0)
			{
				ErrorEx("odd number of insider_minMaxs configured for " + m_PartPath);
				tmp = null;
				return;
			}
			
			m_InsiderBoxPairNames = new array<string>();
			m_InsiderBoxPairNames.Copy(tmp);
		}
	}
	
	//! item falling on dismantle/destruct, if configured.
	protected void InitItemFallingData()
	{
		m_ItemFallingData = new array<string>();
		string path = m_PartPath + " item_falling_data";
		if (g_Game.ConfigIsExisting(path))
		{
			g_Game.ConfigGetTextArray(path, m_ItemFallingData);
		}
	}
	
	//
	protected void InitPartDecayData()
	{
		//can decay
		string path = m_PartPath + " can_part_decay";
		if (g_Game.ConfigIsExisting(path))
			SetCanDecayConfig(g_Game.ConfigGetInt(path));
		
		//decay threshold
		m_PartDecayThresholdConfig = ConstructionBase.DEFAULT_DECAY_THRESHOLD;
		path = m_PartPath + " part_decay_threshold";
		if (g_Game.ConfigIsExisting(path))
			m_PartDecayThresholdConfig = g_Game.ConfigGetFloat(path);
		m_PartDecayThresholdConfig = Math.Clamp(m_PartDecayThresholdConfig, 0.0, 1.0);
		
		//decay rate
		m_PartDecayRateConfig = ConstructionBase.DEFAULT_DECAY_RATE;
		path = m_PartPath + " part_decay_rate";
		if (g_Game.ConfigIsExisting(path))
			m_PartDecayRateConfig = g_Game.ConfigGetFloat(path);
	}
	
	protected void InitHandAnimOverride()
	{
		string path = m_PartPath + " hand_build_FB_anim_override";
		if (g_Game.ConfigIsExisting(path))
			m_HandFBAnimOverride = g_Game.ConfigGetInt(path);
	}
	
	//! attachment slots somehow considered 'essential' to the part
	protected void InitEssentialAttachmentSlots()
	{
		m_EssentialAttachmentSlots = new array<string>();
		string path = m_PartPath + " essential_attachments";
		if (g_Game.ConfigIsExisting(path))
		{
			g_Game.ConfigGetTextArray(path, m_EssentialAttachmentSlots);
		}
	}
	
	//! which 'GUIInventoryAttachmentsProps' subclasses it relates to
	protected void InitGuiAttachmentCategoryLinks()
	{
		m_RelatedGUICategoryNames = new array<string>();
		string path = m_PartPath + " related_GUI_categories";
		if (g_Game.ConfigIsExisting(path))
		{
			g_Game.ConfigGetTextArray(path, m_RelatedGUICategoryNames);
		}
	}
	
	//! if hands get damaged on build (and possibly other overrides later)
	protected void InitConstructionActionDamage()
	{
		m_DamageHandsOnBuild = true;
		string path = m_PartPath + " damage_hands_on_build";
		if (g_Game.ConfigIsExisting(path))
		{
			m_DamageHandsOnBuild = g_Game.ConfigGetInt(path);
		}
	}
	
	protected void InitUtilityPartInfo()
	{
		string path = m_PartPath + " is_utility";
		m_IsUtilityPart = g_Game.ConfigGetInt(path);
	}
	
	protected void InitUtilityBuildData()
	{
		string path = m_PartPath + " utility_build";
		m_UtilityAutomaticBuild = {};
		if (g_Game.ConfigIsExisting(path))
		{
			g_Game.ConfigGetTextArray(path, m_UtilityAutomaticBuild);
		}
	}
	
	protected void InitRequiredPartVariants()
	{
		string path = m_PartPath + " RequiredPartsVariants";
		if (g_Game.ConfigIsExisting(path))
		{
			int count = g_Game.ConfigGetChildrenCount(path);
			if (count > 0)
			{
				if (!m_ReqPartVariants)
				{
					m_ReqPartVariants = new TConstructionPartVariantArray();
					
					for (int i = 0; i < count; ++i)
					{
						string variantPath = "";
						g_Game.ConfigGetChildName(path, i, variantPath);
						variantPath = path + " " + variantPath + " partVariants";
						array<string> tmp = new array<string>();
						g_Game.ConfigGetTextArray(variantPath, tmp);
						m_ReqPartVariants.Insert(tmp);
					}
				}
			}
		}
	}
	
	protected void InitStaticsSupportPartData()
	{
		m_StaticsData = new ConstructionPartStaticsSupportData();
		m_StaticsData.Init(m_PartPath);
	}
	
	//! 'partPath' not necessary here, using part data directly, override as needed on unique part handlers
	protected void InitPartEffectsData()
	{
		m_EffectsData = new ConstructionPartEffectsData();
		m_EffectsData.Init(m_PartPath, this);
	}
	
	protected void InitOptionalOverrides()
	{
		//strings
		string path = m_PartPath + " build_text_override";
		string tmpString = "";
		
		if (g_Game.ConfigIsExisting(path))
		{
			g_Game.ConfigGetTextRaw(path, tmpString);
			g_Game.FormatRawConfigStringKeys(tmpString);
		}
		m_BuildTextOverride = tmpString;
		
		path = m_PartPath + " dismantle_text_override";
		tmpString = "";
		if (g_Game.ConfigIsExisting(path))
		{
			g_Game.ConfigGetTextRaw(path, tmpString);
			g_Game.FormatRawConfigStringKeys(tmpString);
		}
		m_DismantleTextOverride = tmpString;
		/////////////////////////////////////////////////////////////
		//arrays
		//geoms
		path = m_PartPath + " physics_geom_names";
		m_PhxGeomNames = {};
		if (g_Game.ConfigIsExisting(path))
		{
			g_Game.ConfigGetTextArray(path, m_PhxGeomNames);
		}
		
		path = m_PartPath + " physics_geom_behaviors_invert";
		m_PhxGeomBehaviorInverted = {};
		if (g_Game.ConfigIsExisting(path))
		{
			g_Game.ConfigGetIntArray(path, m_PhxGeomBehaviorInverted);
		}
		
		//sanity check, just in case
		if (m_PhxGeomNames.Count() != m_PhxGeomBehaviorInverted.Count())
		{
			m_PhxGeomNames.Clear();
			m_PhxGeomBehaviorInverted.Clear();
			ErrorEx("'physics_geom_names' and 'physics_geom_behaviors_invert' counts do not match for part " + m_PartName);
		}
		/////////////////////////////////////////////////////////////
		//animSources
		path = m_PartPath + " override_animsource_names";
		m_AnimSourceNameOverrides = {};
		if (g_Game.ConfigIsExisting(path))
		{
			g_Game.ConfigGetTextArray(path, m_AnimSourceNameOverrides);
		}
		
		path = m_PartPath + " override_animsource_behaviors_invert";
		m_AnimSourceBehaviorOverridesInverted = {};
		if (g_Game.ConfigIsExisting(path))
		{
			g_Game.ConfigGetIntArray(path, m_AnimSourceBehaviorOverridesInverted);
		}
		
		//sanity check, just in case
		if (m_AnimSourceNameOverrides.Count() != m_AnimSourceBehaviorOverridesInverted.Count())
		{
			m_AnimSourceNameOverrides.Clear();
			m_AnimSourceBehaviorOverridesInverted.Clear();
		}
		/////////////////////////////////////////////////////////////
		//proxy roadways
		path = m_PartPath + " proxyroadway_names";
		m_ProxyRoadwayNames = {};
		if (g_Game.ConfigIsExisting(path))
		{
			g_Game.ConfigGetTextArray(path, m_ProxyRoadwayNames);
		}
		
		path = m_PartPath + " proxyroadway_behaviors_invert";
		m_ProxyRoadwayBehaviorInverted = {};
		if (g_Game.ConfigIsExisting(path))
		{
			g_Game.ConfigGetIntArray(path, m_ProxyRoadwayBehaviorInverted);
		}
		
		//sanity check, just in case
		if (m_ProxyRoadwayNames.Count() != m_ProxyRoadwayBehaviorInverted.Count())
		{
			m_ProxyRoadwayNames.Clear();
			m_ProxyRoadwayBehaviorInverted.Clear();
			ErrorEx("'proxyroadway_names' and 'proxyroadway_behaviors_invert' counts do not match for part " + m_PartName);
		}
	}
	
	//! Generic init method for custom part type properties
	protected void InitCustomPartTypeProperties(PartTypeInitData initData);
	
	//////////////////////////////
	//setters, use with caution!//
	//////////////////////////////
	
	void SetCanDecayConfig(bool can)
	{
		m_CanPartDecayConfig = can;
	}
	
	void SetCustomInstanceType(string name)
	{
		if (!m_CustomInstanceTypename)
			m_CustomInstanceTypename = name.ToType();
	}
	
	///////////
	//Getters//
	///////////
	string GetPartPath()
	{
		return m_PartPath;
	}
	
	string GetNameLocalized()
	{
		return Widget.TranslateString(m_Name);
	}
	
	string GetPartName()
	{
		return m_PartName;
	}

	string GetMainPartName()
	{
		return m_MainPartName;
	}
	
	int GetId()
	{
		return m_Id;
	}
	
	bool DamageToolOnBuild()
	{
		return true;
	}
	
	bool DamageHandsOnBuild()
	{
		return m_DamageHandsOnBuild;
	}
	
	bool DamageToolOnDeconstruct()
	{
		return true;
	}
	
	bool DamageHandsOnDeconstruct()
	{
		return true;
	}
	
	bool IsUtilityPart()
	{
		return m_IsUtilityPart;
	}
	
	bool CanPartDecayConfig()
	{
		return m_CanPartDecayConfig;
	}
	
	typename GetCustomInstanceType()
	{
		return m_CustomInstanceTypename;
	}
	
	float GetPartDecayRateConfig()
	{
		return m_PartDecayRateConfig;
	}
	
	float GetPartDecayThresholdConfig()
	{
		return m_PartDecayThresholdConfig;
	}
	
	int GetHandBuildFBAnimOverride()
	{
		return m_HandFBAnimOverride;
	}
	
	bool CanSimulateItemFalling()
	{
		return m_ItemFallingData.Count() == 2;
	}
	
	bool HasEssentialAttachmentSlots()
	{
		return m_EssentialAttachmentSlots.Count() > 0;
	}
	
	bool HasRelatedGUICategories()
	{
		return m_RelatedGUICategoryNames.Count() > 0;
	}
	
	bool IsBase()
	{
		return m_IsBase;
	}
	
	bool IsGate()
	{
		return m_IsGate;
	}
	
	array<string> GetRequiredPartTypes()
	{
		return m_RequiredPartTypes;
	}
	
	array<string> GetConflictedPartTypes()
	{
		return m_ConflictedPartTypes;
	}
	
	//! strings of min/max selections (should be single points in memory LOD)
	array<string> GetCollisionData()
	{
		return m_CollisionData;
	}
	
	array<string> GetInsiderBoxPairNames()
	{
		return m_InsiderBoxPairNames;
	}
	
	//! strings of min/max selections (should be single points in memory LOD)
	array<string> GetItemFallingData()
	{
		return m_ItemFallingData;
	}
	
	array<string> GetEssentialAttachmentSlots()
	{
		return m_EssentialAttachmentSlots;
	}
	
	array<string> GetRelatedGUICategoryNames()
	{
		return m_RelatedGUICategoryNames;
	}
	
	string GetBuildTextOverride()
	{
		return Widget.TranslateString(m_BuildTextOverride);
	}
	
	string GetDismantleTextOverride()
	{
		return Widget.TranslateString(m_DismantleTextOverride);
	}
	
	//! returns AnimSource name to use in 'SetAnimationPhase'
	string GetPartAnimSourceName()
	{
		return m_PartName;
	}
	
	//! returns bone name to use in 'ProxyPhysics' methods (translated to BoneIdx down the line)
	string GetPartBoneName()
	{
		return m_PartName;
	}
	
	//! rough material type, used for effect playback
	int GetMaterialType()
	{
		return m_MaterialType;
	}
	
	int GetBuildActionTypeMask()
	{
		return m_BuildActionTypeMask;
	}
	
	int GetBuildIndicationTypeMask()
	{
		return m_BuildIndicationTypeMask;
	}
	
	int GetDismantleActionTypeMask()
	{
		return m_DismantleActionTypeMask;
	}
	
	array<ref ConstructionMaterialData> GetMaterialsData()
	{
		return m_MaterialsData;
	}
	
	bool IsReversible()
	{
		return false;
	}
	
	TConstructionPartVariantArray GetRequiredPartsTypeVariantArray()
	{
		return m_ReqPartVariants;
	}
	
	ConstructionPartStaticsSupportData GetPartTypeStaticsSupportData()
	{
		return m_StaticsData;
	}
	
	int GetPartTypeSupportProvided(int category)
	{
		return m_StaticsData.GetSupportProvided(category);
	}
	
	int GetPartTypeSupportRequirement(int category)
	{
		return m_StaticsData.GetSupportRequirement(category);
	}
	
	set<int> GetPartTypeConfiguredSupportCategories()
	{
		return m_StaticsData.GetConfiguredSupportCategories();
	}
	
	array<string> GetPartTypeAnimSourceNameOverrides()
	{
		return m_AnimSourceNameOverrides;
	}
	
	array<int> GetPartTypeAnimSourceBehaviorInverts()
	{
		return m_AnimSourceBehaviorOverridesInverted;
	}
	
	array<string> GetPartTypePhxGeomNames()
	{
		return m_PhxGeomNames;
	}
	
	array<int> GetPartTypePhxGeomBehaviorInverts()
	{
		return m_PhxGeomBehaviorInverted;
	}
	
	array<string> GetPartTypeProxyRoadwayNames()
	{
		return m_ProxyRoadwayNames;
	}
	
	//! Note, this will likely change after release, take care when modding
	array<int> GetPartTypeProxyRoadwayBehaviorInverts()
	{
		return m_ProxyRoadwayBehaviorInverted;
	}
	
	array<string> GetPartTypeUtilityAutobuildPartsList()
	{
		return m_UtilityAutomaticBuild;
	}
	
	ConstructionPartEffectsData GetPartTypeEffectsData()
	{
		return m_EffectsData;
	}
	
	///////////
	//Utility//
	///////////
	
	//! Solves for category icon overlaps (in vanilla configuration)
	protected void SanitizeBuildIndicationMask()
	{
		m_BuildIndicationTypeMask = m_BuildActionTypeMask;
		
		if (m_BuildIndicationTypeMask & EConstructionTools.TOOL_NAIL && m_BuildIndicationTypeMask & EConstructionTools.TOOL_MOUNT_LOG)
			m_BuildIndicationTypeMask &= ~EConstructionTools.TOOL_MOUNT_LOG;
		
		if (m_BuildIndicationTypeMask & EConstructionTools.TOOL_DIG_BASE && m_BuildIndicationTypeMask & EConstructionTools.TOOL_EXCAVATION)
			m_BuildIndicationTypeMask &= ~EConstructionTools.TOOL_EXCAVATION;
	}
	
	sealed protected void ErrorConfigUndefined(string undefinedParam, string path)
	{
		ErrorEx("'" + undefinedParam + "'parameter undefined for " + path);
	}
}