/* =========================================================================== Copyright (C) 2015-2019 Project Meteor Dev Team This file is part of Project Meteor Server. Project Meteor Server is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Project Meteor Server is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with Project Meteor Server. If not, see . =========================================================================== */ using Meteor.Common; using Meteor.Map.actors.area; using Meteor.Map.actors.group; using Meteor.Map.Actors; using Meteor.Map.lua; using Meteor.Map.packets.send.actor; using MoonSharp.Interpreter; using System; using System.Collections.Generic; namespace Meteor.Map.actors.director { class Director : Actor { private uint directorId; private string directorScriptPath; private List members = new List(); protected ContentGroup contentGroup; private bool isCreated = false; private bool isDeleted = false; private bool isDeleting = false; private Script directorScript; private Coroutine currentCoroutine; public Director(uint id, Area zone, string directorPath, bool hasContentGroup, params object[] args) : base((6 << 28 | zone.actorId << 19 | (uint)id)) { directorId = id; this.zone = zone; this.zoneId = zone.actorId; directorScriptPath = directorPath; LoadLuaScript(); if (hasContentGroup) contentGroup = Server.GetWorldManager().CreateContentGroup(this, GetMembers()); eventConditions = new EventList(); eventConditions.noticeEventConditions = new List(); eventConditions.noticeEventConditions.Add(new EventList.NoticeEventCondition("noticeEvent", 0xE,0x0)); eventConditions.noticeEventConditions.Add(new EventList.NoticeEventCondition("noticeRequest", 0x0, 0x1)); eventConditions.noticeEventConditions.Add(new EventList.NoticeEventCondition("reqForChild", 0x0, 0x1)); } public override SubPacket CreateScriptBindPacket() { List actualLParams = new List(); actualLParams.Insert(0, new LuaParam(2, classPath)); actualLParams.Insert(1, new LuaParam(4, 4)); actualLParams.Insert(2, new LuaParam(4, 4)); actualLParams.Insert(3, new LuaParam(4, 4)); actualLParams.Insert(4, new LuaParam(4, 4)); actualLParams.Insert(5, new LuaParam(4, 4)); List lparams = LuaEngine.GetInstance().CallLuaFunctionForReturn(null, this, "init", false); for (int i = 1; i < lparams.Count; i++) actualLParams.Add(lparams[i]); return ActorInstantiatePacket.BuildPacket(actorId, actorName, className, actualLParams); } public override List GetSpawnPackets(ushort spawnType = 1) { List subpackets = new List(); subpackets.Add(CreateAddActorPacket(0)); subpackets.AddRange(GetEventConditionPackets()); subpackets.Add(CreateSpeedPacket()); subpackets.Add(CreateSpawnPositonPacket(0)); subpackets.Add(CreateNamePacket()); subpackets.Add(CreateStatePacket()); subpackets.Add(CreateIsZoneingPacket()); subpackets.Add(CreateScriptBindPacket()); return subpackets; } public override List GetInitPackets() { List subpackets = new List(); SetActorPropetyPacket initProperties = new SetActorPropetyPacket("/_init"); initProperties.AddTarget(); subpackets.Add(initProperties.BuildPacket(actorId)); return subpackets; } public void OnTalkEvent(Player player, Npc npc) { LuaEngine.GetInstance().CallLuaFunction(player, this, "onTalkEvent", false, npc); } public void OnCommandEvent(Player player, Command command) { LuaEngine.GetInstance().CallLuaFunction(player, this, "onCommandEvent", false, command); } public void StartDirector(bool spawnImmediate, params object[] args) { object[] args2 = new object[args.Length + 1]; args2[0] = this; Array.Copy(args, 0, args2, 1, args.Length); List lparams = CallLuaScript("init", args2); if (lparams != null && lparams.Count >= 1 && lparams[0].value is string) { classPath = (string)lparams[0].value; className = classPath.Substring(classPath.LastIndexOf("/") + 1); GenerateActorName((int)directorId); isCreated = true; } if (isCreated && spawnImmediate) { if (contentGroup != null) contentGroup.Start(); foreach (Player p in GetPlayerMembers()) { p.QueuePackets(GetSpawnPackets()); p.QueuePackets(GetInitPackets()); } } if (this is GuildleveDirector) { ((GuildleveDirector)this).LoadGuildleve(); } CallLuaScript("main", this, contentGroup); } public void StartContentGroup() { if (contentGroup != null) contentGroup.Start(); } public void EndDirector() { isDeleting = true; if (contentGroup != null) contentGroup.DeleteGroup(); if (this is GuildleveDirector) ((GuildleveDirector)this).EndGuildleveDirector(); List players = GetPlayerMembers(); foreach (Actor player in players) ((Player)player).RemoveDirector(this); members.Clear(); isDeleted = true; Server.GetWorldManager().GetZone(zoneId).DeleteDirector(actorId); } public void AddMember(Actor actor) { if (!members.Contains(actor)) { members.Add(actor); if (actor is Player) ((Player)actor).AddDirector(this); if (contentGroup != null) contentGroup.AddMember(actor); } } public void RemoveMember(Actor actor) { if (members.Contains(actor)) members.Remove(actor); if (contentGroup != null) contentGroup.RemoveMember(actor.actorId); if (GetPlayerMembers().Count == 0 && !isDeleting) EndDirector(); } public List GetMembers() { return members; } public List GetPlayerMembers() { return members.FindAll(s => s is Player); } public List GetNpcMembers() { return members.FindAll(s => s is Npc); } public bool IsCreated() { return isCreated; } public bool IsDeleted() { return isDeleted; } public bool HasContentGroup() { return contentGroup != null; } public ContentGroup GetContentGroup() { return contentGroup; } public void GenerateActorName(int actorNumber) { //Format Class Name string className = this.className; className = char.ToLowerInvariant(className[0]) + className.Substring(1); //Format Zone Name string zoneName = zone.zoneName.Replace("Field", "Fld") .Replace("Dungeon", "Dgn") .Replace("Town", "Twn") .Replace("Battle", "Btl") .Replace("Test", "Tes") .Replace("Event", "Evt") .Replace("Ship", "Shp") .Replace("Office", "Ofc"); if (zone is PrivateArea) { //Check if "normal" zoneName = zoneName.Remove(zoneName.Length - 1, 1) + "P"; } zoneName = char.ToLowerInvariant(zoneName[0]) + zoneName.Substring(1); try { className = className.Substring(0, 20 - zoneName.Length); } catch (ArgumentOutOfRangeException) { } //Convert actor number to base 63 string classNumber = Utils.ToStringBase63(actorNumber); //Get stuff after @ uint zoneId = zone.actorId; uint privLevel = 0; if (zone is PrivateArea) privLevel = ((PrivateArea)zone).GetPrivateAreaType(); actorName = string.Format("{0}_{1}_{2}@{3:X3}{4:X2}", className, zoneName, classNumber, zoneId, privLevel); } public string GetScriptPath() { return directorScriptPath; } private void LoadLuaScript() { string luaPath = string.Format(LuaEngine.FILEPATH_DIRECTORS, GetScriptPath()); directorScript = LuaEngine.LoadScript(luaPath); if (directorScript == null) Program.Log.Error("Could not find script for director {0}.", GetName()); } private List CallLuaScript(string funcName, params object[] args) { if (directorScript != null) { directorScript = LuaEngine.LoadScript(string.Format(LuaEngine.FILEPATH_DIRECTORS, directorScriptPath)); if (!directorScript.Globals.Get(funcName).IsNil()) { DynValue result = directorScript.Call(directorScript.Globals[funcName], args); List lparams = LuaUtils.CreateLuaParamList(result); return lparams; } else Program.Log.Error("Could not find script for director {0}.", GetName()); } return null; } private List StartCoroutine(string funcName, params object[] args) { if (directorScript != null) { if (!directorScript.Globals.Get(funcName).IsNil()) { currentCoroutine = directorScript.CreateCoroutine(directorScript.Globals[funcName]).Coroutine; DynValue value = currentCoroutine.Resume(args); LuaEngine.GetInstance().ResolveResume(null, currentCoroutine, value); } else Program.Log.Error("Could not find script for director {0}.", GetName()); } return null; } public void OnEventStart(Player player, object[] args) { object[] args2 = new object[args.Length + (player == null ? 1 : 2)]; Array.Copy(args, 0, args2, (player == null ? 1 : 2), args.Length); if (player != null) { args2[0] = player; args2[1] = this; } else args2[0] = this; Coroutine coroutine = directorScript.CreateCoroutine(directorScript.Globals["onEventStarted"]).Coroutine; DynValue value = coroutine.Resume(args2); LuaEngine.GetInstance().ResolveResume(player, coroutine, value); } } }