using CommonAI.Zone; using CommonAI.Zone.ZoneEditor; using System; using System.Collections.Generic; using System.Linq; using System.Text; using XmdsCommonServer.Plugin.Scene; using CommonAI.Zone.Instance; using CommonAI.Zone.Helper; using CommonLang; using System.Diagnostics; using CommonAI.Data; namespace XmdsCommonZone.Zones { /// /// 定时刷宝箱类,最初用于连服宝箱,类似的功能需要继承该类,类似于Zone80001.cs /// public class ZoneIntervalRebirthMonster : XmdsServerScene { private bool initedFromServer = false; private TimeTaskMS timeTask = null; private int maxMonsterNum = 0; private int createMonsterIntervalMS = 0; // 按时间从小到大排序 { openTime, closeTime, openTime, closeTime ... } private int[] timeOpenCloseList = null; // 按概率从小到大排序 {怪物id, 万分比概率, 怪物id,万分比概率 ...} private int[] monsterIdProbabilityList = null; private List monsterList = new List(); // monster的出生地坐标列表 private List usingPointList = new List(); private List freePointList = new List(); public ZoneIntervalRebirthMonster(TemplateManager templates, InstanceZoneListener listener, SceneData data, GSCreateAreaData gsData, string bindGameSrvId) : base(templates, listener, data, gsData, bindGameSrvId) { AddEvents(); } /// /// 从游戏服初始化场景数据 /// /// 从00点到当前的毫秒数{openTime, closeTime, openTime, closeTime ...} /// monsterId,万分比概率{monsterId, probability, monsterId, probability ...} /// 创建Monster的时间间隔,单位毫秒 /// 创建monster的最大个数 public void InitSceneDataFromGameServer(int[] timeOpenCloseList, int[] monsterIdProbabilityList, int createMonsterIntervalMS, int maxMonsterNum) { Debug.Assert(!initedFromServer, "ZoneIntervalRebirthMonster.InitSceneDataFromGameServer already call, can not call it twice"); initedFromServer = true; Log.Error("ZoneIntervalRebirthMonster.InitSceneDataFromGameServer"); this.timeOpenCloseList = SortListBySecondValue(timeOpenCloseList); this.monsterIdProbabilityList = SortListBySecondValue(monsterIdProbabilityList); this.createMonsterIntervalMS = createMonsterIntervalMS; this.maxMonsterNum = maxMonsterNum; AdjustMonsterProbability(this.monsterIdProbabilityList); if (CheckInOpenTime(0)) { TryCreateAllMonster(null); }else { timeTask = AddTimePeriodicMS(30000, WaitOpenTime); } } private void AdjustMonsterProbability(int[] list) { float n = 0; for (int i = 1; i < list.Length; i += 2) { n += list[i]; } float scale = 10000f / n; int p = 0; for (int i = 1; i < list.Length; i += 2) { list[i] = (int)(list[i] * scale) + p; p = list[i]; } list[list.Length - 1] = 10000; } private int[] SortListBySecondValue(int[] list) { int listLen = list.Length; int[] newList = new int[listLen]; bool[] freeList = new bool[listLen / 2]; for (int i = 0; i < listLen / 2; i++) freeList[i] = true; for (int n = 0; n < listLen; n += 2) { int tmpIdx = 0, probability = int.MaxValue; for (int i = 1; i < listLen; i += 2) { if (freeList[i/2] && list[i] < probability) { tmpIdx = i; probability = list[i]; } } freeList[tmpIdx/2] = false; newList[n] = list[tmpIdx - 1]; newList[n+1] = probability; } return newList; } private bool CheckInOpenTime(int offsetMillisecond) { DateTime datetime = DateTime.Now.AddMilliseconds(offsetMillisecond); int time = datetime.Hour * 3600000 + datetime.Minute * 60000 + datetime.Second * 1000 + datetime.Millisecond; for (int i = 0; i < timeOpenCloseList.Length; i += 2) { if (timeOpenCloseList[i] <= time && timeOpenCloseList[i + 1] > time) return true; } return false; } // 获得到下次开启的MS数 private int GetDeltaTimeToOpen() { DateTime datetime = DateTime.Now; int time = datetime.Hour * 3600000 + datetime.Minute * 60000 + datetime.Second * 1000 + datetime.Millisecond; for (int i = 0; i < timeOpenCloseList.Length; i += 2) { if (timeOpenCloseList[i] > time) return timeOpenCloseList[i] - time; else if (timeOpenCloseList[i + 1] > time) return 0; } return 3600000 * 24 - time + timeOpenCloseList[0]; } private void AddEvents() { OnInit += ZoneIntervalRebirthMonster_OnInit; OnUnitDead += ZoneIntervalRebirthMonster_OnUnitDead; } private void ZoneIntervalRebirthMonster_OnInit(InstanceZone zone) { Log.Error("ZoneIntervalRebirthMonster.ZoneIntervalRebirthMonster_OnInit"); int i = 1; while(true) { InstanceFlag flag = getFlag(string.Format("bz{0:00}", i++)); if (flag == null) break; freePointList.Add(flag); } // int[] timeList = { 14 * 3600000, 16 * 3600000, 16 * 3600000 + 10 * 60000, 16 * 3600000 + 30 * 60000, 17 * 3600000 , 18 * 3600000 }; // int[] monsterIdProbablilityList = new int[] { 91110, 6000, 91120,3000, 91130,1000 }; // InitSceneDataFromGameServer(timeList, monsterIdProbablilityList, 30000, 12); } private void ZoneIntervalRebirthMonster_OnUnitDead(InstanceZone zone, InstanceUnit obj, InstanceUnit attacker) { int idx = monsterList.FindIndex((unit) => { return obj == unit; }); if (idx < 0) return; freePointList.Add(usingPointList[idx]); usingPointList.RemoveAt(idx); monsterList.RemoveAt(idx); if (!CheckInOpenTime(createMonsterIntervalMS)) { if (timeTask != null) return; timeTask = AddTimePeriodicMS(30000, WaitOpenTime); return; } DelayCall(createMonsterIntervalMS, TryCreateMonster); } private void DelayCall(int delayMS, TickHandler handler) { long endTicks = DateTime.Now.Ticks + delayMS * TimeSpan.TicksPerMillisecond; AddTimePeriodicMS(1000, (TimeTaskMS task) => { if (DateTime.Now.Ticks > endTicks) { task.Stop(); handler(null); } }); } private void WaitOpenTime(TimeTaskMS task) { if (CheckInOpenTime(0)) { timeTask.Stop(); timeTask = null; TryCreateAllMonster(null); } } private void TryCreateAllMonster(TimeTaskMS task) { if (monsterList.Count >= maxMonsterNum) { return; } int n = maxMonsterNum - monsterList.Count; Log.Error("ZoneIntervalRebirthMonster TryCreateAllMonster will create count=" + n); while (--n >= 0) TryCreateMonster(null); } private void TryCreateMonster(TimeTaskMS task) { if (monsterList.Count >= maxMonsterNum) return; int probalility = RandomN.Next(0, 10000); int monsterId = 0; for (int i = 1; i < monsterIdProbabilityList.Length; i += 2) { if (probalility <= monsterIdProbabilityList[i]) { monsterId = monsterIdProbabilityList[i - 1]; break; } } if (monsterId == 0) return; int flagIdx = RandomN.Next(0, freePointList.Count); InstanceFlag flag = freePointList[flagIdx]; InstanceUnit unit = AddUnit(monsterId, null, 1, 0, flag.X, flag.Y, (float)RandomN.NextDouble() * 6.28f); if (unit != null) { monsterList.Add(unit); freePointList.RemoveAt(flagIdx); usingPointList.Add(flag); Log.Error("ZoneIntervalRebirthMonster createMonster count=" + monsterList.Count); } } } }