using System;
using System.Collections.Generic;
using System.Text;
using CommonAI.RTS;
using CommonLang.Vector;
using CommonAI.Zone;
using CommonAI.Zone.Instance;
using CommonAI.RTS.Manhattan;
using CommonLang;
using CommonLang.Log;
using CommonAI.Zone.Formula;
using CommonAI.ZoneClient;
using CommonAI.Zone.Helper;
using CommonLang.Property;
using CommonAI.Zone.Attributes;
using CommonAI.Zone.EventTrigger;
using CommonAI.Zone.Instance.Helper;
using CommonAI.Data;
using static CommonAI.Zone.UnitInfo;
using CommonAI.data;
using CommonAI.ZoneServer.JSGModule;
namespace CommonAI.Zone.Instance
{
abstract public partial class InstanceUnit : InstanceZoneObject
{
private readonly UnitInfo mInfo;
private readonly DropItemGenerator mDropItems;
///
/// 统计信息
///
public IUnitStatistic Statistic { get; private set; }
//最后一次受伤时间
public long mLastDamageTime;
//最后一次攻击事件
public long mLastHitOtherTime;
//上一次处理死亡回调时间
public long mProcessDeadCallbackTime;
private IFormula mFormula = TemplateManager.Factory.Formula;
private IVirtualUnit mUnitVirtual;
private readonly string mName;
private int mForce = 0;
private int mAlliesForce = 0; // 服务器对战情况下,有盟友服务器
private int mLevel = 0;
private int mMoney = 0;
private readonly bool mIsAttackRangeIncludeBodySize;
// 当前HP
private readonly RangeValue __mCurrentHP;
// 当前MP
private readonly RangeValue __mCurrentMP;
// 当前移动速度加成
private float __mCurrentMoveSpeedSEC = 0;
// 攻速
private int __mCurrentAttackSpeed = 10000;
// 当前技能速度加成
private float __mSkillActionSpeedRate = 0;
// 当前快速施法速度
private float mFastCastRate = 0;
///
/// 当前单位是否地图阻挡
///
private bool mIntersectMap = false;
///
/// 当前单位是否单位阻挡
///
private bool mIntersectObj = false;
// 当前技能cd减少
private float __mCurrentSkillCdReduce;
// 控制减速,韧性
private float __mCurrentControledTimeReduce;
// 控制增幅
private float __mControledTimeAdd;
/// 单位最后死亡时间
public long mDeadTime = 0;
//游戏服标记字段,怪物死亡的时候,回传给游戏服
public int gameServerFlag = 0;
//回血
public int recoverHP = 0;
//随从最后一次瞬移时间
public long petTeleportTime = 0;
//最后一次返回召回随从操作频繁时间
public long lastTeleportTime = 0;
//绑定攻击玩家
private string mBindAttackPlayerId;
//主人id
private long mRemoveSelfTime;
private InstanceUnit mBindMaster;
//检测散开间隔
protected long mCheckAttackSpread = 0;
///
/// 自动恢复计数器
///
private TimeInterval mRecoveryTime = null;
public InstanceUnit(InstanceZone zone, UnitInfo uinfo, string name, int force, int level, bool is_static_block = false, int alliesForce = 0)
: base(zone, is_static_block)
{
this.mInfo = (UnitInfo)uinfo.Clone();
this.mName = string.IsNullOrEmpty(name) ? "" : name;
this.mIsAttackRangeIncludeBodySize = zone.Templates.CFG.OBJECT_ATTACK_RANGE_INCLUDE_BODYSIZE;
this.mForce = force;
this.mAlliesForce = alliesForce;
this.mLevel = level;
this.mIntersectMap = true;
this.mIntersectObj = !Templates.CFG.OBJECT_NONE_TOUCH && (mInfo.BodySize > 0);
this.mSyncInfo = new SyncUnitInfo(zone.IsHalfSync);
this.mSyncInfo.Name = mName;
this.mSyncInfo.TemplateID = mInfo.ID;
this.__mCurrentHP = new RangeValue(mInfo.HealthPoint, 0, mInfo.HealthPoint);
this.__mCurrentMP = new RangeValue(mInfo.ManaPoint, 0, mInfo.ManaPoint);
this.__mCurrentMoveSpeedSEC = mInfo.MoveSpeedSEC;
this.mDropItems = new DropItemGenerator(uinfo.DropItemsSet);
this.mTriggerHelper = new UnitTriggerHelper(this);
if (mInfo.IdleRecover && mInfo.RecoveryIntervalMS > 0)
{
this.mRecoveryTime = new TimeInterval(mInfo.RecoveryIntervalMS);
this.recoverHP = Info.HealthRecoveryPoint;
}
this.InitTimeLines();
this.InitBagSlots();
this.InitSkills(mInfo.BaseSkillID, mInfo.Skills.ToArray());
this.Statistic = this.CreateUnitStatistic();
this.mUnitVirtual = TemplateManager.Factory.CreateUnitVirtual(this);
}
public override bool IsNeedProcessDead()
{
return this.mProcessDeadTime == 0;
}
protected override void Disposing()
{
//if(this.IsMonster && (this.mProcessDeadTime == 0 || this.CurrentHP > 0 || this.mProcessDeadTime == 0))
//{
// log.Info("单位Disposing:" + this.Parent.UUID + ", " + this.Parent.GetSceneID() + ", " + this.ID + ", " + this.CurrentHP + "," +
// this.IsMonster + ", " + mProcessDeadTime);
//}
if (mUnitVirtual != null)
{
mUnitVirtual.OnDispose(this);
}
base.Disposing();
this.clearBindEvents();
this.clearSkills();
this.clearBuffs();
this.clearItemSlots();
this.clearTriggers();
this.mNoneBlockTimeMS.Disposing();
this.mStunTimeMS.Disposing();
this.mInvisibleTimeMS.Disposing();
this.mInvincibleTimeMS.Disposing();
this.mSilentTimeMS.Disposing();
this.mCannotMoveTimeMS.Disposing();
this.mIgnoreControl.Disposing();
foreach (MultiTimeLine timeLine in mMultiTimeLineGroup)
{
timeLine.Disposing();
}
this.mMultiTimeLineGroup.Clear();
this.mMultiTimeLineGroup = null;
this.mMultiTimeLineSync = null;
}
protected override void onAdded(bool pointLv)
{
if (this.mUnitVirtual != null)
{
this.mUnitVirtual.OnInit(this, pointLv);
if (this.mRecoveryTime != null && this.Info.UType == UnitType.TYPE_MONSTER)
{
this.recoverHP = Info.HealthRecoveryPoint == 0 ? (int)(this.MaxHP * 0.005f) : Info.HealthRecoveryPoint;
}
}
this.mSyncInfo.ObjectID = base.ID;
this.mSyncInfo.IsTouchObj = this.mIntersectObj;
this.mSyncInfo.IsTouchMap = this.mIntersectMap;
this.mSyncInfo.IsStaticBlockable = this.IsStaticBlockable;
this.mSyncInfo.fateType = (byte)this.Virtual.GetUnitFateType();
if (mInfo.SpawnTimeMS > 0)
{
this.SetInvincibleTimeMS(mInfo.SpawnTimeMS);
}
if (this.mInfo.InventoryList != null)
{
foreach (InventoryItem item in mInfo.InventoryList)
{
ItemTemplate temp = Templates.getItem(item.ItemTemplateID);
if (temp != null)
{
AddItemToEmptyInventory(temp, item.Count);
}
}
}
if (mInfo.Events != null)
{
foreach (int evt_id in mInfo.Events)
{
this.BindUnitEvent(evt_id);
}
}
if (mOnAdded != null)
{
mOnAdded.Invoke(this);
}
}
protected override void onRemoved()
{
if (mOnRemoved != null)
{
mOnRemoved.Invoke(this);
}
foreach (UnitEventTriggerCollection uc in mBindEvents.Values)
{
uc.Dispose();
}
mBindEvents.Clear();
if (Info.RemovedEffect != null)
{
Parent.queueEvent(new AddEffectEvent(0/*this.ID*/, X, Y, Direction, Info.RemovedEffect));
}
}
public void BindAttackPlayer(string playerId)
{
this.mBindAttackPlayerId = playerId;
}
public string GetAttackPlayer()
{
return this.mBindAttackPlayerId;
}
public void BindMasterId(int masterId)
{
InstanceUnit master = this.Parent.getUnitByID(masterId);
if (master == null)
{
log.Error("BindMasterId找不到单位:" + this.Parent.GetSceneID() + ", " + masterId);
return;
}
if (this.mBindMaster != null)
{
log.Error("BindMasterId重复:" + this.Info.ID + ", " + master.PlayerUUID);
return;
}
this.mBindMaster = master;
}
//--------------------------------------------------------------------------
///
/// 扩展功能绑定接口
///
public IVirtualUnit Virtual { get { return mUnitVirtual; } }
///
/// 扩展数据
///
public virtual IUnitProperties Properties { get { return mInfo.Properties; } }
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
public UnitInfo Info { get { return mInfo; } }
public string Name { get { return mName; } }
public string Alias { get { return mSyncInfo.Alias; } set { if (value != null) { mSyncInfo.Alias = value; } } }
public int Force { get { return mForce; } protected set { mForce = value; } }
public int AlliesForce { get { return mAlliesForce; } protected set { mAlliesForce = value; } }
public float MoveSpeedSEC { get { return __mCurrentMoveSpeedSEC; } }
public float SkillCdReduce { get { return __mCurrentSkillCdReduce; } }
public float ControledTimeReduce { get { return __mCurrentControledTimeReduce; } }
public float ControledTimeAdd { get { return __mControledTimeAdd; } }
public float FastCastRate { get { return mFastCastRate; } }
public override float BodyBlockSize { get { return mInfo.BodySize; } }
public override float BodyHitSize { get { return mInfo.BodyHitSize; } }
public override float BodyHeight { get { return mInfo.BodyHeight; } }
public override float Weight { get { return mInfo.Weight; } }
public override bool IntersectMap { get { return mIntersectMap; } }
public override bool IntersectObj { get { return mIntersectObj && IsVisible; } }
public override bool Moveable { get { return mInfo.IsMoveable; } }
public override bool ClientVisible { get { return true; } }
public override bool SyncPos { get { return true; } }
public override bool IsDead() { return __mCurrentHP.Value <= 0; }
public int DeadCount { get { return Statistic.DeadCount; } }
public long LastDeadTimeMS { get { return mDeadTime; } }
public bool CanWhiplashDeadBody { get { return Templates.CFG.UNIT_CAN_WHIPLASH_BODY && (LastDeadTimeMS + mInfo.DeadTimeMS > Parent.PassTimeMS); } }
///
/// 是否为玩家
///
virtual public bool IsPlayer { get { return false; } }
virtual public bool IsMonster { get { return false; } }
virtual public bool IsPet { get { return false; } }
//玩家或者宠物合集
virtual public bool IsPlayerUnit { get { return false; } }
virtual public void OnUnitDead() { }
///
/// 是否中立
///
virtual public bool IsNature { get { return false; } }
///
/// 此单位是否能被攻击并且活着
///
virtual public bool IsActive { get { return (__mCurrentHP.Value > 0) && (base.Enable)/*&& !IsInvincible && IsVisible*/; } }
///
/// 此单位是否可以被打到,包括鞭尸
///
virtual public bool IsAttackable { get { return (base.Enable) /*&& !IsInvincible && IsVisible*/; } }
///
/// 此单位是否无技能
///
public bool IsNoneSkill {
get
{
foreach (SkillState st in mSkillStatus.Skills)
{
if (st.LaunchSkill.AutoLaunch) return false;
}
return true;
}
}
///
/// 技能可产生位移,或者多段由服务器决定
///
virtual public bool IsSkillControllableByServer { get { return true; } }
///
/// 单位是否可控
///
virtual public bool IsControllable { get { return IsActive && !IsStun && CurrentActionStatus != UnitActionStatus.Damage; } }
///
/// 用于显示的,单位横向数据
///
public ZoneClient.IUnitVisibleData VisibleInfo { get { return mSyncInfo.VisibleInfo; } }
//-----------------------------------------------------------------------------------------------------//
protected virtual IUnitStatistic CreateUnitStatistic()
{
return new UnitStatistic(this);
}
//-----------------------------------------------------------------------------------------------------//
#region __StateMachine__
private bool is_init = false;
private State current_state = null;
private State next_state;
private Queue next_state_queue = new Queue();
///
/// 当前状态机
///
public State CurrentState { get { return current_state; } }
//状态机额外数据
public long chuangongTime = 0;
///
/// 下一个状态
///
protected State NextState { get { return next_state; } }
///
/// 死亡状态可能的状态机,一般配合使用
///
public bool IsStateDead
{
get
{
if ((current_state is StateDead) ||
(current_state is StateDamage) ||
(current_state is StateDeadFuck) ||
(current_state is StateDeadFuckFuck) ||
(current_state is StateRebirth) ||
(next_state is StateDead) ||
(next_state is StateDamage) ||
(next_state is StateDeadFuck) ||
(next_state is StateDeadFuckFuck) ||
(next_state is StateRebirth))
{
return true;
}
return false;
}
}
public void queueState(State s)
{
next_state_queue.Enqueue(s);
}
public bool TryEnqueueIdleState()
{
if (next_state_queue.Count > 0)
{
return false;
}
next_state_queue.Enqueue(new StateIdle(this));
return true;
}
public void queueCurrentState(State s)
{
if (current_state != null)
{
if (!changeState(s))
{
State.StateStopHandler onstop = new State.StateStopHandler((obj, st) =>
{
changeState(s);
});
current_state.AddStopOnce(onstop);
}
}
else
{
changeState(s);
}
}
public bool changeState(State s, bool force = false)
{
if (s == current_state)
{
return true;
}
if (s == next_state)
{
return true;
}
if (s.unit != this)
{
throw new Exception("State is not Owner unit : " + s);
}
if (current_state == null || current_state.onBlock(s) || force)
{
if (next_state == null || next_state.onBlock(s) || force)
{
if (next_state != null)
{
next_state.stop();
}
onNewStateBeginChange(current_state, ref s);
next_state = s;
return true;
}
}
return false;
}
private void updateState()
{
//绑定主人类怪物,脱战或者主人移除自杀
if (mRemoveSelfTime == 0)
{
if (this.mBindMaster != null && (!this.mBindMaster.IsActive || this.mBindMaster.Virtual.GetBattleStatus() <= BattleStatus.ReadyBattle))
{
//添加移除逻辑
mRemoveSelfTime = CommonLang.CUtils.localTimeMS + 3000;
}
}
else if (mRemoveSelfTime < CommonLang.CUtils.localTimeMS)
{
this.kill(null, false);
}
if (IsDead() && (!IsStateDead))
{
changeState(new StateDead(this, this, false), true);
queueEvent(new UnitDeadEvent(ID, this.ID, false, mInfo.RebirthTimeMS));
if(this.mProcessDeadCallbackTime < CommonLang.CUtils.localTimeMS)
{
log.Warn("手动调用死亡逻辑2:" + this.PlayerUUID + ", " + this.mZone.GetSceneID() + ", templateID:" + this.Info.ID + ", state: " + this.current_state);
Parent.cb_unitDeadCallBack(this, this);
}
}
else if (next_state == null && next_state_queue.Count > 0)
{
// 尝试从队列中取一个状态机,有机会就执行 //
while (next_state_queue.Count > 0)
{
State queued_state = next_state_queue.Peek();
if (changeState(queued_state))
{
next_state_queue.Dequeue();
}
else { break; }
}
}
if (next_state != null && next_state != current_state)
{
State old_state = current_state;
if (old_state != null)
{
old_state.stop();
}
this.current_state = next_state;
this.next_state = null;
this.current_state.start();
this.onStateChanged(old_state, current_state);
if (mOnStateChanged != null)
{
mOnStateChanged.Invoke(this, old_state, current_state);
}
}
if (current_state != null)
{
current_state.update();
}
UpdateTimeLines(Parent.UpdateIntervalMS);
}
#endregion
protected virtual void onUpdateRecover()
{
//自动恢复
if (this.recoverHP > 0 && mRecoveryTime != null && this.CurrentHP < this.MaxHP && CurrentActionStatus != UnitActionStatus.Damage
&& this.Virtual.GetBattleStatus() == BattleStatus.None && !IsDead())
{
if (mRecoveryTime.Update(Parent.UpdateIntervalMS))
{
AddHP(this.recoverHP, null);
//AddMP(Info.ManaRecoveryPoint);
}
}
}
override protected void onUpdate(bool slowRefresh)
{
if (!is_init)
{
is_init = true;
onInit();
}
if (!IsPaused)
{
updatePhysical();
updateState();
onUpdateRecover();
updateSkills();
updateBuffs();
updateTriggers(slowRefresh);
updateItems();
if (mOnUpdate != null)
{
mOnUpdate.Invoke(this);
}
}
updateSyncFields();
updateSyncSkillActives();
}
internal void doAction(ObjectAction act)
{
this.onAction(act);
if (mOnHandleObjectAction != null)
{
mOnHandleObjectAction.Invoke(this, act);
}
}
private void doRebirth(int max_hp, int max_mp)
{
next_state_queue.Clear();
if (this.Moveable)
{
this.mIntersectObj = !Templates.CFG.OBJECT_NONE_TOUCH && (mInfo.BodySize > 0);
}
else
{
this.mIntersectObj = (mInfo.BodySize > 0);
}
if (max_hp == 0) max_hp = this.MaxHP;
if (max_mp == 0) max_mp = this.MaxMP;
if (max_hp != 0) this.__mCurrentHP.SetValue(max_hp);
if (max_mp != 0) this.__mCurrentMP.SetValue(max_mp);
syncFields(UnitFieldChangedEvent.MASK_HP | UnitFieldChangedEvent.MASK_MP);
Parent.cb_unitRebirthCallBack(this);
queueEvent(new UnitRebirthEvent(ID));
}
public void updateContinueKills()
{
if (this.Statistic.continueKills < short.MaxValue)
{
++this.Statistic.continueKills;
}
UnitContinueKillValue temp = new UnitContinueKillValue(this.ID, this.Statistic.continueKills);
queueEvent(temp);
}
public void resetContinueKills()
{
this.Statistic.continueKills = 0;
}
private void doActivated()
{
next_state_queue.Clear();
if (this.Moveable)
{
this.mIntersectObj = !Templates.CFG.OBJECT_NONE_TOUCH && (mInfo.BodySize > 0);
}
else
{
this.mIntersectObj = (mInfo.BodySize > 0);
}
this.addTriggers(mInfo.Triggers);
Parent.cb_unitActivatedCallBack(this);
}
internal void doDead(InstanceUnit killer)
{
if (killer != null)
{
this.Statistic.LogDead(killer.Statistic);
}
this.mIntersectObj = false;
this.clearBuffs();
//吴永辉:5v5人物死亡后会重置技能CD 无论在哪个地图死亡都不能重置 你可能要指给黄鱼 bugid=2748
//this.ClearAllSkillCD();
this.resetAI();
}
//------------------------------------------------------------------------------------------------------//
internal void callback_onActivated(InstanceZone zone)
{
if (this.mOnActivated != null)
this.mOnActivated.Invoke(this);
}
internal void callback_onAttack(InstanceZone zone, InstanceUnit target, int reduceHP, AttackSource source)
{
if (this.mOnAttack != null)
this.mOnAttack(this, target, reduceHP, source);
}
internal void callback_onDamage(InstanceZone zone, InstanceUnit attacker, int reduceHP, AttackSource source)
{
if (this.mOnDamage != null)
this.mOnDamage.Invoke(this, attacker, reduceHP, source);
}
public long mProcessDeadTime = 0;
internal void callback_onDead(InstanceZone zone, InstanceUnit attacker)
{
this.mProcessDeadTime = CommonLang.TimeUtil.GetTimestampMS();
this.OnUnitDead();
if (this.mOnDead != null)
this.mOnDead.Invoke(this, attacker);
}
internal void callback_onRebirth(InstanceZone zone)
{
if (this.mOnRebirth != null)
this.mOnRebirth.Invoke(this);
}
internal void callback_onGotInstanceItem(InstanceZone zone, InstanceItem item)
{
if (this.mOnGotInstanceItem != null)
this.mOnGotInstanceItem.Invoke(this, item);
}
internal void callback_onGotInventoryItem(InstanceZone zone, ItemTemplate item)
{
if (this.mOnGotInventoryItem != null)
this.mOnGotInventoryItem.Invoke(this, item);
}
internal void callback_onLostInventoryItem(InstanceZone zone, ItemTemplate item)
{
if (this.mOnLostInventoryItem != null)
this.mOnLostInventoryItem.Invoke(this, item);
}
internal void callback_onUseItem(InstanceZone zone, ItemTemplate item, InstanceUnit item_creater)
{
if (this.mOnUseItem != null)
this.mOnUseItem.Invoke(this, item, item_creater);
}
internal void callback_onGotBuff(InstanceZone zone, InstanceUnit.BuffState buff)
{
if (this.mOnGotBuff != null)
this.mOnGotBuff.Invoke(this, buff);
}
internal void callback_onLostBuff(InstanceZone zone, InstanceUnit.BuffState buff)
{
if (this.mOnLostBuff != null)
this.mOnLostBuff.Invoke(this, buff);
}
//-----------------------------------------------------------------------------------------------------//
private void onInit()
{
syncFields(UnitFieldChangedEvent.MASK_ALL);
if (mInfo.SpawnTimeMS > 0)
{
changeState(new StateSpawn(this, mInfo.SpawnTimeMS));
}
else
{
changeState(new StateIdle(this));
doActivated();
}
}
#region _Overrideable_
///
/// 收到协议
///
///
virtual protected void onAction(ObjectAction act) { }
///
/// 新的状态将要切换时回调
///
virtual protected void onNewStateBeginChange(State old_state, ref State new_state) { }
///
/// 状态已切换时回调
///
///
///
virtual protected void onStateChanged(State old_state, State state) { }
// 被攻击时回调
virtual protected void onDamaged(InstanceUnit attacker, AttackSource source, int reduceHP) { }
virtual protected void onDead(InstanceUnit killer) { }
#endregion
///
/// 单位被攻击核心函数,里面处理受击状态,死亡状态
///
///
///
virtual protected internal void doHitAttack(InstanceUnit attacker, AttackSource source)
{
if (IsDead())
{
//死亡后鞭尸//
if (Moveable && CanWhiplashDeadBody)
{
source.Begin(this);
changeState(new StateDamage(this, source, attacker));
}
doHitAttackEndEffect(attacker, source);
return;
}
else
{
if (current_state is StateDamage)
{
StateDamage state_damage = current_state as StateDamage;
if (state_damage.IsDamageProtect)
{
return;
}
}
// TODO HP //
source.Begin(this);
int reduceHP = mFormula.OnHit(attacker, source, this);
// 统计 //
reduceHP = this.AddHP(-reduceHP, attacker, !source.OutSendEvent, source);
//this.Statistic.LogDamage(attacker.Statistic, reduceHP);
AttackProp attack = source.Attack;
// Post Event //
if (source.OutSendEvent)
{
UnitHitEvent evt = new UnitHitEvent(ID);
evt.senderId = attacker.ID;
evt.senderMasterId = attacker.Virtual.GetMasterID();
evt.hitMasterId = this.Virtual.GetMasterID();
evt.hp = reduceHP;
evt.isDead = IsDead();
evt.isCritical = source.Attack.MaskMustCritical;
evt.effect = source.OutHitEffect;
evt.SourceAttack = source.Attack;
evt.client_state = source.OutClientState;
//if (source != null && attacker != null && source.FromSkillType == XmdsSkillType.cardSkill && this.IsMonster && attacker.IsMonster)
//{
evt.InViewForceSend = true;
//}
queueEvent(evt);
}
if (reduceHP > 0)
{
source.HasHitted = true;
onDamaged(attacker, source, reduceHP);
Parent.cb_unitDamageCallBack(this, attacker, reduceHP, source);
if (IsDead())
{
//doDeadProcess(attacker, source);
return;
}
}
// 非免控,才会有受击
if (!this.IsIgnoreControl && source.OutIsDamage && Moveable)
{
changeState(new StateDamage(this, source, attacker));
}
doHitAttackEndEffect(attacker, source);
return;
}
}
/** 执行死亡处理逻辑 */
private void doDeadProcess(InstanceUnit attacker, AttackSource source)
{
try
{
onDead(attacker);
Parent.cb_unitDeadCallBack(this, attacker);
if (source == null)
{
queueEvent(new UnitDeadEvent(ID, attacker == null ? 0 : attacker.ID, false, mInfo.RebirthTimeMS));
changeState(new StateDead(this, attacker, true));
}
else
{
queueEvent(new UnitDeadEvent(ID, attacker.ID, source.OutIsCrush, mInfo.RebirthTimeMS));
// 被击碎,秒杀 //
if (source.OutIsCrush)
{
Parent.queueEvent(new AddEffectEvent(this.ID, X, Y, Direction, source.Attack.CrushEffect));
changeState(new StateDead(this, attacker, true));
}
else
{
if (!Moveable)
{
changeState(new StateDead(this, attacker));
}
else if (source.OutHasKnockDown || source.OutHasFly)
{
if (!changeState(new StateDamage(this, source, attacker)))
{
changeState(new StateDead(this, attacker));
}
}
else
{
changeState(new StateDead(this, attacker));
}
}
doHitAttackEndEffect(attacker, source);
}
}
catch (Exception e)
{
log.Warn("doDeadProcess catch:" + this.Info.ID + ", AttackId: " + (attacker == null ? -1 : attacker.Info.ID), e);
}
}
///
/// 死亡后自爆或者触发法术
///
///
///
private void doHitAttackEndEffect(InstanceUnit attacker, AttackSource source)
{
if (source.Attack.Buff != null)
{
AddBuff(source.Attack.Buff, attacker);
}
if (source.Attack.Spell != null)
{
Parent.attackLaunchSpell(source.FromSkillType, attacker, this, source);
}
}
// 单位获取道具
protected virtual bool tryGotItem(InstanceItem item, out bool removeItem)
{
if (!Parent.IsVisibleAOI(this, item))
{
removeItem = false;
return false;
}
if (item.Info.DropMoneyMin > 0 && item.Info.DropMoneyMax > 0)
{
int min = Math.Min(item.Info.DropMoneyMin, item.Info.DropMoneyMax);
int max = Math.Max(item.Info.DropMoneyMin, item.Info.DropMoneyMax);
int money = RandomN.Next(min, max + 1);
this.CurrentMoney += money;
removeItem = item.Info.RemoveOnFinishPick;
return true;
}
if (item.Info.GotOnUse)
{
// 获取后立即使用 //
if (UseItem(item.Info, item.ItemCreater))
{
removeItem = item.Info.RemoveOnFinishPick;
return true;
}
}
else
{
// 获取后进背包 //
if (AddItemToEmptyInventory(item.Info) > 0)
{
removeItem = item.Info.RemoveOnFinishPick;
return true;
}
}
removeItem = false;
return false;
}
internal bool doGotInstanceItem(InstanceItem item, out bool removeItem, out int pickTimes)
{
pickTimes = 0;
var ret = tryGotItem(item, out removeItem);
if (ret)
{
pickTimes = Parent.cb_unitGotInstanceItemCallBack(this, item);
if (item.Info.GotEffect != null)
{
queueEvent(new UnitEffectEvent(ID, item.Info.GotEffect));
}
}
return ret;
}
internal void doGotInventoryItem(InventorySlot slot, ItemTemplate item, int index, int count)
{
mFormula.OnGotInventoryItem(this, item);
queueEvent(new UnitSyncInventoryItemEvent(ID, item.ID, index, slot.Count));
Parent.cb_unitGotInventoryItemCallBack(this, item, count);
// 添加装备Buff //
if (item.EquipBuffs != null)
{
foreach (LaunchBuff buff in item.EquipBuffs)
{
AddBuff(buff, this, true);
}
}
}
internal void doLostInventoryItem(InventorySlot slot, ItemTemplate item, int index, int count)
{
mFormula.OnLostInventoryItem(this, item);
queueEvent(new UnitSyncInventoryItemEvent(ID, item.ID, index, slot.Count));
Parent.cb_unitLostInventoryItemCallBack(this, item, count);
// 移除装备Buff //
if (item.EquipBuffs != null)
{
foreach (LaunchBuff buff in item.EquipBuffs)
{
removeBuff(buff.BuffID);
}
}
}
// 单位获取道具
internal void doGotBuff(InstanceUnit.BuffState buff)
{
Parent.cb_unitGotBuffCallBack(this, buff);
}
internal void doLostBuff(InstanceUnit.BuffState buff)
{
Parent.cb_unitLostBuffCallBack(this, buff);
}
public bool UseItem(int itemTemplateID, InstanceUnit item_creater = null)
{
ItemTemplate item = Templates.getItem(itemTemplateID);
if (item != null)
{
return UseItem(item, item_creater);
}
return false;
}
public bool UseItem(ItemTemplate item, InstanceUnit item_creater = null)
{
if (item_creater == null)
{
item_creater = this;
}
if (tryUseItem(item, item_creater))
{
beginUseItem(item);
// 如果关键帧绑定特效
if (item.UseEffect != null)
{
queueEvent(new UnitEffectEvent(ID, item.UseEffect));
}
// 如果关键帧绑定释放法术
if (item.UseSpell != null)
{
Parent.unitLaunchSpell(XmdsSkillType.none, item_creater, item.UseSpell, X, Y);
}
if (item.UseSummon != null)
{
Parent.unitSummonUnit(item_creater, item.UseSummon);
}
// 如果关键帧绑定自己释放BUFF
if (item.UseBuffs != null)
{
foreach (LaunchBuff buff in item.UseBuffs)
{
this.AddBuff(buff, item_creater);
}
}
mFormula.OnUseItem(this, item, item_creater);
queueEvent(new UnitUseItemEvent(ID, item.ID));
Parent.cb_unitUseItemCallBack(this, item, item_creater);
Statistic.LogUseItem(item);
return true;
}
return false;
}
//-----------------------------------------------------------------------------------------------------//
///
/// 有伤害源的扣血
///
///
///
///
///
/// force: 忽略无敌效果,强制扣血
public int ReduceHP(int hp, InstanceUnit attacker, AttackSource source, bool sendHit = true, UnitHitEvent hitMessage = null,
bool IngoreHealEffect = false, DamageSource dmgSrc = DamageSource.Def, bool force = false)
{
//1.目标无敌,不扣血
if (IsDead() || hp == 0 || (hp > 0 && this.IsInvincible && !force))
{
return 0;
}
//2. 针对有发送者的伤害来源
if (attacker != null)
{
if (hp < 0 && !IngoreHealEffect)
{
int healedEffect = this.Virtual.GetHealedEffect();
int healEffect = (attacker.Virtual.GetUnitPro() == XmdsUnitPro.Priest) ? attacker.Virtual.GetHealEffect() : 0;
if (healedEffect != 0 || healEffect != 0)
{
hp = CUtils.CastInt(hp * (1 + healEffect * 0.0001) * (1 + healedEffect * 0.0001));
}
}
if (hp < 0)
{
//传递加血事件
hp = attacker.Virtual.DispatchAddOtherHPEvent(hp, this, source);
//2 道灵对宠物加血,需要有个系数
if (attacker.IsPlayer && this.IsPet && attacker.Virtual.GetUnitPro() == XmdsUnitPro.Priest)
{
hp = (int)(hp * XmdsConstConfig.PET_HEALD_RATIO);
}
}
else
{
//传递单位-被其他人扣血
hp = this.Virtual.DispatchAddOtherHPEvent(hp, attacker, source);
if (this.IsPlayer && attacker.IsMonster)
{
//2.3 如果玩家受伤,伤害来源存在且为怪物,宠物可以分担伤害
InstanceUnit petUnit = this.Virtual.GetPetUnit();
if (petUnit != null)
{
int petShareDmg = Math.Max(1, (int)(hp * XmdsConstConfig.PET_SHARE_MASTERDMG_RATIO));
hp = Math.Max(1, hp - petShareDmg);
petUnit.PetShareDamage(petShareDmg, this);
}
}
}
this.Statistic.LogDamage(attacker.Statistic, hp);
}
this.DoAddHP(-hp);
if (attacker != null && sendHit)
{
if (hitMessage == null)
{
hitMessage = new UnitHitEvent();
}
hitMessage.object_id = this.ID;
hitMessage.senderId = attacker == null ? 0 : attacker.ID;
hitMessage.senderMasterId = attacker == null ? 0 : attacker.Virtual.GetMasterID();
hitMessage.hitMasterId = this.Virtual.GetMasterID();
hitMessage.hp = hp;
hitMessage.isSpecialHit = dmgSrc != DamageSource.Def;
hitMessage.dmgSrc = dmgSrc;
hitMessage.isDead = IsDead();
queueEvent(hitMessage);
}
//if (IsDead())
//{
// changeState(new StateDead(this, attacker, false));
// Parent.cb_unitDeadCallBack(this, attacker);
// queueEvent(new UnitDeadEvent(ID, attacker == null ? 0 : attacker.ID, false, mInfo.RebirthTimeMS));
//}
if (hp > 0 && this.IsDead())
{
this.doDeadProcess(attacker, source);
}
return hp;
}
public void AddMP(int mp, InstanceUnit sender, bool sendMsg = true, bool force = false, AttackSource source = null)
{
if (mp == 0 || this.MaxMP <= 0)
{
return;
}
//传递扣定力事件
if (mp < 0 && sender != null)
{
int finalHP = mp;
sender.Virtual.DispatchAddMPEvent(mp, this, out finalHP, source);
mp = finalHP;
}
this.DoAddMP(mp, force);
}
public void removeFromParent()
{
Parent.RemoveObjectByID(ID);
}
public void kill(InstanceUnit killer = null, bool sendHit = true, UnitHitEvent hitMessage = null)
{
ReduceHP(this.CurrentHP, killer, null, sendHit, hitMessage, true);
}
virtual protected void onResetAI()
{
this.doSomething();
}
public void resetAI()
{
next_state_queue.Clear();
onResetAI();
}
public override void faceTo(float d)
{
if (Info.IsTurnable) { base.faceTo(d); }
}
public override void faceTo(float x, float y)
{
if (Info.IsTurnable) { base.faceTo(x, y); }
}
///
/// 瞬移
///
///
///
public void transport(float x, float y, bool setDirction = false, float direction = 0)
{
this.SetActionStatus(UnitActionStatus.Transport);
this.changeState(new StateTransport(this), true);
setPos(x, y);
if (setDirction)
{
this.Direction = direction;
}
SendForceSync();
if (mOnRegionTransport != null)
{
mOnRegionTransport.Invoke();
}
}
//-----------------------------------------------------------------------------------------------------//
public virtual void doSomething()
{
startIdle();
}
///
/// 单位待机
///
public bool startIdle(bool force = false)
{
if (current_state is StateIdle)
{
}
else
{
return changeState(new StateIdle(this), force);
}
return false;
}
///
/// 直接复活
///
public bool startRebirth(int max_hp = 0, int max_mp = 0)
{
if (IsDead())
{
//this.DeadHide = false;
this.mProcessDeadCallbackTime = 0;
return changeState(new StateRebirth(this, max_hp, max_mp));
}
return false;
}
///
/// 单位移动
///
///
///
public bool startMoveTo(float x, float y)
{
return changeState(new StateMove(this, x, y));
}
///
/// 调整射击位置
///
///
///
///
public bool startAdjustLaunchSkill(SkillTemplate expect_skill, InstanceUnit target, Predicate onEndAction)
{
if (expect_skill.AttackKeepRange > 0 && expect_skill.AttackRange > expect_skill.AttackKeepRange)
{
float keep_range = GetSkillAttackRange(expect_skill.AttackKeepRange) + target.BodyBlockSize;
float distance = MathVector.getDistance(this.X, this.Y, target.X, target.Y);
if (distance < keep_range)
{
var half = (expect_skill.AttackRange - expect_skill.AttackKeepRange) / 2;
var md = (keep_range - distance) + (float)(RandomN.NextDouble() * half);
var target_pos = new Vector2(this.X, this.Y);
var rd = (CMath.PI_DIV_2 / 4);
var target_direction = this.Direction + CMath.PI_F - (rd / 2 + (float)(RandomN.NextDouble() * rd));
MathVector.movePolar(target_pos, target_direction, md);
if (!Parent.TryTouchMap(this, target_pos.X, target_pos.Y))
{
var back_pos = new Vector2(this.X, this.Y);
MathVector.movePolar(back_pos, target_direction, this.BodyBlockSize);
if (!Parent.TryTouchMap(this, back_pos.X, back_pos.Y))
{
var move = new StateMove(this, target_pos.X, target_pos.Y);
move.MinStepCheckCount = 0;
move.StopOnTouchMap = true;
move.EndMoveAction = onEndAction;
return this.changeState(move);
}
}
}
}
return false;
}
///
/// 单位移动
///
///
public bool startFollowTo(InstanceZoneObject obj)
{
return changeState(new StateFollowObject(this, obj));
}
///
/// 单位逃跑
///
///
///
public bool startEscape(int timeMS, float distance = 0)
{
return changeState(new StateEscape(this, timeMS, distance));
}
///
/// 和自身交互(搓炉石)
///
///
///
///
public StatePickObject startPickProgressSelf(int timeMS, StatePickObject.OnPickDone done, string status = null)
{
StatePickObject picking = new StatePickObject(this, this, timeMS, status, done);
changeState(picking);
return picking;
}
///
/// 和目标交互
///
///
///
///
///
///
public StatePickObject startPickProgressObject(InstanceZoneObject item, int timeMS, StatePickObject.OnPickDone done, string status = null)
{
StatePickObject picking = new StatePickObject(this, item, timeMS, status, done);
changeState(picking);
return picking;
}
//-----------------------------------------------------------------------------------------------------------------
#region _SKILL_
//-----------------------------------------------------------------------------------------------------------------
public float GetSkillAttackRange(SkillTemplate skill, InstanceUnit targetUnit)
{
return mIsAttackRangeIncludeBodySize ? (BodyBlockSize + skill.AttackRange + targetUnit.BodyBlockSize) : skill.AttackRange;
//return mIsAttackRangeIncludeBodySize ? (BodyBlockSize + skill.AttackRange) : skill.AttackRange;
}
public float GetSkillAttackRange(SkillTemplate skill)
{
return mIsAttackRangeIncludeBodySize ? (BodyBlockSize + skill.AttackRange) : skill.AttackRange;
}
public float GetSkillAttackRange(float range)
{
return (mIsAttackRangeIncludeBodySize ? BodyBlockSize + range : range);
}
///
/// 判断当前目标在攻击范围内
///
///
///
///
public bool IsTargetInSkillRange(SkillTemplate skill, InstanceUnit unit)
{
float rg = GetSkillAttackRange(skill);
float dr = skill.AttackAngle / 2;
if (Collider.Object_HitBody_TouchFan(unit, X, Y, rg, Direction - dr, Direction + dr))
{
return true;
}
return false;
}
[Obsolete]
public List getSkillAttackableTargets(SkillTemplate skill, AttackReason reason)
{
float rg = GetSkillAttackRange(skill);
List list = Parent.getObjectsRoundRange(Collider.Object_HitBody_TouchRound, X, Y, rg, this.AoiStatus);
Parent.getAttackableUnits(this, list, skill.ExpectTarget, reason, skill);
return list;
}
public void getSkillAttackableTargets(SkillTemplate skill, List list, AttackReason reason)
{
float rg = GetSkillAttackRange(skill);
Parent.getObjectsRoundRange(Collider.Object_HitBody_TouchRound, X, Y, rg, list, this.AoiStatus);
Parent.getAttackableUnits(this, list, skill.ExpectTarget, reason, skill);
}
///
/// 获得可用的技能
///
///
///
public SkillState getAvailableSkill(SkillTemplate.CastTarget expect)
{
for (int si = mAllSkills.Count - 1; si >= 0; --si)
{
SkillTemplate st = mAllSkills[si];
if (st.ExpectTarget == expect)
{
SkillState sst = mSkillStatus.Get(st.GetID());
if (sst.IsActive && sst.IsDone)
{
return sst;
}
}
}
return null;
}
/** 获取当前可自动释放的技能 */
public SkillState getAvailableAutoLaunchSkill(SkillTemplate.CastTarget expect)
{
for (int si = mAllSkills.Count - 1; si >= 0; --si)
{
SkillTemplate st = mAllSkills[si];
if (st.ExpectTarget == expect)
{
SkillState sst = mSkillStatus.Get(st.GetID());
if (sst.IsActive && sst.IsDone && sst.LaunchSkill.AutoLaunch && sst.CanAutoLaunch())
{
return sst;
}
}
}
return null;
}
///
/// 获取当前最适合攻击的目标
///
///
///
///
///
public InstanceUnit getSkillAttackableFirstTarget(SkillTemplate skill, AttackReason reason, ref bool directionChange)
{
using (var list = ListObjectPool.AllocAutoRelease())
{
getSkillAttackableTargets(skill, list, reason);
if (list.Count > 0)
{
float rg = GetSkillAttackRange(skill);
// 检测攻击范围内的单位 //
float dr = skill.AttackAngle / 2;
for (int i = 0; i < list.Count; i++)
{
InstanceUnit u = list[i];
if (Collider.Object_HitBody_TouchFan(u, X, Y, rg, Direction - dr, Direction + dr))
{
directionChange = false;
return u;
}
}
// 优先当前朝向的目标 //
dr = CMath.PI_DIV_2;
directionChange = true;
for (int i = 0; i < list.Count; i++)
{
InstanceUnit u = list[i];
if (Collider.Object_HitBody_TouchFan(u, X, Y, rg, Direction - dr, Direction + dr))
{
return u;
}
}
// 最后选取最近的目标 //
InstanceUnit min = null;
float min_len = float.MaxValue;
for (int i = 0; i < list.Count; i++)
{
InstanceUnit u = list[i];
float len = MathVector.getDistanceSquare(u.X, u.Y, X, Y);
if (min_len > len)
{
min_len = len;
min = u;
}
}
return min;
}
}
return null;
}
public struct LaunchSkillParam
{
public uint TargetUnitID;
public Vector2 SpellTargetPos;
public bool AutoFocusNearTarget;
public bool LaunchSetDirection; // 释放时是否重新设置方向
public float direction;
public bool IsAutoLaunch; // 是否自动战斗时释放
public bool IsInGuard; // 是否是自动战斗
public LaunchSkillParam(uint targetUnitID = 0, Vector2 target_pos = null, bool autoFocusNearTarget = false,
bool LaunchSetDirection = false, float direction = 0, bool IsAutoLaunch = false, bool IsInGuard = false)
{
this.TargetUnitID = targetUnitID;
this.SpellTargetPos = target_pos;
this.AutoFocusNearTarget = autoFocusNearTarget;
this.LaunchSetDirection = LaunchSetDirection;
this.direction = direction;
this.IsAutoLaunch = IsAutoLaunch;
this.IsInGuard = IsInGuard;
}
}
public StateSkill launchSkill(SkillState ss, LaunchSkillParam param)
{
if (ss == null) return null;
StateSkill current = CurrentState as StateSkill;
if (current != null && current.SkillData.IsManuallyCancelable)
{
//如果当前技能为手动取消//
if (current.Skill.ID == ss.ID)
{
//判断停止当前技能//
if (current.IsCancelableBySkill)
{
current.block();
}
}
//手动取消技能禁止其他技能打断//
return null;
}
if (ss.TryLaunch() && mFormula.TryLaunchSkill(this, ss, ref param))
{
if (param.IsAutoLaunch && !ss.CanAutoLaunch())
{
return null;
}
//沉默不能释放其他技能//
if (IsSilent && ss != mDefaultSkill)
{
return null;
}
// 自动战斗下,释放技能要在范围内
InstanceUnit target = null;
if (ss.Data.AttackMustBeInRange)
{
target = Parent.getUnit(param.TargetUnitID);
if (!ss.checkTargetRange(target))
{
return null;
}
}
//是否在合理的攻击范围内
if (param.IsInGuard && !ss.checkTargetInAttackRange(target, param))
{
return null;
}
if (ss.GetSkillType() == XmdsSkillType.petGiveAcitve)
{
mFormula.TriggerPetSkill(this, ss, ref param);
return null;
}
StateSkill state = new StateSkill(this, ss, param, ss.ActionSpeed, (st) =>
{
overLaunchSkill(ss, st);
if (mOnLaunchSkill != null)
{
mOnLaunchSkill.Invoke(this, ss);
}
});
if (state.tryLaunch())
{
this.Virtual.SetCombatState(BattleStatus.ReadyBattle);
Parent.cb_unitLaunchSkill(this, ss);
if (changeState(state))
{
//释放成功
if (param.LaunchSetDirection)
{
//Console.WriteLine("launchSkill - 设置方向: " + param.direction + ", " + this.ID);
//this.faceTo(param.direction);
//this.SendForceSync();
}
return state;
}
}
}
return null;
}
protected virtual void overLaunchSkill(SkillState ss, StateSkill state)
{
this.AddHP(-ss.Data.CostHP, null);
this.AddMP(-ss.Data.CostMP, null);
}
///
/// 单位释放技能
///
public StateSkill launchSkill(int skillID, LaunchSkillParam param)
{
SkillState skill = getSkillState(skillID);
return launchSkill(skill, param);
}
///
/// 释放随机技能,一般用于AI
///
///
///
///
public virtual StateSkill launchRandomSkill(SkillTemplate.CastTarget expectTarget, LaunchSkillParam param)
{
StateSkill current = CurrentState as StateSkill;
if (current != null && !current.IsCancelableBySkill)
{
return null;
}
int rand = RandomN.Next(0, mAllSkills.Count);
for (int si = mAllSkills.Count - 1; si >= 0; --si)
{
SkillTemplate st = mAllSkills[CMath.cycNum(rand, si, mAllSkills.Count)];
if (st.ExpectTarget == expectTarget)
{
SkillState sst = mSkillStatus.Get(st.GetID());
if (sst.LaunchSkill.AutoLaunch && sst.TryLaunch())
{
StateSkill state = launchSkill(sst, param);
if (state != null)
{
return state;
}
}
}
}
return null;
}
public virtual StateSkill launchRandomSkillForAll(LaunchSkillParam param)
{
StateSkill current = CurrentState as StateSkill;
if (current != null && !current.IsCancelableBySkill)
{
return null;
}
int rand = RandomN.Next(0, mAllSkills.Count);
for (int si = mAllSkills.Count - 1; si >= 0; --si)
{
SkillTemplate st = mAllSkills[CMath.cycNum(rand, si, mAllSkills.Count)];
SkillState sst = mSkillStatus.Get(st.GetID());
if (sst.LaunchSkill.AutoLaunch && sst.TryLaunch())
{
StateSkill state = launchSkill(sst, param);
if (state != null)
{
return state;
}
}
}
return null;
}
///
/// 尝试取消当前技能,打出连击
///
///
///
///
public virtual bool tryLaunchRandomSkillAndCancelCurrentSkill(InstanceUnit target, bool autoFocusNearTarget = false)
{
StateSkill current = CurrentState as StateSkill;
if (current != null && !current.IsChanting && current.IsCancelableBySkill)
{
LaunchSkillParam param = new LaunchSkillParam(target.ID, null, autoFocusNearTarget);
//优先多段攻击//
if (current.SkillData.IsSingleAction)
{
if (IsTargetInSkillRange(current.SkillData, target))
{
StateSkill st = launchSkill(current.SkillData.ID, param);
if (st != null)
{
return true;
}
}
}
//随机其他技能//
int rand = RandomN.Next(0, mAllSkills.Count);
for (int si = mAllSkills.Count - 1; si >= 0; --si)
{
SkillTemplate st = mAllSkills[CMath.cycNum(rand, si, mAllSkills.Count)];
if (Parent.IsAttackable(this, target, st.ExpectTarget, AttackReason.Attack, st))
{
SkillState sst = mSkillStatus.Get(st.GetID());
if (sst.LaunchSkill.AutoLaunch && IsTargetInSkillRange(st, target))
{
StateSkill state = launchSkill(sst, param);
if (state != null)
{
return true;
}
}
}
}
}
return false;
}
///
/// 尝试在范围内找到目标释放技能,并进入StateFollowAndAttack,自己走过去打。
///
///
///
///
public virtual bool tryFollowAndLaunchRandomSkillToTargetInRange(float range, bool skill_auto_launchable = false)
{
if (!IsNoneSkill)
{
SkillState[] skills = mSkillStatus.SkillsArray;
CUtils.RandomArray(RandomN, skills);
using (var list = ListObjectPool.AllocAutoRelease())
{
//随机找个目标施法//
Parent.getObjectsRoundRange(Collider.Object_Pos_IncludeInRound, X, Y, Info.GuardRange, list, this.AoiStatus);
DoAndRemoveCollection.UpdateAndRemove(list, (InstanceUnit u) =>
{
return !u.IsActive;
});
if (list.Count == 0) { return false; }
CUtils.RandomList(Parent.RandomN, list);
foreach (SkillState skill in skills)
{
if ((!skill_auto_launchable || skill.LaunchSkill.AutoLaunch) && skill.TryLaunch())
{
for (int i = 0; i < list.Count; i++)
{
InstanceUnit u = list[i];
if (Parent.IsAttackable(this, u, skill.Data.ExpectTarget, AttackReason.Attack, skill.Data))
{
//检测是否有可释放技能//
changeState(new StateFollowAndAttack(this, u, skill.Data.ExpectTarget));
return true;
}
}
}
}
}
}
return false;
}
#endregion
//-----------------------------------------------------------------------------------------------------------------
internal void deadDropItems(int force)
{
foreach (KeyValuePair e in mDropItems.Drop(Parent, Parent.RandomN))
{
float x;
float y;
CMath.RandomPosInRound(RandomN, X, Y, e.Value.DropPosRange, out x, out y);
Parent.AddItem(e.Key, e.Key.Name, x, y, CMath.RandomAngle(RandomN), force, e.Key.Name, this);
}
}
protected bool tryPickObject(InstanceUnit unit)
{
if (!Parent.IsVisibleAOI(this, unit))
{
return false;
}
bool ret = true;
if (mOnTryPickUnit != null)
{
foreach (TryPickUnitHandler trypick in mOnTryPickUnit.GetInvocationList())
{
if (!trypick.Invoke(this, unit))
{
ret = false;
}
}
}
return ret;
}
public void PickUnit(InstanceUnit pickable)
{
if (tryPickObject(pickable))
{
Parent.cb_unitPickUnitCallBack(this, pickable);
if (mOnPickUnit != null)
{
mOnPickUnit.Invoke(this, pickable);
}
}
}
public CommonAI.Data.SceneType GetSceneType()
{
return mZone.SceneType;
}
//-----------------------------------------------------------------------------------------------------//
#region Environment
//-----------------------------------------------------------------------------------------------------//
private HashMap EnvironmentVarMap = new HashMap();
public void SetEnvironmentVar(string key, object value, bool syncToClient = false)
{
if (!string.IsNullOrEmpty(key))
{
EnvironmentVar var = EnvironmentVarMap.Get(key);
if (var != null)
{
if (EnvironmentVar.ALWAYS_SYNC_ENVIRONMENT_VAR || (var.SyncToClient && var.Value != value))
{
queueEvent(new PlayerSyncEnvironmentVarEvent(ID, key, value));
}
var.Value = value;
}
else
{
var = new EnvironmentVar(key, syncToClient, value);
EnvironmentVarMap.Add(key, var);
if (EnvironmentVar.ALWAYS_SYNC_ENVIRONMENT_VAR || var.SyncToClient)
{
queueEvent(new PlayerSyncEnvironmentVarEvent(ID, key, value));
}
}
}
}
public T GetEnvironmentVarAs(string key)
{
if (!string.IsNullOrEmpty(key))
{
EnvironmentVar var = EnvironmentVarMap.Get(key);
if (var != null)
{
try
{
return (T)var.Value;
}
catch (Exception err)
{
log.Warn("GetEnvironmentVarAs : " + key + ", catch: " + err);
}
}
}
return default(T);
}
public int ListEnvironmentVars(List list)
{
list.AddRange(EnvironmentVarMap.Values);
return EnvironmentVarMap.Count;
}
public List ListEnvironmentVars()
{
return new List(EnvironmentVarMap.Values);
}
public ClientStruct.ZoneEnvironmentVar[] GetCurrentUnitVars()
{
ClientStruct.ZoneEnvironmentVar[] ret = new ClientStruct.ZoneEnvironmentVar[EnvironmentVarMap.Count];
int i = 0;
try
{
foreach (EnvironmentVar var in EnvironmentVarMap.Values)
{
ret[i].Key = var.Key;
ret[i].Value = var.Value;
ret[i].SyncToClient = var.SyncToClient;
i++;
}
}
catch (Exception e)
{
log.Warn("GetCurrentUnitVars catch: " + ret.Length + ", " + EnvironmentVarMap.Count + ", " + i + ", e: " + e);
}
return ret;
}
#endregion
//-----------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------//
#region SceneEvents
//-----------------------------------------------------------------------------------------------------//
private HashMap mBindEvents = new HashMap();
public void BindUnitEvent(int unit_event_id)
{
if (!mBindEvents.ContainsKey(unit_event_id))
{
UnitEventTemplate uet = Templates.getUnitEvent(unit_event_id);
if (uet != null)
{
uet = uet.Clone() as UnitEventTemplate;
UnitEventTriggerCollection bind_event = new UnitEventTriggerCollection(this);
bind_event.Bind(uet.Events);
mBindEvents.Add(unit_event_id, bind_event);
}
}
}
protected virtual void clearBindEvents()
{
foreach (var evt in mBindEvents.Values)
{
evt.Dispose();
}
mBindEvents.Clear();
}
/** 计算并获得伤害 */
public virtual void PetShareDamage(int baseDmgValue, InstanceUnit sender)
{
}
#endregion
//-----------------------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------------------//
}
}