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);
}
}
}
}