public object GetSaveData() { if (!enemy) { return(null); } // Get entity behaviour DaggerfallEntityBehaviour entityBehaviour = enemy.GetComponent <DaggerfallEntityBehaviour>(); if (!entityBehaviour) { return(null); } // Create save data EnemyEntity entity = entityBehaviour.Entity as EnemyEntity; EnemyMotor motor = enemy.GetComponent <EnemyMotor>(); EnemySenses senses = enemy.GetComponent <EnemySenses>(); DaggerfallMobileUnit mobileEnemy = enemy.GetComponentInChildren <DaggerfallMobileUnit>(); EnemyData_v1 data = new EnemyData_v1(); data.loadID = LoadID; data.gameObjectName = entityBehaviour.gameObject.name; data.currentPosition = enemy.transform.position; data.localPosition = enemy.transform.localPosition; data.currentRotation = enemy.transform.rotation; data.worldContext = entity.WorldContext; data.worldCompensation = GameManager.Instance.StreamingWorld.WorldCompensation; data.entityType = entity.EntityType; data.careerName = entity.Career.Name; data.careerIndex = entity.CareerIndex; data.startingHealth = entity.MaxHealth; data.currentHealth = entity.CurrentHealth; data.currentFatigue = entity.CurrentFatigue; data.currentMagicka = entity.CurrentMagicka; data.isHostile = motor.IsHostile; data.hasEncounteredPlayer = senses.HasEncounteredPlayer; data.isDead = (entity.CurrentHealth <= 0) ? true : false; data.questSpawn = enemy.QuestSpawn; data.mobileGender = mobileEnemy.Summary.Enemy.Gender; data.items = entity.Items.SerializeItems(); data.equipTable = entity.ItemEquipTable.SerializeEquipTable(); data.instancedEffectBundles = GetComponent <EntityEffectManager>().GetInstancedBundlesSaveData(); data.alliedToPlayer = mobileEnemy.Summary.Enemy.Team == MobileTeams.PlayerAlly; data.questFoeSpellQueueIndex = entity.QuestFoeSpellQueueIndex; data.questFoeItemQueueIndex = entity.QuestFoeItemQueueIndex; data.wabbajackActive = entity.WabbajackActive; data.team = (int)entity.Team + 1; // Add quest resource data if present QuestResourceBehaviour questResourceBehaviour = GetComponent <QuestResourceBehaviour>(); if (questResourceBehaviour) { data.questResource = questResourceBehaviour.GetSaveData(); } return(data); }
void Start() { mobile = GetComponentInChildren <DaggerfallMobileUnit>(); entityBehaviour = GetComponent <DaggerfallEntityBehaviour>(); enemyEntity = entityBehaviour.Entity as EnemyEntity; motor = GetComponent <EnemyMotor>(); questBehaviour = GetComponent <QuestResourceBehaviour>(); short[] classicSpawnXZDistArray = { 1024, 384, 640, 768, 768, 768, 768 }; short[] classicSpawnYDistUpperArray = { 128, 128, 128, 384, 768, 128, 256 }; short[] classicSpawnYDistLowerArray = { 0, 0, 0, 0, -128, -768, 0 }; short[] classicDespawnXZDistArray = { 1024, 1024, 1024, 1024, 768, 768, 768 }; short[] classicDespawnYDistArray = { 384, 384, 384, 384, 768, 768, 768 }; byte index = mobile.Summary.ClassicSpawnDistanceType; classicSpawnXZDist = classicSpawnXZDistArray[index] * MeshReader.GlobalScale; classicSpawnYDistUpper = classicSpawnYDistUpperArray[index] * MeshReader.GlobalScale; classicSpawnYDistLower = classicSpawnYDistLowerArray[index] * MeshReader.GlobalScale; classicDespawnXZDist = classicDespawnXZDistArray[index] * MeshReader.GlobalScale; classicDespawnYDist = classicDespawnYDistArray[index] * MeshReader.GlobalScale; // 180 degrees is classic's value. 190 degrees is actual human FOV according to online sources. if (DaggerfallUnity.Settings.EnhancedCombatAI) { FieldOfView = 190; } }
/// <summary> /// Assigns a new QuestResourceBehaviour component if this is a Questor NPC. /// Can happen either at runtime or during scene layout. /// </summary> public void AssignQuestResourceBehaviour() { // Static NPC data must match a known questor Person resource Person questorPerson = QuestMachine.Instance.ActiveQuestor(Data); if (questorPerson == null) { return; } // Can only have a single QuestResourceBehaviour if (GetComponent <QuestResourceBehaviour>()) { return; } // Assign new QuestResourceBehaviour and link to Person resource in quest system QuestResourceBehaviour resourceBehaviour = gameObject.AddComponent <QuestResourceBehaviour>(); if (resourceBehaviour) { resourceBehaviour.AssignResource(questorPerson); Debug.LogFormat("Added new QuestResourceBehaviour to object {0} and assigned Questor Person resource {1}", gameObject.name, questorPerson.DisplayName); } }
// Player has clicked a GameObject with a QuestResourceBehaviour attached void TriggerQuestResourceBehaviourClick(QuestResourceBehaviour questResourceBehaviour) { // Handle typical quest resource click if (questResourceBehaviour) { questResourceBehaviour.DoClick(); } }
void CompleteDeath() { if (!entityBehaviour) { return; } // If enemy associated with quest system, make sure quest system is done with it first QuestResourceBehaviour questResourceBehaviour = GetComponent <QuestResourceBehaviour>(); if (questResourceBehaviour) { if (!questResourceBehaviour.IsFoeDead) { return; } } // Play body collapse sound if (DaggerfallUI.Instance.DaggerfallAudioSource) { AudioClip collapseSound = DaggerfallUI.Instance.DaggerfallAudioSource.GetAudioClip((int)SoundClips.BodyFall); AudioSource.PlayClipAtPoint(collapseSound, entityBehaviour.transform.position); } // Disable enemy gameobject // Do not destroy as we must still save enemy state when dead gameObject.SetActive(false); // Show death message string deathMessage = HardStrings.thingJustDied; deathMessage = deathMessage.Replace("%s", mobile.Summary.Enemy.Name); DaggerfallUI.Instance.PopupMessage(deathMessage); // Generate lootable corpse marker DaggerfallLoot loot = GameObjectHelper.CreateLootableCorpseMarker( GameManager.Instance.PlayerObject, entityBehaviour.gameObject, enemyEntity, mobile.Summary.Enemy.CorpseTexture, DaggerfallUnity.NextUID); // Generate items loot.GenerateItems(); entityBehaviour.CorpseLootContainer = loot; // Transfer any items owned by entity to loot container // Many quests will stash a reward in enemy inventory for player to find // This will be in addition to normal random loot table generation loot.Items.TransferAll(entityBehaviour.Entity.Items); // Raise static event if (OnEnemyDeath != null) { OnEnemyDeath(this, null); } }
/// <summary> /// Add a quest NPC to marker position. /// </summary> static void AddQuestNPC(SiteTypes siteType, Quest quest, QuestMarker marker, Person person, Transform parent) { // Get billboard texture data FactionFile.FlatData flatData; if (person.IsIndividualNPC) { // Individuals are always flat1 no matter gender flatData = FactionFile.GetFlatData(person.FactionData.flat1); } if (person.Gender == Genders.Male) { // Male has flat1 flatData = FactionFile.GetFlatData(person.FactionData.flat1); } else { // Female has flat2 flatData = FactionFile.GetFlatData(person.FactionData.flat2); } // Create target GameObject GameObject go = CreateDaggerfallBillboardGameObject(flatData.archive, flatData.record, parent); go.name = string.Format("Quest NPC [{0}]", person.DisplayName); // Set position and adjust up by half height if not inside a dungeon Vector3 dungeonBlockPosition = new Vector3(marker.dungeonX * RDBLayout.RDBSide, 0, marker.dungeonZ * RDBLayout.RDBSide); go.transform.localPosition = dungeonBlockPosition + marker.flatPosition; DaggerfallBillboard dfBillboard = go.GetComponent <DaggerfallBillboard>(); if (siteType != SiteTypes.Dungeon) { go.transform.localPosition += new Vector3(0, dfBillboard.Summary.Size.y / 2, 0); } // Add people data to billboard dfBillboard.SetRMBPeopleData(person.FactionIndex, person.FactionData.flags); // Add QuestResourceBehaviour to GameObject QuestResourceBehaviour questResourceBehaviour = go.AddComponent <QuestResourceBehaviour>(); questResourceBehaviour.AssignResource(person); // Set QuestResourceBehaviour in Person object person.QuestResourceBehaviour = questResourceBehaviour; // Add StaticNPC behaviour StaticNPC npc = go.AddComponent <StaticNPC>(); npc.SetLayoutData((int)marker.flatPosition.x, (int)marker.flatPosition.y, (int)marker.flatPosition.z, person); // Set tag go.tag = QuestMachine.questPersonTag; }
// Check if raycast hit a QuestResource private bool QuestResourceBehaviourCheck(RaycastHit hitInfo, out QuestResourceBehaviour questResourceBehaviour) { questResourceBehaviour = hitInfo.transform.GetComponent <QuestResourceBehaviour>(); if (questResourceBehaviour != null) { return(true); } else { return(false); } }
// Player has clicked a GameObject with a QuestResourceBehaviour attached bool TriggerQuestResourceBehaviourClick(QuestResourceBehaviour questResourceBehaviour) { // Handle typical quest resource click if (questResourceBehaviour) { return(questResourceBehaviour.DoClick()); } else { return(false); } }
public override PayloadCallbackResults?EnchantmentPayloadCallback(EnchantmentPayloadFlags context, EnchantmentParam?param = null, DaggerfallEntityBehaviour sourceEntity = null, DaggerfallEntityBehaviour targetEntity = null, DaggerfallUnityItem sourceItem = null, int sourceDamage = 0) { base.EnchantmentPayloadCallback(context, param, sourceEntity, targetEntity, sourceItem, sourceDamage); // Validate if (context != EnchantmentPayloadFlags.Strikes || targetEntity == null) { return(null); } // Change target enemy if (targetEntity.Entity is EnemyEntity) { // Get enemy entity - cannot have Wabbajack active already EnemyEntity enemy = (EnemyEntity)targetEntity.Entity; if (enemy == null || enemy.WabbajackActive) { return(null); } // Get new enemy career and transform MobileTypes enemyType = careerIDs[Random.Range(0, careerIDs.Length)]; if ((int)enemyType == enemy.CareerIndex) { enemyType = (MobileTypes)(((int)enemyType + 1) % careerIDs.Length); } Transform parentTransform = targetEntity.gameObject.transform.parent; // Do not disable enemy if in use by the quest system QuestResourceBehaviour questResourceBehaviour = targetEntity.GetComponent <QuestResourceBehaviour>(); if (questResourceBehaviour && !questResourceBehaviour.IsFoeDead) { return(null); } string[] enemyNames = TextManager.Instance.GetLocalizedTextList("enemyNames"); if (enemyNames == null) { throw new System.Exception("enemyNames array text not found"); } // Switch entity targetEntity.gameObject.SetActive(false); GameObject gameObject = GameObjectHelper.CreateEnemy(enemyNames[(int)enemyType], enemyType, targetEntity.transform.localPosition, MobileGender.Unspecified, parentTransform); DaggerfallEntityBehaviour newEnemyBehaviour = gameObject.GetComponent <DaggerfallEntityBehaviour>(); EnemyEntity newEnemy = (EnemyEntity)newEnemyBehaviour.Entity; newEnemy.WabbajackActive = true; newEnemy.CurrentHealth -= enemy.MaxHealth - enemy.CurrentHealth; // carry over damage to new monster } return(null); }
public object GetSaveData() { if (!enemy) { return(null); } // Get entity behaviour DaggerfallEntityBehaviour entityBehaviour = enemy.GetComponent <DaggerfallEntityBehaviour>(); if (!entityBehaviour) { return(null); } // Create save data EnemyEntity entity = entityBehaviour.Entity as EnemyEntity; EnemyMotor motor = enemy.GetComponent <EnemyMotor>(); EnemySenses senses = enemy.GetComponent <EnemySenses>(); DaggerfallMobileUnit mobileEnemy = enemy.GetComponentInChildren <DaggerfallMobileUnit>(); EnemyData_v1 data = new EnemyData_v1(); data.loadID = LoadID; data.gameObjectName = entityBehaviour.gameObject.name; data.currentPosition = enemy.transform.position; data.currentRotation = enemy.transform.rotation; data.entityType = entity.EntityType; data.careerName = entity.Career.Name; data.careerIndex = entity.CareerIndex; data.startingHealth = entity.MaxHealth; data.currentHealth = entity.CurrentHealth; data.currentFatigue = entity.CurrentFatigue; data.currentMagicka = entity.CurrentMagicka; data.isHostile = motor.IsHostile; data.hasEncounteredPlayer = senses.HasEncounteredPlayer; data.isDead = (entity.CurrentHealth <= 0) ? true : false; data.questSpawn = enemy.QuestSpawn; data.mobileGender = mobileEnemy.Summary.Enemy.Gender; data.items = entity.Items.SerializeItems(); data.equipTable = entity.ItemEquipTable.SerializeEquipTable(); // Add quest resource data if present QuestResourceBehaviour questResourceBehaviour = GetComponent <QuestResourceBehaviour>(); if (questResourceBehaviour) { data.questResource = questResourceBehaviour.GetSaveData(); } return(data); }
/// <summary> /// Adds a quest item to marker position. /// </summary> static void AddQuestItem(SiteTypes siteType, Quest quest, QuestMarker marker, Item item, Transform parent = null) { // Texture indices for quest items are from world texture record int textureArchive = item.DaggerfallUnityItem.WorldTextureArchive; int textureRecord = item.DaggerfallUnityItem.WorldTextureRecord; // Create billboard GameObject go = CreateDaggerfallBillboardGameObject(textureArchive, textureRecord, parent); DaggerfallBillboard dfBillboard = go.GetComponent <DaggerfallBillboard>(); // Set name go.name = string.Format("Quest Item [{0} | {1}]", item.Symbol.Original, item.DaggerfallUnityItem.LongName); // Setup custom material if available if (AssetInjection.TextureReplacement.CustomTextureExist(textureArchive, textureRecord)) { AssetInjection.TextureReplacement.SetBillboardCustomMaterial(go, textureArchive, textureRecord); } // Marker position Vector3 position; Vector3 dungeonBlockPosition = new Vector3(marker.dungeonX * RDBLayout.RDBSide, 0, marker.dungeonZ * RDBLayout.RDBSide); position = dungeonBlockPosition + marker.flatPosition; // Dungeon flats have a different origin (centre point) than elsewhere (base point) // Find bottom of marker in world space as it should be aligned to placement surface (e.g. ground, table, shelf, etc.) if (siteType == SiteTypes.Dungeon) { position.y += (-DaggerfallLoot.randomTreasureMarkerDim / 2 * MeshReader.GlobalScale); } // Now move up item icon by half own size and assign position position.y += (dfBillboard.Summary.Size.y / 2f); go.transform.localPosition = position; // Add QuestResourceBehaviour to GameObject QuestResourceBehaviour questResourceBehaviour = go.AddComponent <QuestResourceBehaviour>(); questResourceBehaviour.AssignResource(item); // Set QuestResourceBehaviour in Item object item.QuestResourceBehaviour = questResourceBehaviour; // Assign a trigger collider for clicks SphereCollider collider = go.AddComponent <SphereCollider>(); collider.isTrigger = true; }
public override void MagicRound() { base.MagicRound(); DaggerfallEntityBehaviour entityBehaviour = GetPeeredEntityBehaviour(manager); if (!entityBehaviour) { return; } if (entityBehaviour.Entity is EnemyEntity) { EnemyEntity enemy = (EnemyEntity)entityBehaviour.Entity; if (enemy.WabbajackActive) { return; } MobileTypes enemyType = careerIDs[Random.Range(0, careerIDs.Length)]; if ((int)enemyType == enemy.CareerIndex) { enemyType = (MobileTypes)(((int)enemyType + 1) % careerIDs.Length); } Transform parentTransform = entityBehaviour.gameObject.transform.parent; // Do not disable enemy if in use by the quest system QuestResourceBehaviour questResourceBehaviour = entityBehaviour.GetComponent <QuestResourceBehaviour>(); if (questResourceBehaviour) { if (!questResourceBehaviour.IsFoeDead) { return; } } entityBehaviour.gameObject.SetActive(false); GameObject gameObject = GameObjectHelper.CreateEnemy(HardStrings.enemyNames[(int)enemyType], enemyType, entityBehaviour.transform.localPosition, parentTransform); DaggerfallEntityBehaviour newEnemyBehaviour = gameObject.GetComponent <DaggerfallEntityBehaviour>(); EnemyEntity newEnemy = (EnemyEntity)newEnemyBehaviour.Entity; newEnemy.WabbajackActive = true; newEnemy.CurrentHealth -= enemy.MaxHealth - enemy.CurrentHealth; // carry over damage to new monster } }
/// <summary> /// Adds a single quest foe to marker position. /// </summary> static void AddQuestFoe(SiteTypes siteType, Quest quest, QuestMarker marker, Foe foe, Transform parent) { // Create enemy GameObject Vector3 dungeonBlockPosition = new Vector3(marker.dungeonX * RDBLayout.RDBSide, 0, marker.dungeonZ * RDBLayout.RDBSide); GameObject go = CreateEnemy("Quest Foe", foe.FoeType, dungeonBlockPosition + marker.flatPosition, parent); // Add QuestResourceBehaviour to GameObject QuestResourceBehaviour questResourceBehaviour = go.AddComponent <QuestResourceBehaviour>(); questResourceBehaviour.AssignResource(foe); // Set QuestResourceBehaviour in this particular instantiated Foe object // Each GameObject placed in world for this Foe will reference same Foe quest resource // Keep this one-to-many relationship in mind for Foe handling foe.QuestResourceBehaviour = questResourceBehaviour; // Rearm injured trigger at time of placement // Notes for later: // * This should be rearmed at the beginning of each wave // * Only first wounding of a wave will trigger "injured aFoe" until rearmed on next wave foe.RearmInjured(); }
void Start() { mobile = GetComponentInChildren <DaggerfallMobileUnit>(); entityBehaviour = GetComponent <DaggerfallEntityBehaviour>(); enemyEntity = entityBehaviour.Entity as EnemyEntity; motor = GetComponent <EnemyMotor>(); questBehaviour = GetComponent <QuestResourceBehaviour>(); lastKnownTargetPos = ResetPlayerPos; short[] classicSpawnXZDistArray = { 1024, 384, 640, 768, 768, 768, 768 }; short[] classicSpawnYDistUpperArray = { 128, 128, 128, 384, 768, 128, 256 }; short[] classicSpawnYDistLowerArray = { 0, 0, 0, 0, -128, -768, 0 }; short[] classicDespawnXZDistArray = { 1024, 1024, 1024, 1024, 768, 768, 768 }; short[] classicDespawnYDistArray = { 384, 384, 384, 384, 768, 768, 768 }; byte index = mobile.Summary.ClassicSpawnDistanceType; classicSpawnXZDist = classicSpawnXZDistArray[index] * MeshReader.GlobalScale; classicSpawnYDistUpper = classicSpawnYDistUpperArray[index] * MeshReader.GlobalScale; classicSpawnYDistLower = classicSpawnYDistLowerArray[index] * MeshReader.GlobalScale; classicDespawnXZDist = classicDespawnXZDistArray[index] * MeshReader.GlobalScale; classicDespawnYDist = classicDespawnYDistArray[index] * MeshReader.GlobalScale; }
public void RestoreSaveData(object dataIn) { if (!enemy) { return; } EnemyData_v1 data = (EnemyData_v1)dataIn; if (data.loadID != LoadID) { return; } DaggerfallEntityBehaviour entityBehaviour = enemy.GetComponent <DaggerfallEntityBehaviour>(); EnemySenses senses = enemy.GetComponent <EnemySenses>(); EnemyMotor motor = enemy.GetComponent <EnemyMotor>(); EnemyEntity entity = entityBehaviour.Entity as EnemyEntity; // Restore enemy career or class if different if (entity == null || entity.EntityType != data.entityType || entity.CareerIndex != data.careerIndex) { SetupDemoEnemy setupEnemy = enemy.GetComponent <SetupDemoEnemy>(); setupEnemy.ApplyEnemySettings(data.entityType, data.careerIndex, data.mobileGender, data.isHostile, alliedToPlayer: data.alliedToPlayer); setupEnemy.AlignToGround(); if (entity == null) { entity = entityBehaviour.Entity as EnemyEntity; } } // Quiesce entity during state restore entity.Quiesce = true; // Restore enemy data entityBehaviour.gameObject.name = data.gameObjectName; enemy.transform.rotation = data.currentRotation; entity.QuestFoeSpellQueueIndex = data.questFoeSpellQueueIndex; entity.QuestFoeItemQueueIndex = data.questFoeItemQueueIndex; entity.WabbajackActive = data.wabbajackActive; entity.Items.DeserializeItems(data.items); entity.ItemEquipTable.DeserializeEquipTable(data.equipTable, entity.Items); entity.MaxHealth = data.startingHealth; entity.SetHealth(data.currentHealth, true); entity.SetFatigue(data.currentFatigue, true); entity.SetMagicka(data.currentMagicka, true); int team = data.team; if (team > 0) // Added 1 to made backwards compatible. 0 = no team saved { entity.Team = (MobileTeams)(team - 1); } motor.IsHostile = data.isHostile; senses.HasEncounteredPlayer = data.hasEncounteredPlayer; // Restore enemy position and migrate to floating y support for exteriors // Interiors seem to be working fine at this stage with any additional support // Dungeons are not involved with floating y and don't need any changes WorldContext enemyContext = GetEnemyWorldContext(enemy); if (enemyContext == WorldContext.Exterior) { RestoreExteriorPositionHandler(enemy, data, enemyContext); } else { // Everything else enemy.transform.position = data.currentPosition; } // Disable dead enemies if (data.isDead) { entityBehaviour.gameObject.SetActive(false); } // Restore quest resource link enemy.QuestSpawn = data.questSpawn; if (enemy.QuestSpawn) { // Add QuestResourceBehaviour to GameObject QuestResourceBehaviour questResourceBehaviour = entityBehaviour.gameObject.AddComponent <QuestResourceBehaviour>(); questResourceBehaviour.RestoreSaveData(data.questResource); // Destroy QuestResourceBehaviour if no actual quest properties are restored from save if (questResourceBehaviour.QuestUID == 0 || questResourceBehaviour.TargetSymbol == null) { enemy.QuestSpawn = false; Destroy(questResourceBehaviour); } } // Restore instanced effect bundles GetComponent <EntityEffectManager>().RestoreInstancedBundleSaveData(data.instancedEffectBundles); // Resume entity entity.Quiesce = false; }
// Player has clicked on a static NPC void StaticNPCClick(StaticNPC npc) { // Do nothing if no NPC passed or fade in progress // Quest machine does not tick while fading (to prevent things happening while screen is black) // But this can result in player clicking a quest NPC before quest state ticks after load and breaking quest if (!npc || DaggerfallUI.Instance.FadeInProgress) { return; } // Store the NPC just clicked in quest engine QuestMachine.Instance.LastNPCClicked = npc; // Check if this NPC is a quest giver and show temp guild quest popup // This will be changed later when temp guild system replaced with real thing if (QuestorCheck(npc)) { return; } // Handle quest NPC click and exit if linked to a Person resource QuestResourceBehaviour questResourceBehaviour = npc.gameObject.GetComponent <QuestResourceBehaviour>(); if (questResourceBehaviour) { if (TriggerQuestResourceBehaviourClick(questResourceBehaviour)) { return; } } // Do nothing further if a quest is actively listening on this individual NPC // This NPC not reserved as a Person resource but has a WhenNpcIsAvailable action listening on it // This effectively shuts down several named NPCs during main quest, but not trivial to otherwise determine appropriate access // TODO: Try to find a good solution for releasing listeners when the owning action is disabled if (QuestMachine.Instance.HasFactionListener(npc.Data.factionID)) { return; } // Get faction data. FactionFile.FactionData factionData; if (playerEnterExit.IsPlayerInsideBuilding && GameManager.Instance.PlayerEntity.FactionData.GetFactionData(npc.Data.factionID, out factionData)) { UserInterfaceManager uiManager = DaggerfallUI.Instance.UserInterfaceManager; Debug.LogFormat("faction id: {0}, social group: {1}, guild: {2}", npc.Data.factionID, (FactionFile.SocialGroups)factionData.sgroup, (FactionFile.GuildGroups)factionData.ggroup); // Check if the NPC offers a guild service. if (Enum.IsDefined(typeof(GuildServices), npc.Data.factionID)) { FactionFile.GuildGroups guild = (FactionFile.GuildGroups)factionData.ggroup; GuildServices service = (GuildServices)npc.Data.factionID; Debug.Log("NPC offers guild service: " + service.ToString()); uiManager.PushWindow(new DaggerfallGuildServicePopupWindow(uiManager, npc, guild, service)); } // Check if this NPC is a merchant. else if ((FactionFile.SocialGroups)factionData.sgroup == FactionFile.SocialGroups.Merchants) { // Shop? if (RMBLayout.IsShop(playerEnterExit.BuildingDiscoveryData.buildingType)) { if (RMBLayout.IsRepairShop(playerEnterExit.BuildingDiscoveryData.buildingType)) { uiManager.PushWindow(new DaggerfallMerchantRepairPopupWindow(uiManager, npc)); } else { uiManager.PushWindow(new DaggerfallMerchantServicePopupWindow(uiManager, npc, DaggerfallMerchantServicePopupWindow.Services.Sell)); } } // Bank? else if (playerEnterExit.BuildingDiscoveryData.buildingType == DFLocation.BuildingTypes.Bank) { uiManager.PushWindow(new DaggerfallMerchantServicePopupWindow(uiManager, npc, DaggerfallMerchantServicePopupWindow.Services.Banking)); } // Tavern? else if (playerEnterExit.BuildingDiscoveryData.buildingType == DFLocation.BuildingTypes.Tavern) { // for now only talk to all npc in taverns - TODO: add tavern option in here GameManager.Instance.TalkManager.TalkToStaticNPC(npc); } } // TODO - more checks for npc social types? else // if no special handling had to be done for npc with social group of type merchant: talk to the static npc { GameManager.Instance.TalkManager.TalkToStaticNPC(npc); } } else // if no special handling had to be done (all remaining npcs of the remaining social groups not handled explicitely above): default is talk to the static npc { // with one exception: guards if (npc.Data.billboardArchiveIndex == 183 && npc.Data.billboardRecordIndex == 3) // detect if clicked guard (comment Nystul: didn't find a better mechanism than billboard texture check) { return; // if guard was clicked don't open talk window } // otherwise open talk window GameManager.Instance.TalkManager.TalkToStaticNPC(npc); } }
void CompleteDeath() { if (!entityBehaviour) { return; } // If enemy associated with quest system, make sure quest system is done with it first QuestResourceBehaviour questResourceBehaviour = GetComponent <QuestResourceBehaviour>(); if (questResourceBehaviour) { if (!questResourceBehaviour.IsFoeDead) { return; } } // Play body collapse sound if (DaggerfallUI.Instance.DaggerfallAudioSource) { AudioClip collapseSound = DaggerfallUI.Instance.DaggerfallAudioSource.GetAudioClip((int)SoundClips.BodyFall); AudioSource.PlayClipAtPoint(collapseSound, entityBehaviour.transform.position, 1.05f); } // Disable enemy gameobject // Do not destroy as we must still save enemy state when dead gameObject.SetActive(false); // Show death message string deathMessage = HardStrings.thingJustDied; deathMessage = deathMessage.Replace("%s", mobile.Summary.Enemy.Name); DaggerfallUI.Instance.PopupMessage(deathMessage); // Generate lootable corpse marker DaggerfallLoot loot = GameObjectHelper.CreateLootableCorpseMarker( GameManager.Instance.PlayerObject, entityBehaviour.gameObject, enemyEntity, mobile.Summary.Enemy.CorpseTexture, DaggerfallUnity.NextUID); // Generate items loot.GenerateItems(); // This is still required so enemy equipment is not marked as equipped // This item collection is transferred to loot container below for (int i = (int)Items.EquipSlots.Head; i <= (int)Items.EquipSlots.Feet; i++) { Items.DaggerfallUnityItem item = enemyEntity.ItemEquipTable.GetItem((Items.EquipSlots)i); if (item != null) { enemyEntity.ItemEquipTable.UnequipItem((Items.EquipSlots)i); } } // Chance of adding map loot.RandomlyAddMap(mobile.Summary.Enemy.MapChance); if (!string.IsNullOrEmpty(mobile.Summary.Enemy.LootTableKey)) { // Chance of adding potion loot.RandomlyAddPotion(3); // Chance of adding potion recipe loot.RandomlyAddPotionRecipe(2); } entityBehaviour.CorpseLootContainer = loot; // Transfer any items owned by entity to loot container // Many quests will stash a reward in enemy inventory for player to find // This will be in addition to normal random loot table generation loot.Items.TransferAll(entityBehaviour.Entity.Items); // Raise static event if (OnEnemyDeath != null) { OnEnemyDeath(this, null); } }
public void RestoreSaveData(object dataIn) { if (!enemy) { return; } EnemyData_v1 data = (EnemyData_v1)dataIn; if (data.loadID != LoadID) { return; } DaggerfallEntityBehaviour entityBehaviour = enemy.GetComponent <DaggerfallEntityBehaviour>(); EnemySenses senses = enemy.GetComponent <EnemySenses>(); EnemyMotor motor = enemy.GetComponent <EnemyMotor>(); EnemyEntity entity = entityBehaviour.Entity as EnemyEntity; // Restore enemy career or class if different if (entity == null || entity.EntityType != data.entityType || entity.CareerIndex != data.careerIndex) { SetupDemoEnemy setupEnemy = enemy.GetComponent <SetupDemoEnemy>(); setupEnemy.ApplyEnemySettings(data.entityType, data.careerIndex, data.mobileGender, data.isHostile); setupEnemy.AlignToGround(); if (entity == null) { entity = entityBehaviour.Entity as EnemyEntity; } } // Quiesce entity during state restore entity.Quiesce = true; // Restore enemy data entityBehaviour.gameObject.name = data.gameObjectName; enemy.transform.position = data.currentPosition; enemy.transform.rotation = data.currentRotation; entity.Items.DeserializeItems(data.items); entity.ItemEquipTable.DeserializeEquipTable(data.equipTable, entity.Items); entity.MaxHealth = data.startingHealth; entity.CurrentHealth = data.currentHealth; entity.CurrentFatigue = data.currentFatigue; entity.CurrentMagicka = data.currentMagicka; motor.IsHostile = data.isHostile; senses.HasEncounteredPlayer = data.hasEncounteredPlayer; // Disable dead enemies if (data.isDead) { entityBehaviour.gameObject.SetActive(false); } // Restore quest resource link enemy.QuestSpawn = data.questSpawn; if (enemy.QuestSpawn) { // Add QuestResourceBehaviour to GameObject QuestResourceBehaviour questResourceBehaviour = entityBehaviour.gameObject.AddComponent <QuestResourceBehaviour>(); questResourceBehaviour.RestoreSaveData(data.questResource); } // Resume entity entity.Quiesce = false; }
void CompleteDeath() { if (!entityBehaviour) { return; } // If enemy associated with quest system, make sure quest system is done with it first QuestResourceBehaviour questResourceBehaviour = GetComponent <QuestResourceBehaviour>(); if (questResourceBehaviour) { if (!questResourceBehaviour.IsFoeDead) { return; } } // Disable enemy gameobject // Do not destroy as we must still save enemy state when dead gameObject.SetActive(false); // Show death message string deathMessage = TextManager.Instance.GetLocalizedText("thingJustDied"); deathMessage = deathMessage.Replace("%s", TextManager.Instance.GetLocalizedEnemyName(mobile.Summary.Enemy.ID)); DaggerfallUI.Instance.PopupMessage(deathMessage); // Generate lootable corpse marker DaggerfallLoot loot = GameObjectHelper.CreateLootableCorpseMarker( GameManager.Instance.PlayerObject, entityBehaviour.gameObject, enemyEntity, mobile.Summary.Enemy.CorpseTexture, DaggerfallUnity.NextUID); // This is still required so enemy equipment is not marked as equipped // This item collection is transferred to loot container below for (int i = (int)Items.EquipSlots.Head; i <= (int)Items.EquipSlots.Feet; i++) { Items.DaggerfallUnityItem item = enemyEntity.ItemEquipTable.GetItem((Items.EquipSlots)i); if (item != null) { enemyEntity.ItemEquipTable.UnequipItem((Items.EquipSlots)i); } } entityBehaviour.CorpseLootContainer = loot; // Transfer any items owned by entity to loot container // Many quests will stash a reward in enemy inventory for player to find // This will be in addition to normal random loot table generation loot.Items.TransferAll(entityBehaviour.Entity.Items); // Play body collapse sound if (DaggerfallUI.Instance.DaggerfallAudioSource) { DaggerfallUI.Instance.DaggerfallAudioSource.PlayClipAtPoint(SoundClips.BodyFall, loot.transform.position, 1f); } // Lower enemy alert state on player now that enemy is dead // If this is final enemy targeting player then alert state will remain clear // Other enemies still targeting player will continue to raise alert state every update EnemySenses senses = entityBehaviour.GetComponent <EnemySenses>(); if (senses && senses.Target == GameManager.Instance.PlayerEntityBehaviour) { GameManager.Instance.PlayerEntity.SetEnemyAlert(false); } // Raise static event if (OnEnemyDeath != null) { OnEnemyDeath(this, null); } }
public void RestoreSaveData(object dataIn) { if (!enemy) { return; } EnemyData_v1 data = (EnemyData_v1)dataIn; if (data.loadID != LoadID) { return; } DaggerfallEntityBehaviour entityBehaviour = enemy.GetComponent <DaggerfallEntityBehaviour>(); EnemySenses senses = enemy.GetComponent <EnemySenses>(); EnemyMotor motor = enemy.GetComponent <EnemyMotor>(); EnemyEntity entity = entityBehaviour.Entity as EnemyEntity; // Restore enemy career or class if different if (entity == null || entity.EntityType != data.entityType || entity.CareerIndex != data.careerIndex) { SetupDemoEnemy setupEnemy = enemy.GetComponent <SetupDemoEnemy>(); setupEnemy.ApplyEnemySettings(data.entityType, data.careerIndex, data.mobileGender, data.isHostile); setupEnemy.AlignToGround(); if (entity == null) { entity = entityBehaviour.Entity as EnemyEntity; } } // Quiesce entity during state restore entity.Quiesce = true; // Restore enemy data entityBehaviour.gameObject.name = data.gameObjectName; enemy.transform.rotation = data.currentRotation; entity.Items.DeserializeItems(data.items); entity.ItemEquipTable.DeserializeEquipTable(data.equipTable, entity.Items); entity.MaxHealth = data.startingHealth; entity.CurrentHealth = data.currentHealth; entity.CurrentFatigue = data.currentFatigue; entity.CurrentMagicka = data.currentMagicka; motor.IsHostile = data.isHostile; senses.HasEncounteredPlayer = data.hasEncounteredPlayer; // Restore enemy position and migrate to floating y support for exteriors // Interiors seem to be working fine at this stage with any additional support // Dungeons are not involved with floating y and don't need any changes WorldContext enemyContext = GetEnemyWorldContext(enemy); if (enemyContext == WorldContext.Exterior) { RestoreExteriorPositionHandler(enemy, data, enemyContext); } else { // Everything else enemy.transform.position = data.currentPosition; } // Disable dead enemies if (data.isDead) { entityBehaviour.gameObject.SetActive(false); } // Restore quest resource link enemy.QuestSpawn = data.questSpawn; if (enemy.QuestSpawn) { // Add QuestResourceBehaviour to GameObject QuestResourceBehaviour questResourceBehaviour = entityBehaviour.gameObject.AddComponent <QuestResourceBehaviour>(); questResourceBehaviour.RestoreSaveData(data.questResource); } // Resume entity entity.Quiesce = false; }