Code viewer
Custom Hat Player NPC Classes (v1)
#CustomActor
It allows us to set up startup expression and animation, custom skin and hat class, weapon visibility, and text above the head. Bow Kid and Hat Kid variants included! (it only doesn't support costumes for now)
/** * * Copyright 2012-2015 Gears for Breakfast ApS. All Rights Reserved. */ class mcu8_NPC_Player extends Hat_NPC dependson(Hat_ExpressionComponent) abstract; var Array<Inventory> MyInventory; var transient PlayerController PlayerOwner; var transient bool HasUpdatedVisualsOnce; var Hat_TextRenderComponent TextRenderComponent; var MeshComponent PreviewMeshes[2]; var(CustomNPC_Visuals) bool GiveWeapon; var(CustomNPC_Visuals) class<Hat_Weapon> WeaponClass; var(CustomNPC_Visuals) bool WeaponInitiallyVisible; var(CustomNPC_Visuals) class<Hat_Ability_Trigger> HatClass; var(CustomNPC_Visuals) class<Hat_CosmeticItemQualityInfo> HatQualityInfo; var(CustomNPC_Visuals) class<Hat_Collectible_Skin> MySkinClass; var(CustomNPC_Visuals) string DisplayName; var(CustomNPC_Visuals) Color DisplayColor; var(CustomNPC_Animations) Name InitialAnimation; var(CustomNPC_Animations) bool Loop; var(CustomNPC_Animations) bool Restart; var(CustomNPC_Animations) float PlayRate; var(CustomNPC_Animations) float AnimationDuration; var(CustomNPC_Expressions) EExpressionType InitialExpression; var(CustomNPC_Expressions) bool MakeDefault; var(CustomNPC_Expressions) float Duration; var(Cosmetics) bool DisableUpperBody; var(Cosmetics) bool DisableLegs; var(Cosmetics) bool DisableHats; var(Cosmetics) bool DisableMasks; // If we don't want to cover the player's face in this cinematic, turn this on var bool IsLowQuality; // Sets IsLowQuality on its cosmeticitems var transient protected class<Hat_Collectible_Skin> CurrentSkinClass; function OnEnabled() { Super.OnEnabled(); UpdateVisuals(); } simulated event PostBeginPlay() { Super.PostBeginPlay(); if (!HasUpdatedVisualsOnce) UpdateVisuals(); } simulated event Destroyed() { DiscardInventory(); Super.Destroyed(); } function PlayAnimationMy(SkeletalMeshComponent c, bool IsPlay) { local float dur; local AnimNodeSlot slot; if (c.AnimTreeTemplate != None) { foreach c.AllAnimNodes(class'AnimNodeSlot', slot) { if (InitialAnimation == '' || !IsPlay) slot.StopCustomAnim(0.1); else { slot.PlayCustomAnim(InitialAnimation, PlayRate, 0.1, 0.1, Loop); } break; } return; } dur = 0.0; if (PlayRate > 0 && AnimationDuration > 0) dur = AnimationDuration / PlayRate; c.PlayAnim(InitialAnimation, dur, Loop, Restart); } function SetExpression(Actor Act, EExpressionType Exp, optional float d) { local Hat_ExpressionComponent Cmp; Cmp = GetActorExpression(Act); if (Cmp == None) { /* Cmp = new(Act) class'Hat_ExpressionComponent_HatKid'; Act.AttachComponent(Cmp); Cmp.Init(); if (Hat_SkeletalMeshActor(Act) != None) Hat_SkeletalMeshActor(Act).ExpressionComponent = Cmp; */ return; } if (MakeDefault) { Cmp.SetDefaultExpression(Exp); } else { Cmp.SetExpression(Exp, d); } if (Exp == EExpressionType_Ignore) { Expression.Reset(); Expression.Init(); } } static function Hat_ExpressionComponent GetActorExpression(Actor Act) { local Hat_ExpressionComponent Cmp; foreach Act.ComponentList(class'Hat_ExpressionComponent', Cmp) return Cmp; return None; } function UpdateVisuals() { local int i; for (i = 0; i < 2; i++) { if (PreviewMeshes[i] == None) continue; DetachComponent(PreviewMeshes[i]); PreviewMeshes[i] = None; } AttachComponent(Expression); Expression.Reset(); Expression.Init(); AddDefaultInventory(); HasUpdatedVisualsOnce = true; PlayAnimationMy(SkeletalMeshComponent, true); If (Expression != None) { SetExpression(Self, InitialExpression, Duration); } TextRenderComponent.Text = DisplayName; TextRenderComponent.TextColor = DisplayColor; TextRenderComponent.SetHidden(DisplayName == ""); ReattachComponent(TextRenderComponent); } function AddDefaultInventory() { DiscardInventory(); CreateInventoryForPlayerTypeNPC(); CreateInventory(HatClass, HatQualityInfo); GiveUmbrella(); ShowWeapon(WeaponInitiallyVisible); if (MySkinClass != None) { InitMaterialInstances(); CurrentSkinClass = MySkinClass; CurrentSkinClass.static.Apply(self); } } function CreateInventoryForPlayerTypeNPC(); function Array<MeshComponent> GetMyMaterialMeshComponents(optional bool attachments) { local Array<MeshComponent> OutArray; local Inventory Inv; local MeshComponent Mesh; OutArray = Super.GetMyMaterialMeshComponents(attachments); foreach MyInventory(Inv) { Mesh = MeshComponent(Inv.DroppedPickupMesh); if (Mesh != None) { OutArray.AddItem(Mesh); } } return OutArray; } simulated expensive function InitMaterialInstances() { local Inventory Inv; local MeshComponent Mesh; Super.InitMaterialInstances(); foreach MyInventory(Inv) { Mesh = MeshComponent(Inv.DroppedPickupMesh); if (Mesh != None) { InitMaterialInstancesMesh(Mesh); if (Inv.IsA('Hat_CosmeticItem')) Hat_CosmeticItem(Inv).OnInitInventoryMaterialInstancesQualityInfo(Mesh, Hat_CosmeticItem(Inv).MyItemQualityInfo); } } // We have to re-initialize expression any time after if (Expression != None) { Expression.Reset(); Expression.Init(); } } function GiveLoadoutItem(Hat_BackpackItem InvClass) { if (class<Inventory>(InvClass.BackpackClass) == None) return; CreateInventory(class<Inventory>(InvClass.BackpackClass), InvClass.IsA('Hat_LoadoutBackpackItem') ? Hat_LoadoutBackpackItem(InvClass).ItemQualityInfo : None); } function Inventory CreateInventory(class<Inventory> c, optional class<Hat_CosmeticItemQualityInfo> ItemQualityInfo) { local Inventory Inv; local Hat_CosmeticItem cos; local Name SpawnTag; // We have a custom tag set, so likely we're set to a specific cubemap. Our items should be too SpawnTag = ''; if (InStr(Locs(string(Tag)), "hat_npc_player") == INDEX_NONE) { SpawnTag = Tag; } Inv = Spawn(c, None, SpawnTag,,,,true); if (Inv == None) return None; MyInventory.AddItem(Inv); cos = Hat_CosmeticItem(Inv); if (cos != None) { // MEKU TO-DO: Work out why Instigator is set? cos.Instigator = None; cos.ActorInstigator = None; if (ItemQualityInfo != None) cos.UpdateItemQuality(ItemQualityInfo); cos.ActorInstigator = self; cos.IsLowQuality = IsLowQuality; if (Hat_Ability(Inv) != None) { Hat_Ability(Inv).UpdateArrayIndex(); } if (!cos.AttachToOwner(self, cos.MyItemQualityInfo)) { `if(`notdefined(FINAL_RELEASE)) `broadcast("AttachToOwner failed: " $ c); `endif } cos.SetOcclusionHidden(true); if (cos.DroppedPickupMesh != None) cos.DroppedPickupMesh.SetDepthPriorityGroup(SkeletalMeshComponent.DepthPriorityGroup); if (!IsLowQuality && cos.DroppedPickupMesh != None && SkeletalMeshComponent(cos.DroppedPickupMesh) != None) SkeletalMeshComponent(cos.DroppedPickupMesh).SetHasPhysicsAssetInstance(SkeletalMeshComponent.bHasPhysicsAssetInstance); if (!IsLowQuality && cos.OccludedMesh != None && SkeletalMeshComponent(cos.OccludedMesh) != None) SkeletalMeshComponent(cos.OccludedMesh).SetHasPhysicsAssetInstance(SkeletalMeshComponent.bHasPhysicsAssetInstance); } else if (Inv.IsA('Hat_Weapon')) { if (Inv.DroppedPickupMesh != None) Hat_Weapon(Inv).AttachMeshToOwner(self, Inv.DroppedPickupMesh); } return Inv; } function DiscardInventory() { local int i; for (i = MyInventory.Length-1; i >= 0; i--) { MyInventory[i].ItemRemovedFromInvManager(); MyInventory[i].Destroy(); } MyInventory.Length = 0; SkeletalMeshComponent.SetSectionGroup(''); // We have to un-apply the skin by applying the default skin (which resets parameters) if (CurrentSkinClass != None) { //`broadcast("Removed: " $ CurrentSkinClass); CurrentSkinClass.static.Removed(self); CurrentSkinClass = None; class'Hat_Collectible_Skin'.static.Apply(self); if (Expression != None) { Expression.Reset(); Expression.Init(); } } } simulated function ShowWeapon(bool b) { local int i; for (i = 0; i < MyInventory.Length; i++) { if (!MyInventory[i].IsA('Hat_Weapon')) continue; MyInventory[i].SetHidden(!b); if (MyInventory[i].IsA('Hat_Weapon_Umbrella')) Hat_Weapon_Umbrella(MyInventory[i]).TakeOut(); } } function bool GiveUmbrella() { local Hat_BackpackItem bi; if (!GiveWeapon) return false; bi = new class'Hat_BackpackItem'; bi.BackpackClass = WeaponClass; GiveLoadoutItem(bi); return true; } function bool IsTooFarAway() { return false; } defaultproperties { Begin Object Class=Hat_TextRenderComponent Name=TextRenderComponent0 Translation=(Z=115) Size = 0.8f TextLimit = 50 HiddenGame=false TextColor=(R=127,G=187,B=213) CastShadow = false //Rotation=(Yaw=-16384) End Object TextRenderComponent = TextRenderComponent0; Components.Add(TextRenderComponent0) TickOptimize = TickOptimize_None; bBlockActors = false; bCollideWorld = true; bCollideActors = true; BlockRigidBody = false; bPathColliding = false; bCanBeDamaged = true; GiveWeapon = false; WeaponInitiallyVisible = false; WeaponClass = class'Hat_Weapon_Umbrella'; HatClass = class'Hat_Ability_Help'; HatQualityInfo = None; InitialAnimation = "Idle" Loop = true; Restart = false; PlayRate = 1.0; AnimationDuration = 0.0; DisplayColor=(R=127,G=187,B=213) Duration = 0; }
class mcu8_NPC_Player_BowKid extends mcu8_NPC_Player placeable; defaultproperties { Begin Object Name=SkeletalMeshComponent0 SkeletalMesh=SkeletalMesh'HatInTime_Characters_Coop.models.bowkid_head_skm' PhysicsAsset=PhysicsAsset'HatinTime_Characters_CoPartner.Physics.CoPartner_Physics' AnimSets(0)=AnimSet'HatInTime_Characters_HatKid.AnimSet.HatKidV2_Anims' AnimSets(1)=AnimSet'HatInTime_Characters_HatKid.AnimSet.HatKidV2_Attack_Anims' AnimSets(2)=AnimSet'HatInTime_Characters_HatKid2.AnimSet.HatKidV2_Cruise' AnimSets(3)=AnimSet'HatInTime_Characters_HatKid3.AnimSet.HatKidV2_Metro' AnimTreeTemplate=AnimTree'HatInTime_Characters.AnimTree.MatineeAnimTree' Animations=None bNoSelfShadow=true bUseTickOptimization = false; End Object Begin Object Class=SkeletalMeshComponent Name=PreviewMesh0 SkeletalMesh=SkeletalMesh'HatInTime_Characters_Coop.models.bowkid_body_skm' PhysicsAsset=PhysicsAsset'HatInTime_Characters_Coop.Physics.bowkid_body_skm_Physics' AnimSets(0)=AnimSet'HatInTime_Characters_HatKid.AnimSet.HatKidV2_Anims' AnimSets(1)=AnimSet'HatInTime_Characters_HatKid.AnimSet.HatKidV2_Attack_Anims' AnimSets(2)=AnimSet'HatInTime_Characters_HatKid2.AnimSet.HatKidV2_Cruise' AnimSets(3)=AnimSet'HatInTime_Characters_HatKid3.AnimSet.HatKidV2_Metro' bCacheAnimSequenceNodes=FALSE ShadowParent = SkeletalMeshComponent0 ParentAnimComponent=SkeletalMeshComponent0 LightEnvironment=MyLightEnvironment CanBlockCamera=false MaxDrawDistance = 7000; bDisableFaceFX = true; AlwaysLoadOnClient=false AlwaysLoadOnServer=false End Object Components.Add(PreviewMesh0) PreviewMeshes(0) = PreviewMesh0; Begin Object Class=SkeletalMeshComponent Name=PreviewMesh1 SkeletalMesh=SkeletalMesh'HatInTime_Characters_Coop.models.bowkid_legs_skm' PhysicsAsset=PhysicsAsset'HatInTime_Characters_HatKid.Physics.HatKidLegs_Physics' AnimSets(0)=AnimSet'HatInTime_Characters_HatKid.AnimSet.HatKidV2_Anims' AnimSets(1)=AnimSet'HatInTime_Characters_HatKid.AnimSet.HatKidV2_Attack_Anims' AnimSets(2)=AnimSet'HatInTime_Characters_HatKid2.AnimSet.HatKidV2_Cruise' AnimSets(3)=AnimSet'HatInTime_Characters_HatKid3.AnimSet.HatKidV2_Metro' bCacheAnimSequenceNodes=FALSE ShadowParent = SkeletalMeshComponent0 ParentAnimComponent=SkeletalMeshComponent0 LightEnvironment=MyLightEnvironment CanBlockCamera=false MaxDrawDistance = 7000; bDisableFaceFX = true; AlwaysLoadOnClient=false AlwaysLoadOnServer=false End Object Components.Add(PreviewMesh1) PreviewMeshes(1) = PreviewMesh1; Begin Object Class=Hat_ExpressionComponent_BowKid Name=hExpression End Object Components.Add(hExpression); Expression = hExpression; HatQualityInfo = class'Hat_CosmeticItemQualityInfo_Help_Bow'; } function CreateInventoryForPlayerTypeNPC() { CreateInventory(class'Hat_CosmeticItem_BowKidUpperBody', None); CreateInventory(class'Hat_CosmeticItem_BowKidLegs', None); }
class mcu8_NPC_Player_HatKid extends mcu8_NPC_Player placeable; defaultproperties { Begin Object Name=SkeletalMeshComponent0 SkeletalMesh=SkeletalMesh'HatInTime_Characters_HatKid.models.HatKidHead' PhysicsAsset=PhysicsAsset'HatInTime_Characters_HatKid.Physics.HatKidHead_Physics' AnimSets(0)=AnimSet'HatInTime_Characters_HatKid.AnimSet.HatKidV2_Anims' AnimSets(1)=AnimSet'HatInTime_Characters_HatKid.AnimSet.HatKidV2_Attack_Anims' AnimSets(2)=AnimSet'HatInTime_Characters_HatKid2.AnimSet.HatKidV2_Cruise' AnimSets(3)=AnimSet'HatInTime_Characters_HatKid3.AnimSet.HatKidV2_Metro' AnimTreeTemplate=AnimTree'HatInTime_Characters.AnimTree.MatineeAnimTree' Animations=None bNoSelfShadow=true bUseTickOptimization = false; End Object Begin Object Class=SkeletalMeshComponent Name=PreviewMesh0 SkeletalMesh=SkeletalMesh'HatInTime_Characters_HatKid.models.HatKidBody' PhysicsAsset=PhysicsAsset'HatInTime_Characters_HatKid.Physics.HatKidBody_Physics' AnimSets(0)=AnimSet'HatInTime_Characters_HatKid.AnimSet.HatKidV2_Anims' AnimSets(1)=AnimSet'HatInTime_Characters_HatKid.AnimSet.HatKidV2_Attack_Anims' AnimSets(2)=AnimSet'HatInTime_Characters_HatKid2.AnimSet.HatKidV2_Cruise' AnimSets(3)=AnimSet'HatInTime_Characters_HatKid3.AnimSet.HatKidV2_Metro' bCacheAnimSequenceNodes=FALSE ShadowParent = SkeletalMeshComponent0 ParentAnimComponent=SkeletalMeshComponent0 LightEnvironment=MyLightEnvironment CanBlockCamera=false MaxDrawDistance = 7000; bDisableFaceFX = true; AlwaysLoadOnClient=false AlwaysLoadOnServer=false End Object Components.Add(PreviewMesh0) PreviewMeshes(0) = PreviewMesh0; Begin Object Class=SkeletalMeshComponent Name=PreviewMesh1 SkeletalMesh=SkeletalMesh'HatInTime_Characters_HatKid.models.HatKidLegs' PhysicsAsset=PhysicsAsset'HatInTime_Characters_HatKid.Physics.HatKidLegs_Physics' AnimSets(0)=AnimSet'HatInTime_Characters_HatKid.AnimSet.HatKidV2_Anims' AnimSets(1)=AnimSet'HatInTime_Characters_HatKid.AnimSet.HatKidV2_Attack_Anims' AnimSets(2)=AnimSet'HatInTime_Characters_HatKid2.AnimSet.HatKidV2_Cruise' AnimSets(3)=AnimSet'HatInTime_Characters_HatKid3.AnimSet.HatKidV2_Metro' bCacheAnimSequenceNodes=FALSE ShadowParent = SkeletalMeshComponent0 ParentAnimComponent=SkeletalMeshComponent0 LightEnvironment=MyLightEnvironment CanBlockCamera=false MaxDrawDistance = 7000; bDisableFaceFX = true; AlwaysLoadOnClient=false AlwaysLoadOnServer=false End Object Components.Add(PreviewMesh1) PreviewMeshes(1) = PreviewMesh1; Begin Object Class=Hat_ExpressionComponent_HatKid Name=hExpression End Object Components.Add(hExpression); Expression = hExpression; } function CreateInventoryForPlayerTypeNPC() { CreateInventory(class'Hat_CosmeticItem_HatKidUpperBody', None); CreateInventory(class'Hat_CosmeticItem_HatKidLegs', None); }