using System;
using System.Collections.Generic;
using System.Text;
using CommonLang;
using CommonAI.RTS;
using CommonLang.Vector;
using CommonAI.RTS.Manhattan;
using CommonAI.Zone.Helper;
using CommonAI.Data;
namespace CommonAI.Zone.Instance
{
///
/// 生成单位的触发器
///
public abstract class AbstractSpawnTrigger : Ability
{
public string Name { get; private set; }
private ZoneRegion mAdded = null;
private int mSpawnTimeIntervalMS;
private int mDelayTimeMS = 0;
private int mSpawnOnceCount;
private LaunchEffect mSpawnEffect;
private bool mSpawnWithoutAlive = true;
private bool mResetOnWithoutAlive = false;
private int mTotalSpawnCount = 0;
private int mSpawnIndexer = 0;
private int mLimitedSpawnCount = 0;
private int mLimitedAliveCount = 0;
private HashMap mSpawnedUnits = new HashMap();
private string mUnitTag;
private TimeTaskMS mTimeTask;
private float mStartDirection = float.NaN;
private TeamFormation mTeam;
private TeamFormationGroup mTeamHelper;
//绑定事件
//protected List Events = new List();
//--------------------------------------------------------------------------------------------------
public AbstractSpawnTrigger(InstanceZone zone, string name)
: base(zone)
{
this.Name = name;
}
public InstanceZone BindingZone { get { return mAdded.Parent; } }
public ZoneRegion BindingRegion { get { return mAdded; } }
public int OnceSpawnCount { get { return mSpawnOnceCount; } }
public int LimitedSpawnCount { get { return mLimitedSpawnCount; } }
public int LimitedAliveCount { get { return mLimitedAliveCount; } }
///
/// 当前存活数量
///
public virtual int AliveCount { get { return mSpawnedUnits.Count; } }
public int SpawnIndexer { get { return mSpawnIndexer; } }
public int TotalSpawnCount { get { return mTotalSpawnCount; } }
public float StartDirection { get { return (!float.IsNaN(mStartDirection)) ? mStartDirection : (float)(Zone.RandomN.NextDouble() * CMath.PI_MUL_2); } }
///
/// 是否已完成刷新
///
public bool IsSpawnOver
{
get
{
if (mLimitedSpawnCount == 0)
return false;
return (mTotalSpawnCount >= mLimitedSpawnCount);
}
}
public bool IsWaitAlive
{
get
{
if (mLimitedAliveCount == 0)
return false;
return (mSpawnedUnits.Count >= mLimitedAliveCount);
}
}
///
/// 生产单位间隔时间
///
///
public void setSpawnInterval(int interval)
{
this.mSpawnTimeIntervalMS = interval;
}
///
/// 设置每次产生个数
///
///
public void setSpawnCount(int count)
{
this.mSpawnOnceCount = count;
}
///
/// 设置出生特效
///
///
public void setSpawnEffect(LaunchEffect effect)
{
this.mSpawnEffect = effect;
}
///
/// 单位产生绑定的标志
///
///
public void setUnitTag(string tag)
{
this.mUnitTag = tag;
}
///
/// 只有当前怪物没有存活时才刷新
///
///
public void setSpawnWithoutAlive(bool without_alive)
{
this.mSpawnWithoutAlive = without_alive;
}
///
/// 设置怪物存活最大上限
///
///
public void setLimitedAliveCount(int count)
{
this.mLimitedAliveCount = count;
}
///
/// 设置怪物最大产生数量
///
///
public void setLimitedSpawnCount(int count)
{
this.mLimitedSpawnCount = count;
}
///
/// 设置当前触发器禁止时间,就是多长时间后才起效。
///
///
public void setDelayTime(int time)
{
this.mDelayTimeMS = time;
}
public void setStartDirection(float direction)
{
if (direction >= 0)
{
this.mStartDirection = direction;
}
}
public void setTeamFormation(TeamFormation team)
{
this.mTeam = team;
}
public void setResetOnWithoutAlive(bool flag)
{
this.mResetOnWithoutAlive = flag;
}
public void getSpawnedObjects(List list) where T : InstanceZoneObject
{
foreach (var o in mSpawnedUnits.Values)
{
if (o is T)
{
list.Add(o as T);
}
}
}
///
/// 重置计时器
///
public void reset()
{
mTotalSpawnCount = 0;
mSpawnedUnits.Clear();
if (mTimeTask != null)
{
mTimeTask.Reset();
}
}
///
/// 绑定到区域
///
///
public void bindToRegion(ZoneRegion region)
{
if (mAdded == null)
{
InstanceZone zone = region.Parent;
mAdded = region;
mTimeTask = zone.AddTimeTask(mSpawnTimeIntervalMS, mDelayTimeMS, 0, onTimeSpawn);
region.OnFlagDisabled += this.onRegionStop;
region.OnFlagEnabled += this.onRegionStart;
region.AddSpawnTrigger(this);
if (!region.Enable)
{
mTimeTask.Pause();
}
else
{
//一开始就执行一次spawn
spawnOnce(mAdded);
}
}
else
{
throw new Exception("This Trigger already bind a region !!!");
}
}
private void onRegionStart(InstanceFlag region)
{
//一开始就执行一次spawn
spawnOnce(mAdded);
mTimeTask.Resume();
}
private void onRegionStop(InstanceFlag region)
{
mTimeTask.Pause();
}
private void onTimeSpawn(TimeTaskMS task)
{
spawnOnce(mAdded);
}
private void spawnOnce(ZoneRegion region)
{
if (SpawnTemplateCount <= 0)
{
return;
}
if (mSpawnWithoutAlive && mSpawnedUnits.Count > 0)
{
return;
}
InstanceZone zone = region.Parent;
if (mTeam != null)
{
if (mTeamHelper == null || mTeamHelper.Data != mTeam)
{
mTeamHelper = new TeamFormationGroup(mTeam, region);
}
for (int i = mSpawnOnceCount - 1; i >= 0; --i)
{
var pos = region.getRandomPos(zone.RandomN);
mTeamHelper.AddPos(pos.X, pos.Y, StartDirection);
}
mTeamHelper.ResetPos();
}
else
{
mTeamHelper = null;
}
for (int i = mSpawnOnceCount - 1; i >= 0; --i)
{
if (IsSpawnOver) { break; }
if (IsWaitAlive) { break; }
var pos = (mTeamHelper != null) ? mTeamHelper.PopPos() : null;
var obj = SpawnObject(pos);
this.mSpawnIndexer++;
this.mTotalSpawnCount++;
if (obj != null)
{
this.mSpawnedUnits.Put(obj, obj);
obj.UnitTag = mUnitTag;
obj.OnObjectRemoved += removeSpawned;
OnObjectSpawned(obj);
if (mOnSpawnObject != null)
{
mOnSpawnObject.Invoke(region, this, obj);
}
if (mSpawnEffect != null)
{
zone.queueEvent(new AddEffectEvent(0 ,region.X, region.Y, region.Direction, mSpawnEffect));
}
if (IsSpawnOver)
{
if (mOnSpawnOver != null)
{
mOnSpawnOver.Invoke(region, this);
}
}
}
}
if (mTeamHelper != null)
{
mTeamHelper.Clear();
}
if (mResetOnWithoutAlive)
{
this.mTimeTask.Pause();
}
}
private void removeSpawned(InstanceZoneObject obj)
{
obj.OnObjectRemoved -= removeSpawned;
obj = mSpawnedUnits.RemoveByKey(obj);
if (obj != null)
{
OnSpawnedObjectRemoved(obj);
if (IsSpawnOver && mSpawnedUnits.Count == 0)
{
mTimeTask.Pause();
if (mOnLastObjectRemoved != null)
{
mOnLastObjectRemoved.Invoke(mAdded, this, obj);
}
}
}
if (IsSpawnOver == false && mSpawnedUnits.Count == 0 && mResetOnWithoutAlive)
{
this.mTimeTask.Reset();
}
}
//--------------------------------------------------------------------------------------------------
#region Delegate
public override void Dispose()
{
base.Dispose();
mOnSpawnOver = null;
mOnSpawnObject = null;
mOnLastObjectRemoved = null;
}
public delegate void SpawnObjectHandler(ZoneRegion region, AbstractSpawnTrigger trigger, InstanceZoneObject unit);
public delegate void SpawnOverHandler(ZoneRegion region, AbstractSpawnTrigger trigger);
public delegate void SpawnLastObjectRemovedHandler(ZoneRegion region, AbstractSpawnTrigger trigger, InstanceZoneObject unit);
private SpawnOverHandler mOnSpawnOver;
private SpawnObjectHandler mOnSpawnObject;
private SpawnLastObjectRemovedHandler mOnLastObjectRemoved;
public event SpawnOverHandler OnSpawnOver { add { mOnSpawnOver += value; } remove { mOnSpawnOver -= value; } }
public event SpawnObjectHandler OnSpawnUnit { add { mOnSpawnObject += value; } remove { mOnSpawnObject -= value; } }
public event SpawnLastObjectRemovedHandler OnLastObjectRemoved { add { mOnLastObjectRemoved += value; } remove { mOnLastObjectRemoved -= value; } }
#endregion
//--------------------------------------------------------------------------------------------------
#region ABSTRACT
abstract public int SpawnTemplateCount { get; }
///
/// 创建并生成一个单位
///
///
abstract protected InstanceZoneObject SpawnObject(IPositionObject pos);
///
/// 当一个单位被生成
///
///
abstract protected void OnObjectSpawned(InstanceZoneObject obj);
///
/// 当被生成的单位被移除场景
///
///
abstract protected void OnSpawnedObjectRemoved(InstanceZoneObject obj);
#endregion
}
//-------------------------------------------------------------------------------------------
///
/// 生成单位的触发器
///
public class SpawnUnitTrigger : AbstractSpawnTrigger
{
public struct SpawnUnitInfo
{
public UnitInfo Unit;
public int Level;
public float Percent;
public SpawnUnitInfo(UnitInfo unit, int level, float percent)
{
this.Unit = unit;
this.Level = level;
this.Percent = percent;
}
}
private List mSpawnUnitTemplates = new List();
private HashMap mAlivedUnits = new HashMap();
private ZoneWayPoint mStartPath = null;
private int mStartPathMinHoldTimeMS, mStartPathMaxHoldTimeMS;
private int mPeaceTime;
private byte mUnitForceMin;
private byte mUnitForceMax;
private string mUnitName;
public override int SpawnTemplateCount
{
get { return mSpawnUnitTemplates.Count; }
}
public override int AliveCount
{
get {
if (mAlivedUnits.Count > 0)
{
int count = 0;
foreach(var u in mAlivedUnits.Values)
{
if (!u.IsDead())
{
count++;
}
}
return count;
}
return 0;
}
}
public SpawnUnitTrigger(InstanceZone zone, string name)
: base(zone, name)
{
}
///
/// 设置产生单位的Force
///
///
public void setUnitForce(byte forceMin, byte forceMax)
{
this.mUnitForceMin = forceMin;
this.mUnitForceMax = forceMax;
}
///
/// 设置出生单位名字
///
///
public void setUnitName(string name)
{
this.mUnitName = name;
}
///
/// 添加单位模板
///
/// 将要产生的单位模板
///
///
public void addUnitInfo(UnitInfo info, int level, float percent)
{
this.mSpawnUnitTemplates.Add(new SpawnUnitInfo(info, level, percent));
}
///
/// 添加单位模板
///
/// 将要产生的单位模板
///
///
public void addUnitInfo(int templateID, int level = 0, float percent = 100f)
{
UnitInfo info = Zone.Templates.getUnit(templateID);
if (info != null)
{
info = (UnitInfo)info.Clone();
this.addUnitInfo(info, level, percent);
}
}
//添加单位事件
//public void addItemEvent(string eventId)
//{
// this.Events.Add(eventId);
//}
///
/// 添加多个单位模板
///
///
///
public void addUnits(int[] unitsTemplateID, int level)
{
if (unitsTemplateID != null)
{
foreach (int id in unitsTemplateID)
{
UnitInfo info = Zone.Templates.getUnit(id);
if (info != null)
{
info = (UnitInfo)info.Clone();
this.addUnitInfo(info, level, 100f);
}
}
}
}
///
/// 清除所有怪物模板
///
public void clearTemplates()
{
mSpawnUnitTemplates.Clear();
}
///
/// 设置移动路线
///
///
///
///
///
public ZoneWayPoint setStartPath(InstanceZone zone, string flagName, int minHoldTimeMS, int maxHoldTimeMS, int PeaceTime)
{
this.mStartPath = null;
if (!string.IsNullOrEmpty(flagName))
{
InstanceFlag flag = zone.getFlag(flagName);
if (flag is ZoneWayPoint)
{
mStartPath = flag as ZoneWayPoint;
mStartPathMinHoldTimeMS = minHoldTimeMS;
mStartPathMaxHoldTimeMS = maxHoldTimeMS;
mPeaceTime = PeaceTime;
}
}
return mStartPath;
}
protected override InstanceZoneObject SpawnObject(IPositionObject pos)
{
InstanceZone zone = this.BindingZone;
SpawnUnitInfo spawn = mSpawnUnitTemplates[SpawnIndexer % mSpawnUnitTemplates.Count];
if (CUtils.RandomPercent(zone.RandomN, spawn.Percent))
{
IVector2 mpos = pos != null ? new TVector2(pos.X, pos.Y) : BindingRegion.getRandomPos(zone.RandomN);
float direction = pos != null ? pos.Direction : this.StartDirection;
UnitInfo info = spawn.Unit;
int level = spawn.Level;
InstanceUnit unit = zone.AddUnit(info,
mUnitName,
this.GetForce(),
level,
mpos.X, mpos.Y, direction);
if (unit is IGuardUnit)
{
IGuardUnit guard = unit as IGuardUnit;
guard.SetOrginPosition(mpos.X, mpos.Y);
}
return unit;
}
return null;
}
private byte GetForce()
{
if (this.mUnitForceMax > this.mUnitForceMin && this.mUnitForceMin >= 0)
{
return (byte)(GlobalData.gRandom.Next() % (this.mUnitForceMax - this.mUnitForceMin) + this.mUnitForceMin);
}
return this.mUnitForceMin;
}
protected override void OnObjectSpawned(InstanceZoneObject obj)
{
InstanceUnit unit = (obj as InstanceUnit);
if (unit != null)
{
mAlivedUnits.Put(unit.ID, unit);
unit.OnDead += unit_OnDead;
if (mStartPath != null && (unit is IGuardUnit))
{
unit.OnActivated += unit_OnActivated;
}
}
}
protected override void OnSpawnedObjectRemoved(InstanceZoneObject obj)
{
IGuardUnit guard = (obj as IGuardUnit);
if (guard != null)
{
var unit = guard as InstanceUnit;
mAlivedUnits.RemoveByKey(unit.ID);
unit.OnDead -= unit_OnDead;
unit.OnActivated -= unit_OnActivated;
}
}
private void unit_OnDead(InstanceUnit unit, InstanceUnit attacker)
{
mAlivedUnits.RemoveByKey(unit.ID);
}
private void unit_OnActivated(InstanceUnit unit)
{
unit.OnActivated -= unit_OnActivated;
if (unit is IGuardUnit)
{
IGuardUnit guard = unit as IGuardUnit;
if (mStartPathMinHoldTimeMS != 0 || mStartPathMaxHoldTimeMS != 0)
{
guard.PatrolWith(
mStartPath,
mStartPathMinHoldTimeMS,
mStartPathMaxHoldTimeMS,
mPeaceTime);
}
else
{
guard.AttackTo(mStartPath, mPeaceTime);
}
}
}
}
//-------------------------------------------------------------------------------------------
///
/// 生成物品的触发器
///
public class SpawnItemTrigger : AbstractSpawnTrigger
{
public struct SpawnItemInfo
{
public ItemTemplate Item;
public float Percent;
public SpawnItemInfo(ItemTemplate item, float percent)
{
this.Item = item;
this.Percent = percent;
}
}
private List mSpawnUnitTemplates = new List();
private byte mUnitForce;
private string mUnitName;
public override int SpawnTemplateCount
{
get { return mSpawnUnitTemplates.Count; }
}
public SpawnItemTrigger(InstanceZone zone, string name)
: base(zone, name)
{
}
///
/// 设置产生单位的Force
///
///
public void setUnitForce(byte force)
{
this.mUnitForce = force;
}
///
/// 设置出生单位名字
///
///
public void setUnitName(string name)
{
this.mUnitName = name;
}
///
/// 添加单位模板
///
/// 将要产生的单位模板
public void addItemInfo(int templateID, float percent = 100f)
{
ItemTemplate info = Zone.Templates.getItem(templateID);
if (info != null)
{
info = (ItemTemplate)info.Clone();
mSpawnUnitTemplates.Add(new SpawnItemInfo(info, percent));
}
}
///
/// 清除所有怪物模板
///
public void clearTemplates()
{
mSpawnUnitTemplates.Clear();
}
protected override InstanceZoneObject SpawnObject(IPositionObject pos)
{
InstanceZone zone = this.BindingZone;
SpawnItemInfo spawn = mSpawnUnitTemplates[SpawnIndexer % mSpawnUnitTemplates.Count];
if (CUtils.RandomPercent(zone.RandomN, spawn.Percent))
{
IVector2 mpos = pos != null ? new TVector2(pos.X, pos.Y) : BindingRegion.getRandomPos(zone.RandomN);
float direction = pos != null ? pos.Direction : base.StartDirection;
ItemTemplate info = spawn.Item;
info = (ItemTemplate)info.Clone();
InstanceItem item = zone.AddItem(info, mUnitName, mpos.X, mpos.Y, direction, mUnitForce, mUnitName, null);
return item;
}
return null;
}
protected override void OnObjectSpawned(InstanceZoneObject obj)
{
}
protected override void OnSpawnedObjectRemoved(InstanceZoneObject obj)
{
}
}
}