using System;
using System.Linq;
using System.Threading.Tasks;
using DiIiS_NA.Core.Logging;
using DiIiS_NA.Core.MPQ;
using DiIiS_NA.Core.MPQ.FileFormats;
using DiIiS_NA.GameServer.Core.Types.SNO;
using DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations;
using DiIiS_NA.GameServer.MessageSystem;
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.ACD;
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Artisan;
using DiIiS_NA.GameServer.MessageSystem.Message.Fields;
using DiIiS_NA.GameServer.ClientSystem;
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Base;
using DiIiS_NA.GameServer.GSSystem.PowerSystem;
using DiIiS_NA.GameServer.Core.Types.Math;
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Conversation;
using System.Collections.Concurrent;
using DiIiS_NA.Core.Extensions;
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Quest;
using DiIiS_NA.GameServer.MessageSystem.Message.Definitions.Platinum;
using DiIiS_NA.D3_GameServer.Core.Types.SNO;
using DiIiS_NA.GameServer.Core.Types.TagMap;
namespace DiIiS_NA.GameServer.GSSystem.PlayerSystem
{
///
/// Wraps a conversation asset and manages the whole conversation
///
public class Conversation
{
Logger Logger = new Logger("Conversation");
public event EventHandler ConversationEnded;
public int ConvPiggyBack
{
get { return asset.snoConvPiggyback; }
}
public int SNOId = -1;
public ConversationTypes ConversationType
{
get { return asset.ConversationType; }
}
private DiIiS_NA.Core.MPQ.FileFormats.Conversation asset
{
get
{
return (DiIiS_NA.Core.MPQ.FileFormats.Conversation)MPQStorage.Data.Assets[SNOGroup.Conversation][SNOId]
.Data;
}
}
private int LineIndex = 0; // index within the RootTreeNodes, conversation progress
private Player player;
private ConversationManager manager;
private int currentUniqueLineID; // id used to identify the current line clientside
private int startTick = 0; // start tick of the current line. used to determine, when to start the next line
private ConversationTreeNode currentLineNode = null;
private int endTick = 0;
// Find a childnode with a matching class id, that one holds information about how long the speaker talks
// If there is no matching childnode, there must be one with -1 which only combines all class specific into one
private int GetDuration()
{
var node = currentLineNode.ChildNodes.FirstOrDefault(a => a.ClassFilter == player.Toon.VoiceClassID);
node ??= currentLineNode.ChildNodes.FirstOrDefault(a => a.ClassFilter == -1);
if (node == null)
{
return 1;
}
return node.CompressedDisplayTimes[(int)manager.ClientLanguage]
.Languages[player.Toon.VoiceClassID * 2 + (player.Toon.Gender == 0 ? 0 : 1)];
}
// This returns the dynamicID of other conversation partners. The client uses its position to identify where you can hear the conversation.
// This implementation relies on there beeing exactly one actor with a given sno in the world!!
// TODO add actor identification for Followers
private ActorSystem.Actor GetSpeaker(Speaker speaker)
{
switch (speaker)
{
case Speaker.AltNPC1:
return GetActorBySNO((ActorSno)asset.SNOAltNpc1);
case Speaker.AltNPC2:
return GetActorBySNO((ActorSno)asset.SNOAltNpc2);
case Speaker.AltNPC3:
return GetActorBySNO((ActorSno)asset.SNOAltNpc3);
case Speaker.AltNPC4:
return GetActorBySNO((ActorSno)asset.SNOAltNpc4);
case Speaker.Player:
return player;
case Speaker.PrimaryNPC:
return GetActorBySNO((ActorSno)asset.SNOPrimaryNpc);
case Speaker.EnchantressFollower:
case Speaker.ScoundrelFollower:
case Speaker.TemplarFollower:
case Speaker.None:
return null;
}
return null;
}
private ActorSystem.Actor GetActorBySNO(ActorSno sno)
{
ActorSystem.Actor SearchFunc(ActorSno a) => player.World.Actors.Values
.Where(actor => actor.SNO == a && actor.IsRevealedToPlayer(player))
.OrderBy((actor) => PowerMath.Distance2D(actor.Position, player.Position)).FirstOrDefault();
//if (sno == 121208)
// sno = 4580; //hack
var result = SearchFunc(sno);
if (result != null)
{
//result.Reveal(player);
return result;
}
if (sno == ActorSno._templarnpc)
{
return SearchFunc(ActorSno._templarnpc_imprisoned);
}
else
{
result = SearchFunc(sno);
if (result == null)
//return player;
return player.World.SpawnMonster(sno,
new Vector3D(player.Position.X, player.Position.Y, player.Position.Z + 150));
else
{
result.Reveal(player);
return result;
}
}
}
///
/// Creates a new conversation wrapper for an asset with a given sno.
///
/// sno of the asset to wrap
/// player that receives messages
/// the quest manager that provides ids
public Conversation(int snoConversation, Player player, ConversationManager manager)
{
SNOId = snoConversation;
this.player = player;
this.manager = manager;
}
///
/// Starts the conversation
///
public void Start()
{
try
{
PlayLine(LineIndex);
}
catch
{
Logger.Warn("Conversation start error!");
}
//if (this.SNOId == 181330) fullHeal(); //TODO this
}
///
/// Immediatly ends the conversation
///
public void Stop()
{
StopLine(true);
EndConversation();
}
///
/// Sets a new end tick for line playback
///
///
public void UpdateAdvance(int endTick)
{
this.endTick = endTick;
}
///
/// Skips to the next line of the conversation
///
public void Interrupt()
{
PlayNextLine(true);
}
///
/// Periodically call this method to make sure conversation progresses
///
public void Update(int tickCounter)
{
if (endTick > 0 && currentLineNode == null)
PlayNextLine(false);
else
{
try
{
// rotate the primary speaker to face the secondary speaker
if (currentLineNode != null)
if (currentLineNode.LineSpeaker != Speaker.Player &&
currentLineNode.SpeakerTarget != Speaker.None)
{
var speaker1 = GetSpeaker(currentLineNode.LineSpeaker);
var speaker2 = GetSpeaker(currentLineNode.SpeakerTarget);
if (!(speaker1 is Player) && speaker2.Position != speaker1.Position) //prevent spinning bug
{
Vector3D translation = speaker2.Position - speaker1.Position;
Vector2F flatTranslation = new Vector2F(translation.X, translation.Y);
float facingAngle = flatTranslation.Rotation();
speaker1.SetFacingRotation(facingAngle);
player.World.BroadcastIfRevealed(plr => new ACDTranslateFacingMessage
{
ActorId = speaker1.DynamicID(plr),
Angle = facingAngle,
TurnImmediately = false
}, speaker1);
}
}
// start the next line if the playback has finished
if (tickCounter > endTick)
PlayNextLine(false);
}
catch
{
Logger.Trace("Conv error");
EndConversation();
}
}
}
///
/// Stops current line and starts the next if there is one, or ends the conversation
///
/// sets, whether the speaker is interrupted
public void PlayNextLine(bool interrupt)
{
StopLine(interrupt);
if (asset.RootTreeNodes.Count > LineIndex + 1)
PlayLine(++LineIndex);
else
EndConversation();
}
///
/// Ends the conversation, though i dont know, what it actually does. This is only through observation
///
private void EndConversation()
{
player.InGameClient.SendMessage(new EndConversationMessage()
{
SNOConversation = asset.Header.SNOId,
ActorId = player.DynamicID(player),
Field2 = -1
});
if (asset.ConversationType != ConversationTypes.AmbientFloat &&
asset.ConversationType != ConversationTypes.GlobalFloat)
player.CheckConversationCriteria(asset.Header.SNOId);
Logger.Debug("Handling conversation for Conversation: {0}", SNOId);
if (player.World.Game.QuestProgress.QuestTriggers.ContainsKey(SNOId))
{
var trigger = player.World.Game.QuestProgress.QuestTriggers[SNOId];
if (trigger.TriggerType == QuestStepObjectiveType.HadConversation)
{
try
{
trigger.QuestEvent.Execute(player.World); // launch a questEvent
}
catch (Exception e)
{
Logger.WarnException(e, "questEvent()");
}
}
}
if (player.World.Game.SideQuestProgress.QuestTriggers.ContainsKey(SNOId)) //EnterLevelArea
{
var trigger = player.World.Game.SideQuestProgress.QuestTriggers[SNOId];
if (trigger.TriggerType == QuestStepObjectiveType.HadConversation)
{
try
{
trigger.QuestEvent.Execute(player.World); // launch a questEvent
}
catch (Exception e)
{
Logger.WarnException(e, "questEvent()");
}
}
}
if (player.World.Game.SideQuestProgress.GlobalQuestTriggers.ContainsKey(SNOId))
{
var trigger = player.World.Game.SideQuestProgress.GlobalQuestTriggers[SNOId];
if (trigger.TriggerType == QuestStepObjectiveType.HadConversation)
{
try
{
trigger.QuestEvent.Execute(player.World); // launch a questEvent
player.World.Game.SideQuestProgress.GlobalQuestTriggers.Remove(SNOId);
}
catch (Exception e)
{
Logger.WarnException(e, "questEvent()");
}
}
}
if (ConversationEnded != null)
ConversationEnded(this, null);
if (SNOId == 72817) //Tristram parom man
{
var world = player.World.Game.GetWorld(WorldSno.trout_townattack);
player.ChangeWorld(world, world.GetStartingPointById(116).Position);
}
else if (SNOId == 208400) //Cow king
{
var portal = player.World.Game.GetWorld(WorldSno.trout_town)
.GetActorBySNO(ActorSno._g_portal_tentacle_trist);
(portal as WhimsyshirePortal).Open();
}
else if (SNOId == 275450) //PvP hub gatekeeper
{
player.ShowConfirmation(player.DynamicID(player), (() =>
{
var world = player.World.Game.GetWorld(WorldSno.pvp_duel_small_multi);
player.ChangeWorld(world, world.GetStartingPointById(288).Position);
}));
}
else if (SNOId == 340878)
{
foreach (var plr in player.InGameClient.Game.Players.Values)
{
if (player.InGameClient.Game.NephalemGreater)
{
plr.Attributes[GameAttributes.Jewel_Upgrades_Max] = 0;
plr.Attributes[GameAttributes.Jewel_Upgrades_Bonus] = 0;
plr.Attributes[GameAttributes.Jewel_Upgrades_Used] = 0;
plr.InGameClient.SendMessage(new QuestCounterMessage()
{
snoQuest = 0x00052654,
snoLevelArea = 0x000466E2,
StepID = 46,
TaskIndex = 0,
Checked = 1,
Counter = 1
});
plr.InGameClient.SendMessage(new QuestUpdateMessage()
{
snoQuest = 0x00052654,
snoLevelArea = 0x000466E2,
StepID = 5,
DisplayButton = true,
Failed = false
});
plr.InGameClient.SendMessage(new DungeonFinderClosingMessage()
{
Field0 = 26396,
Field1 = 0
});
//RiftEndScreenInfoBlobMessage - 524
plr.InGameClient.SendMessage(new GenericBlobMessage(Opcodes.RiftEndScreenInfoBlobMessage)
{
Data = D3.GameMessage.RiftEndScreenInfo.CreateBuilder()
.SetNewPersonalBest(true)
.SetSuccess(true)
.SetIsFromCheat(false)
.SetRiftTier(plr.InGameClient.Game.NephalemGreaterLevel + 1)
.AddParticipantGameAccounts(D3.OnlineService.GameAccountHandle.CreateBuilder()
.SetId((uint)plr.Toon.GameAccount.BnetEntityId.Low).SetProgram(17459).SetRegion(1))
.SetGoldReward(5000 * plr.Level)
.SetXpReward(50000 * (long)plr.Level)
.SetCompletionTimeMs(900 * 1000 - plr.InGameClient.Game.LastTieredRiftTimeout * 1000)
.SetBannerConfiguration(plr.Toon.GameAccount.BannerConfigurationField.Value)
.Build().ToByteArray()
});
player.InGameClient.SendMessage(new PlatinumAwardedMessage
{
CurrentPlatinum = player.InGameClient.BnetClient.Account.GameAccount.Platinum,
PlatinumIncrement = 5
});
player.InGameClient.BnetClient.Account.GameAccount.Platinum += 5;
plr.UpdateExp(50000 * plr.Level);
plr.Inventory.AddGoldAmount(5000 * plr.Level);
}
else
{
plr.InGameClient.SendMessage(new QuestCounterMessage()
{
snoQuest = 0x00052654,
snoLevelArea = 0x000466E2,
StepID = 10,
TaskIndex = 0,
Checked = 1,
Counter = 1
});
plr.InGameClient.SendMessage(new QuestUpdateMessage()
{
snoQuest = 0x00052654,
snoLevelArea = 0x000466E2,
StepID = 5,
DisplayButton = true,
Failed = false
});
plr.InGameClient.SendMessage(new QuestStepCompleteMessage()
{
QuestStepComplete = D3.Quests.QuestStepComplete.CreateBuilder()
.SetIsQuestComplete(true)
.SetWasRewardAutoequipped(false)
.SetReward(D3.Quests.QuestReward.CreateBuilder().SetPlatinumGranted(1)
.SetGoldGranted(1000 * plr.Level).SetBonusXpGranted(10000 * (ulong)plr.Level))
.Build()
});
player.InGameClient.SendMessage(new PlatinumAwardedMessage
{
CurrentPlatinum = player.InGameClient.BnetClient.Account.GameAccount.Platinum,
PlatinumIncrement = 1
});
player.InGameClient.BnetClient.Account.GameAccount.Platinum += 1;
plr.Inventory.AddGoldAmount(1000 * plr.Level);
player.GrantCriteria(74987243379080);
if (player.InGameClient.Game.Difficulty >= 2)
{
player.GrantCriteria(74987250579270);
if (player.InGameClient.Game.Difficulty >= 3)
player.GrantCriteria(74987247265988);
}
}
//Таймер до закрытия
/*
plr.InGameClient.SendMessage(new DungeonFinderClosingMessage()
{
Field0 = 51605,
Field1 = -1
});
//*/
//Обнуляем прогресс
plr.InGameClient.SendMessage(new FloatDataMessage(Opcodes.DungeonFinderProgressMessage)
{
Field0 = 0
});
plr.InGameClient.SendMessage(new SNODataMessage(Opcodes.DungeonFinderSetTimedEvent)
{
Field0 = 0
});
}
player.InGameClient.Game.ActiveNephalemKilledBoss = false;
player.InGameClient.Game.ActiveNephalemKilledMobs = false;
player.InGameClient.Game.ActiveNephalemPortal = false;
player.InGameClient.Game.ActiveNephalemTimer = false;
player.InGameClient.Game.ActiveNephalemProgress = 0;
//Enabled banner /advocaite
player.Attributes[GameAttributes.Banner_Usable] = true;
var HubWorld = player.InGameClient.Game.GetWorld(WorldSno.x1_tristram_adventure_mode_hub);
var NStone = HubWorld.GetActorBySNO(ActorSno._x1_openworld_lootrunobelisk_b);
bool Activated = true;
NStone.SetIdleAnimation((AnimationSno)NStone.AnimationSet.TagMapAnimDefault[AnimationSetKeys.IdleDefault]);
NStone.PlayActionAnimation((AnimationSno)NStone.AnimationSet.TagMapAnimDefault[AnimationSetKeys.Closing]);
NStone.Attributes[GameAttributes.Team_Override] = (Activated ? -1 : 2);
NStone.Attributes[GameAttributes.Untargetable] = !Activated;
NStone.Attributes[GameAttributes.NPC_Is_Operatable] = Activated;
NStone.Attributes[GameAttributes.Operatable] = Activated;
NStone.Attributes[GameAttributes.Operatable_Story_Gizmo] = Activated;
NStone.Attributes[GameAttributes.Disabled] = !Activated;
NStone.Attributes[GameAttributes.Immunity] = !Activated;
NStone.Attributes.BroadcastChangedIfRevealed();
foreach (var p in HubWorld.GetActorsBySNO(ActorSno._x1_openworld_lootrunportal,
ActorSno._x1_openworld_tiered_rifts_portal))
p.Destroy();
}
}
///
/// Stops readout and display of current conversation line
///
/// sets whether the speaker is interrupted or not
private void StopLine(bool interrupted)
{
player.InGameClient.SendMessage(new StopConvLineMessage()
{
PlayLineParamsId = currentUniqueLineID,
Interrupt = interrupted,
});
}
///
/// Starts readout and display of a certain conversation line
///
/// index of the line withing the rootnodes
private void PlayLine(int lineIndex)
{
if (asset.RootTreeNodes[lineIndex].ConvNodeType == 6)
{
currentLineNode = null;
return;
}
if (asset.RootTreeNodes[lineIndex].ConvNodeType == 4)
currentLineNode = asset.RootTreeNodes[lineIndex].ChildNodes.PickRandom();
else
currentLineNode = asset.RootTreeNodes[lineIndex];
currentUniqueLineID = manager.GetNextUniqueLineID();
if (!GetSpeaker(currentLineNode.LineSpeaker).IsRevealedToPlayer(player))
GetSpeaker(currentLineNode.LineSpeaker).Reveal(player);
var duration = GetDuration();
startTick = player.World.Game.TickCounter;
endTick = startTick + duration;
// TODO Actor id should be CurrentSpeaker.DynamicID not PrimaryNPC.ActorID. This is a workaround because no audio for the player is playing otherwise
player.InGameClient.SendMessage(new PlayConvLineMessage()
{
ActorID = GetSpeaker(currentLineNode.LineSpeaker)
.DynamicID(player), // GetActorBySNO(asset.SNOPrimaryNpc).DynamicID,
Field1 = new[]
{
player.DynamicID(player),
asset.SNOPrimaryNpc != -1
? GetActorBySNO((ActorSno)asset.SNOPrimaryNpc).DynamicID(player)
: 0xFFFFFFFF,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
},
PlayLineParams = new PlayLineParams()
{
SNOConversation = asset.Header.SNOId,
SpeakingPlayerIndex = 0x00000000,
Zoom = false,
FirstLine = true,
Hostiile = false,
PlayerInitiated = true,
LineID = currentLineNode.LineID,
Speaker = currentLineNode.LineSpeaker,
LineGender = -1,
AudioClass = (GameBalance.Class)player.Toon.VoiceClassID,
Gender = (player.Toon.Gender == 0) ? VoiceGender.Male : VoiceGender.Female,
TextClass = currentLineNode.LineSpeaker == Speaker.Player
? (GameBalance.Class)player.Toon.VoiceClassID
: GameBalance.Class.None,
SNOSpeakerActor = (int)GetSpeaker(currentLineNode.LineSpeaker).SNO,
LineFlags = 0x00000000,
AnimationTag = currentLineNode.AnimationTag,
Duration = duration,
Id = currentUniqueLineID,
Priority = 0x00000000
},
Duration = duration,
}); //, true);
}
}
public class ConversationManager
{
Logger Logger = new Logger("ConversationManager");
internal enum Language
{
Invalid,
Global,
enUS,
enGB,
enSG,
esES,
esMX,
frFR,
itIT,
deDE,
koKR,
ptBR,
ruRU,
zhCN,
zTW,
trTR,
plPL,
ptPT
}
private Player player;
private ConcurrentDictionary openConversations =
new ConcurrentDictionary();
private int linesPlayedTotal = 0;
internal Language ClientLanguage
{
get { return Language.enUS; }
}
internal int GetNextUniqueLineID()
{
return linesPlayedTotal++;
}
public ConversationManager(Player player)
{
this.player = player;
}
///
/// Stops all conversations
///
public void StopAll()
{
foreach (var pair in openConversations)
pair.Value.Stop();
}
///
/// Starts and plays a conversation
///
/// SnoID of the conversation
public void StartConversation(int snoConversation)
{
if (!MPQStorage.Data.Assets[SNOGroup.Conversation].ContainsKey(snoConversation))
{
Logger.Warn("Conversation not found: {0}", snoConversation);
return;
}
if (snoConversation != 131349)
if (!openConversations.ContainsKey(snoConversation))
{
#if DEBUG
Logger.Warn("Conversation started: {0}", snoConversation);
#endif
Conversation newConversation = new Conversation(snoConversation, player, this);
newConversation.Start();
newConversation.ConversationEnded += new EventHandler(ConversationEnded);
openConversations.TryAdd(snoConversation, newConversation);
#region События по началу диалогов
switch (snoConversation)
{
case 198199:
//Task.Delay(1000).Wait();
break;
}
#endregion
}
}
///
/// Remove conversation from the list of open conversations and start its piggyback conversation
///
void ConversationEnded(object sender, EventArgs e)
{
Conversation conversation = sender as Conversation;
Logger.Debug(" (ConversationEnded) Sending a notify with type {0} and value {1}",
conversation.ConversationType, conversation.SNOId);
//quests.Notify(QuestStepObjectiveType.HadConversation, conversation.SNOId); //deprecated
//Conversation ended
if (player.PlayerIndex == 0)
switch (conversation.SNOId)
{
#region Events after Dialogs
#region A1-Q2
case 17667:
//var BlacksmithQuest = player.InGameClient.Game.GetWorld(71150).GetActorBySNO(65036,true);
var world = player.InGameClient.Game.GetWorld(WorldSno.trdun_cain_intro);
var cainBrains = world.GetActorBySNO(ActorSno._cain_intro, true);
Vector3D cainPath = new Vector3D(76.99389f, 155.145f, 0.0997252f);
var facingAngle = ActorSystem.Movement.MovementHelpers.GetFacingAngle(cainBrains, cainPath);
cainBrains.Move(cainPath, facingAngle);
var a1Q2Wait1 = Task.Delay(7000).ContinueWith(delegate
{
var actor = world.GetActorsBySNO(ActorSno._trdun_cath_bookcaseshelf_door_reverse)
.Where(d => d.Visible).FirstOrDefault();
(actor as Door).Open();
var a1Q2Wait2 = Task.Delay(2000).ContinueWith(delegate
{
cainBrains.Hidden = true;
cainBrains.Unreveal(player);
});
});
break;
#endregion
#region A1-Q3
case 198292:
var blacksmithQuest = player.InGameClient.Game.GetWorld(WorldSno.trout_town)
.GetActorBySNO(ActorSno._pt_blacksmith_nonvendor, true);
blacksmithQuest.WalkSpeed = 0.33f;
Vector3D firstPoint = new Vector3D(2905.856f, 2584.807f, 0.5997877f);
Vector3D secondPoint = new Vector3D(2790.396f, 2611.313f, 0.5997864f);
var firstfacingAngle =
ActorSystem.Movement.MovementHelpers.GetFacingAngle(blacksmithQuest, firstPoint);
var secondfacingAngle =
ActorSystem.Movement.MovementHelpers.GetFacingAngle(blacksmithQuest, secondPoint);
blacksmithQuest.Move(firstPoint, firstfacingAngle);
var listenerKingSkeletons = Task.Delay(3000).ContinueWith(delegate
{
blacksmithQuest.Move(secondPoint, secondfacingAngle);
});
break;
#endregion
//168282
#region A1-Q4
case 168282:
var wrld = player.InGameClient.Game.GetWorld(WorldSno.a1trdun_level05_templar);
foreach (var wall in wrld.GetActorsBySNO(ActorSno._trdun_cath_bonewall_a_door))
if (wall.Position.Z > -23f)
{
wall.PlayAnimation(11, AnimationSno.trdun_cath_bonewall_a_death);
wall.Attributes[GameAttributes.Deleted_On_Server] = true;
wall.Attributes[GameAttributes.Could_Have_Ragdolled] = true;
wall.Attributes.BroadcastChangedIfRevealed();
wall.Destroy();
}
break;
case 17921:
var cryptwrld = player.InGameClient.Game.GetWorld(WorldSno.a1trdun_level07);
foreach (var ghost in cryptwrld.GetActorsBySNO(ActorSno._skeletonking_ghost))
ghost.Destroy();
break;
#endregion
#region A1-Q4 Event_DoK
case 139823: //Event_DoK_Kill.cnv
//kill the king
var leoricGhost = player.World.GetActorBySNO(ActorSno._skeletonking_leoricghost);
var lachdananGhost = player.World.GetActorBySNO(ActorSno._ghostknight3);
var swordPlace =
player.World.GetActorBySNO(ActorSno._trdun_crypt_deathoftheking_sword_clickable);
lachdananGhost.Move(swordPlace.Position,
ActorSystem.Movement.MovementHelpers.GetFacingAngle(lachdananGhost, swordPlace.Position));
var listenerA1Q4Event1 = Task.Delay(4000).ContinueWith(delegate { StartConversation(139825); });
break;
case 139825: //Event_DoK_Death.cnv
var leoricGhost1 = player.World.GetActorBySNO(ActorSno._skeletonking_leoricghost);
var ghostKnights1 = player.World.GetActorsBySNO(ActorSno._ghostknight2);
var lachdananGhost1 = player.World.GetActorBySNO(ActorSno._ghostknight3);
var listenerA1Q4Event2 = Task.Delay(10000).ContinueWith(delegate
{
player.World.Leave(leoricGhost1);
player.World.Leave(lachdananGhost1);
foreach (var gk in ghostKnights1)
{
player.World.Leave(gk);
}
});
break;
#endregion
#region A1-SQ-Farmer
case 60179:
//player.InGameClient.Game.QuestManager.ClearQuests();
//player.InGameClient.Game.QuestManager.SetQuests();
player.InGameClient.Game.QuestManager.LaunchSideQuest(81925);
var nearActors = player.CurrentScene.Actors;
int foundCount = 0;
foreach (var actor in nearActors)
if (actor.SNO == ActorSno._fleshpitflyerspawner_b_event_farmambush)
{
foundCount++;
}
if (foundCount == 4)
{
Logger.Debug("All the flies are dead, the farmer can continue his work.");
}
else
{
Logger.Debug("There are still flies, kill them.");
var oldPit = player.World.GetActorsBySNO(ActorSno._fleshpitflyerspawner_b_event_farmambush);
foreach (var actor in oldPit)
player.World.Leave(actor);
var spawnerOfPits =
player.World.GetActorsBySNO(ActorSno._spawner_fleshpitflyer_b_immediate);
foreach (var actor in spawnerOfPits)
player.World.SpawnMonster(ActorSno._fleshpitflyerspawner_b_event_farmambush,
actor.Position);
var newPits =
player.World.GetActorsBySNO(ActorSno._fleshpitflyerspawner_b_event_farmambush);
Logger.Debug("The flies are dead. The farmer can continue his work.");
}
break;
#endregion
#region A5
case 308393:
var npc =
player.World.GetActorBySNO(ActorSno._x1_npc_westmarch_introguy) as
ActorSystem.InteractiveNPC;
npc.Conversations.Clear();
npc.Attributes[GameAttributes.Conversation_Icon, 0] = 1;
npc.Attributes.BroadcastChangedIfRevealed();
break;
#endregion
#endregion
}
openConversations.TryRemove(conversation.SNOId, out _);
if (conversation.ConvPiggyBack != -1)
StartConversation(conversation.ConvPiggyBack);
_conversationTrigger = true;
}
///
/// Returns true when the conversation playing finishes.
///
private bool _conversationTrigger = false;
public bool ConversationRunning()
{
var status = _conversationTrigger;
_conversationTrigger = false;
return status;
}
///
/// Update all open conversations
///
///
public void Update(int tickCounter)
{
foreach (var pair in openConversations)
pair.Value.Update(tickCounter);
}
///
/// Consumes conversations related messages
///
///
///
public void Consume(GameClient client, GameMessage message)
{
if (message is RequestCloseConversationWindowMessage)
{
foreach (var pair in openConversations)
pair.Value.Interrupt();
}
if (message is UpdateConvAutoAdvanceMessage tmpMessage)
{
if (openConversations.ContainsKey(tmpMessage.SNOConversation))
openConversations[tmpMessage.SNOConversation].UpdateAdvance(tmpMessage.EndTick);
}
if (message is AdvanceConvMessage convMessage)
{
if (openConversations.ContainsKey(convMessage.SNOConversation))
{
openConversations[convMessage.SNOConversation].PlayNextLine(true);
}
}
}
}
}