11 public override CursorInfo CursorIcon
15 return CursorSystem.IconMelee;
21 public override bool CancelWhenDamaged
30 public override bool CanManualCancel()
41 return this.owner.tactics;
46 public override IEnumerable<
AIAct.Status> Run()
48 if (this.destEnemy !=
null)
50 this.owner.enemy = this.destEnemy;
51 this.destEnemy =
null;
55 bool dontWander = this.owner.IsPCParty && !this.owner.IsPC &&
EClass.game.config.tactics.dontWander;
58 if (
EClass.debug.logCombat)
60 Debug.Log(
string.Concat(
new string[]
70 if (
EClass._zone.isPeace &&
this.owner.IsPCFactionOrMinion && !
this.owner.IsPC)
72 this.owner.enemy =
null;
73 this.owner.ShowEmo(Emo.happy, 0f,
true);
74 yield
return base.Success(
null);
78 if (dontWander && this.owner.enemy !=
null && !
EClass.pc.isBlind && !
EClass.pc.CanSeeLos(
this.owner.enemy, -1,
false) && (
this.owner.Dist(
EClass.pc) > 4 ||
this.owner.Dist(
this.owner.enemy) > 1))
81 if (firstStep.IsValid && !firstStep.HasChara)
83 this.owner.enemy =
null;
86 this.tc = this.owner.enemy;
87 if (this.tc !=
null && this.owner.IsPCFaction)
90 if (ai_Shear !=
null && ai_Shear.target ==
this.tc)
92 this.tc = (this.owner.enemy =
null);
95 if (this.tc ==
null || this.tc.isDead || !
this.tc.ExistsOnMap || !
this.tc.pos.IsInBounds || lostCount >= 5)
97 this.tc = (this.owner.enemy =
null);
98 if (this.owner.IsPC &&
EClass.game.config.autoCombat.abortOnKill)
100 yield
return base.Success(
null);
102 this.owner.FindNewEnemy();
104 if (this.owner.enemy ==
null)
106 yield
return base.Success(
null);
108 this.tc = this.owner.enemy;
110 else if (!this.owner.CanSeeLos(
this.tc, -1,
false))
119 if (this.owner.IsPC &&
this.tc.HasEditorTag(EditorTag.Invulnerable))
121 Msg.Say(
"abort_idle");
122 yield
return base.Success(
null);
124 if (this.tc.IsPCFaction &&
this.owner.id ==
"melilith_boss" &&
EClass._map.plDay.list.Count > 1 &&
EClass._map.plDay.list[0].data.id != 107)
126 EClass._zone.SetBGM(107,
true);
128 if (this.abilities ==
null)
131 this.BuildAbilityList();
133 if (this.owner.IsPCFaction &&
this.tc.IsPCFaction &&
EClass.rnd(5) == 0 && count > 2)
135 this.<Run>g__CalmDown|14_0();
136 yield
return base.Success(
null);
138 if (this.owner.OriginalHostility >= Hostility.Neutral &&
this.tc.OriginalHostility >= Hostility.Neutral && !
this.owner.IsPCParty &&
this.owner.c_bossType == BossType.none && (!(
this.owner.trait is
TraitGuard) ||
this.owner.IsPCFaction || !
this.tc.IsPCParty || !
EClass.player.IsCriminal))
140 if (this.owner.calmCheckTurn < 0 || (!
this.owner.enemy.IsPCParty &&
EClass.rnd(10) == 0))
142 this.<Run>g__CalmDown|14_0();
143 yield
return base.Success(
null);
145 this.owner.calmCheckTurn--;
149 CursorSystem.ignoreCount = 1;
151 if (this.tc.host !=
null && (
this.tc.hp == 0 ||
EClass.rnd(5) == 0))
153 this.tc = this.owner.SetEnemy(this.tc.host);
155 if (this.tc.parasite !=
null && !
this.tc.isRestrained &&
this.tc.parasite.hp > 0 &&
EClass.rnd(5) == 0)
157 this.tc = this.owner.SetEnemy(this.tc.parasite);
159 if (this.tc.ride !=
null && !
this.tc.isRestrained &&
this.tc.ride.hp > 0 &&
EClass.rnd(5) == 0)
161 this.tc = this.owner.SetEnemy(this.tc.ride);
163 if (this.tc.enemy !=
null)
165 this.tc.TrySetEnemy(this.owner);
167 if (!this.tc.IsMinion &&
EClass.rnd(10) == 0 &&
EClass.rnd(
this.tc.DEX + 10) >
this.owner.LV &&
this.tc.HasElement(1315, 1) && !
this.owner.HasElement(1315, 1) &&
this.owner.race.IsMachine &&
this.owner.CanBeTempAlly(
this.tc))
169 this.owner.Say(
"dominate_machine", this.tc, this.owner,
null,
null);
170 this.owner.PlayEffect(
"boost",
true, 0f,
default(Vector3));
171 this.owner.PlaySound(
"boost", 1f,
true);
172 this.owner.ShowEmo(Emo.love, 0f,
true);
173 this.owner.lastEmo = Emo.angry;
174 this.owner.MakeMinion(this.tc.IsPCParty ?
EClass.pc :
this.tc, MinionType.Default);
175 yield
return base.Success(
null);
177 if (
EClass.rnd(5) == 0 &&
this.tc.HasElement(1325, 1) &&
this.owner.race.IsPlant &&
this.owner.CanBeTempAlly(
this.tc))
179 this.owner.Say(
"dominate_plant", this.tc, this.owner,
null,
null);
180 this.owner.ShowEmo(Emo.love, 0f,
true);
181 this.owner.lastEmo = Emo.angry;
182 this.owner.MakeMinion((this.tc.IsPCParty ||
this.tc.IsPCFactionMinion) ?
EClass.pc :
this.tc, MinionType.Friend);
183 yield
return base.Success(
null);
185 if (
EClass.rnd(20) == 0 &&
this.owner.isRestrained)
187 this.owner.Talk(
"restrained",
null,
null,
false);
192 EClass.pc.ModExp(135, 20);
194 int dist = this.owner.Dist(this.tc);
195 bool move = this.owner.host ==
null && (this.tactics.ChanceMove >
EClass.rnd(100) || (this.owner.IsPC &&
this.tc.HasCondition<
ConFear>() && dist >=
EClass.pc.GetSightRadius() - 1));
196 bool haltSecondMove =
false;
197 if (!this.owner.IsPC && !
this.owner.isBlind &&
this.tc.source.HasTag(CTAG.suicide) &&
this.owner.IsNeutralOrAbove() && !
this.owner.isSummon && !
this.owner.IsMinion && !
this.tc.HasCondition<
ConWet>())
203 this.owner.Talk(
"run_suicide",
null,
null,
false);
205 if (this.owner.host ==
null &&
this.owner.TryMoveFrom(
this.tc.pos) !=
Card.MoveResult.Fail)
207 yield
return AIAct.Status.Running;
214 haltSecondMove =
true;
220 int num2 = this.owner.Dist(
EClass.pc);
223 int x = this.tc.pos.x;
224 int z = this.tc.pos.z;
225 if (
EClass.pc.pos.Distance(
this.owner.pos.x + ((x >
this.owner.pos.x) ? 1 : ((x <
this.owner.pos.x) ? -1 : 0)),
this.owner.pos.z + ((z >
this.owner.pos.z) ? 1 : ((z <
this.owner.pos.z) ? -1 : 0))) >= num2)
228 haltSecondMove =
true;
232 if (this.owner.IsPC &&
EClass.game.config.autoCombat.bDontChase)
235 haltSecondMove =
true;
237 if (
EClass.debug.logCombat)
239 Debug.Log(
string.Concat(
new string[]
245 haltSecondMove.ToString(),
252 if (this.owner.IsPC && dist <=
this.owner.GetSightRadius() &&
this.TryUseAbility(dist,
true))
254 yield
return AIAct.Status.Running;
258 if (this.TryMove(dist))
260 if (
EClass.debug.logCombat)
262 Debug.Log(
"moved:" + this.owner.Name);
264 yield
return AIAct.Status.Running;
269 if (this.owner ==
null)
271 yield
return this.Cancel();
273 if (dist <= this.owner.GetSightRadius() &&
this.TryUseAbility(dist,
false))
275 yield
return AIAct.Status.Running;
280 if (
EClass.debug.logCombat)
282 Debug.Log(
string.Concat(
new string[]
288 haltSecondMove.ToString(),
290 this.tactics.ChanceSecondMove.ToString()
293 if (!move && !haltSecondMove && this.tactics.ChanceSecondMove >
EClass.rnd(100) &&
this.TryMove(dist))
295 yield
return AIAct.Status.Running;
300 if (this.owner ==
null)
302 yield
return this.Cancel();
305 if (this.TryAbortCombat())
307 yield
return base.Success(
null);
309 if (this.idleCount > 2)
313 yield
return base.Success(
null);
316 string aiIdle = this.owner.source.aiIdle;
317 if (aiIdle ==
"stand" || aiIdle ==
"root")
319 yield
return base.Success(
null);
321 yield
return base.DoGoto(this.tc.pos, 0,
false,
null);
323 else if (this.owner.FindNearestNewEnemy())
327 yield
return AIAct.Status.Running;
335 public bool TryMove(
int dist)
337 if (this.owner.host !=
null)
341 if (this.owner.isBlind)
343 return this.owner.MoveRandom();
345 int num = this.tc.HasCondition<
ConFear>() ? 1 : this.tactics.DestDist;
346 if (!this.owner.IsPC && (
this.tactics.source.id ==
"archer" ||
this.tactics.source.id ==
"gunner") && !
this.owner.TryEquipRanged())
350 if (!this.owner.IsPC && num > 1)
352 if (this.tactics.DestDist == 2)
359 else if (this.owner.turn / 3 % 5 > 2)
367 flag = (this.owner.TryMoveTowards(this.tc.pos) >
Card.MoveResult.Fail);
375 flag = (this.owner.TryMoveFrom(this.tc.pos) >
Card.MoveResult.Fail);
381 if (
EClass.debug.logCombat)
383 Debug.Log(
string.Concat(
new string[]
399 public void AddAbility(
Act a,
int mod = 0,
int chance = 100,
bool aiPt =
false)
411 public virtual bool TryUseRanged(
int dist)
413 return this.owner.TryEquipRanged() &&
ACT.Ranged.Perform(this.owner, this.tc,
null);
417 public virtual bool TryThrow(
int dist)
419 if (dist > this.owner.GetSightRadius())
423 Thing thing = this.owner.TryGetThrowable();
428 if (!
ACT.Throw.CanPerform(
this.owner,
this.tc,
this.tc.pos))
432 ActThrow.Throw(this.owner, this.tc.pos,
this.tc, thing.HasElement(410, 1) ? thing : thing.Split(1), ThrowMethod.Default);
437 public virtual bool TryUseAbility(
int dist,
bool beforeMove =
false)
440 CS$<>8__locals1.<>4__this =
this;
441 if (this.abilities.Count == 0)
443 string str =
"no ability:";
444 Chara owner = this.owner;
445 Debug.Log(str + ((owner !=
null) ? owner.ToString() :
null));
448 CS$<>8__locals1.numEnemy = -1;
449 CS$<>8__locals1.numFriend = -1;
450 CS$<>8__locals1.charaBuilt =
false;
451 bool flag = this.owner.CanSeeLos(this.tc, dist,
false);
452 bool isPCFaction = this.owner.IsPCFaction;
453 bool flag2 = this.owner.HasCondition<
ConSilence>();
454 bool isBlind = this.owner.isBlind;
455 bool flag3 = this.owner.HasCondition<
ConFear>();
456 bool isConfused = this.owner.isConfused;
457 bool flag4 = this.owner.HasCondition<
ConDim>();
460 if (
EClass.rnd(100) >= itemAbility.chance)
462 itemAbility.priority = 0;
466 Act act = itemAbility.act;
468 itemAbility.priority = 0;
469 itemAbility.tg =
null;
470 itemAbility.pt =
false;
471 if (s.abilityType.Length != 0 && (!
this.owner.IsPC || !flag2 || !(act is
Spell)) && (!beforeMove || act.HasTag(
"before_move")))
473 string text = s.abilityType[0];
474 if (this.
id != 6602 || (dist > 1 && !this.tc.HasCondition<
ConEntangle>()))
476 uint num = <PrivateImplementationDetails>.ComputeStringHash(text);
478 if (num <= 2140930120U)
480 if (num <= 979982427U)
482 if (num <= 115652151U)
484 if (num != 13211034U)
486 if (num != 115652151U)
490 if (!(text ==
"debuff"))
496 num2 = this.tactics.P_Debuff;
503 if (!(text ==
"summon"))
507 if (this.owner.isRestrained || (
this.tc !=
null &&
this.tc.IsRestrainedResident))
511 int num3 =
EClass._zone.CountMinions(this.owner);
512 if (num3 < this.owner.MaxSummon)
514 num2 = this.tactics.P_Summon - 20 * num3 / this.owner.MaxSummon;
520 else if (num != 601369519U)
522 if (num != 740945997U)
524 if (num != 979982427U)
528 if (!(text ==
"heal"))
536 if (!(text ==
"any"))
546 if (!(text ==
"suicide"))
550 if (this.owner.IsPC ||
this.owner.HasCondition<
ConWet>())
554 if (this.owner.HasTag(CTAG.kamikaze))
556 num2 = ((dist <= 1) ? 1000 : 0);
559 num2 = 100 - 125 * this.owner.hp / this.owner.MaxHP;
560 if (
EClass.rnd(200) > num2)
567 else if (num <= 1167440125U)
569 if (num != 1000963043U)
571 if (num != 1167440125U)
575 if (!(text ==
"attack"))
580 else if (!(text ==
"attackMelee"))
585 else if (num != 1244307660U)
587 if (num != 2043306875U)
589 if (num != 2140930120U)
593 if (!(text ==
"summonAlly"))
597 if (!this.owner.isRestrained && (
this.tc ==
null || !
this.tc.IsRestrainedResident))
601 if (
EClass.player.lastEmptyAlly <= 0)
606 else if (
EClass._zone.CountMinions(
this.owner) > 0)
610 num2 = this.tactics.P_Summon;
617 if (!(text ==
"melee"))
621 if (dist > this.owner.body.GetMeleeDistance())
625 num2 = (flag3 ? (this.owner.IsPC ? 0 : (this.tactics.P_Melee / 2)) : this.tactics.P_Melee);
628 num2 -= (this.owner.IsPC ? 30 : 10);
632 num2 -= (this.owner.IsPC ? 50 : 10);
634 if (this.tc.HasElement(1221, 1))
638 if (this.tc.HasElement(1223, 1))
648 if (!(text ==
"buff"))
652 num2 = CS$<>8__locals1.<TryUseAbility>g__ForeachChara|3(itemAbility, delegate(
Chara c)
654 if (!c.HasCondition(s.proc[1]))
656 return CS$<>8__locals1.<>4__this.tactics.P_Buff;
660 if (itemAbility.aiPt || (
this.owner.IsPC &&
this.tactics.CastPartyBuff))
662 itemAbility.pt =
true;
668 else if (num <= 2762313447U)
670 if (num <= 2360683452U)
672 if (num != 2301512864U)
674 if (num != 2360683452U)
678 if (!(text ==
"attackArea"))
682 if (this.owner.isRestrained || (
this.tc !=
null &&
this.tc.IsRestrainedResident))
686 bool flag5 = itemAbility.act is
ActBolt;
687 if (!flag || (this.owner.IsPCParty && (
EClass._zone.IsTown ||
EClass._zone.IsPCFaction)))
691 CS$<>8__locals1.<TryUseAbility>g__GetNumEnemy|0(flag5 ? 6 : 5);
692 if (CS$<>8__locals1.numEnemy != 0)
694 num2 = this.tactics.P_Spell - 20 + CS$<>8__locals1.numEnemy * 10 + CS$<>8__locals1.<TryUseAbility>g__GetAttackMod|4(act);
701 if (!(text ==
"wait"))
705 if (!this.owner.IsPCParty)
713 else if (num != 2627848062U)
715 if (num != 2671260646U)
717 if (num != 2762313447U)
721 if (!(text ==
"buffStats"))
725 num2 = CS$<>8__locals1.<TryUseAbility>g__ForeachChara|3(itemAbility, delegate(
Chara c)
727 Element buffStats = c.GetBuffStats(s.proc[1]);
728 if (buffStats !=
null && buffStats.Value >= 0)
732 return CS$<>8__locals1.<>4__this.tactics.P_Buff;
734 if (itemAbility.aiPt || (
this.owner.IsPC &&
this.tactics.CastPartyBuff))
736 itemAbility.pt =
true;
743 if (!(text ==
"item"))
747 num2 = (itemAbility.act as
ActItem).BuildAct(this.owner);
753 if (!(text ==
"ground"))
757 if (!flag || this.owner.isRestrained || (
this.tc !=
null &&
this.tc.IsRestrainedResident))
770 else if (num <= 3546849056U)
772 if (num != 3164374115U)
774 if (num != 3289626814U)
776 if (num != 3546849056U)
780 if (!(text ==
"dot"))
787 if (!(text ==
"teleport"))
797 if (!(text ==
"taunt"))
801 bool flag6 = this.owner.HasCondition<
StanceTaunt>();
802 bool flag7 = this.tactics.source.taunt != -1 && 100 * this.owner.hp / this.owner.MaxHP >= this.tactics.source.taunt;
803 num2 = ((flag6 && !flag7) ? 100 : ((!flag6 && flag7) ? 100 : 0));
807 else if (num != 4208725202U)
809 if (num != 4274235348U)
811 if (num != 4289936826U)
815 if (!(text ==
"debuffStats"))
821 num2 = CS$<>8__locals1.<TryUseAbility>g__ForeachChara|3(itemAbility, delegate(
Chara c)
823 Element buffStats = c.GetBuffStats(s.proc[1]);
824 if (buffStats !=
null && buffStats.Value <= 0)
828 return CS$<>8__locals1.<>4__this.tactics.P_Debuff;
836 if (!(text ==
"hot"))
845 if (!(text ==
"range"))
849 if (!flag ||
EClass.rnd(100) >
this.tactics.RangedChance)
853 num2 = (flag3 ? (this.owner.IsPC ? 0 : (this.tactics.P_Range / 2)) : this.tactics.P_Range);
856 num2 -= (this.owner.IsPC ? 30 : 10);
860 num2 -= (this.owner.IsPC ? 50 : 10);
862 if (this.owner.ranged !=
null &&
this.owner.ranged.trait is
TraitToolRangeCane &&
this.owner.mana.value <= 0)
872 bool flag8 = text ==
"dot";
873 if (flag8 && (this.owner.isRestrained || (
this.tc !=
null &&
this.tc.IsRestrainedResident)))
877 num2 = ((text ==
"attackMelee") ? this.tactics.P_Melee : this.tactics.P_Spell) + CS$<>8__locals1.<TryUseAbility>g__GetAttackMod|4(act);
878 if (num2 > 0 && flag8)
883 if (s.target ==
"Neighbor")
891 if (s.proc.Length == 0 || !(s.proc[0] ==
"Debuff") || !
this.tc.HasCondition(s.proc[1]))
893 if (s.abilityType.Length > 1)
895 num2 += (this.owner.IsPC ? s.abilityType[2] : s.abilityType[1]).ToInt();
901 if (act.vPotential <= 0)
905 if (flag2 || isConfused || flag4)
916 if (isConfused || flag4)
924 num2 += itemAbility.priorityMod +
EClass.rnd(this.tactics.RandomFacotr + itemAbility.priorityMod);
926 itemAbility.priority = num2;
931 bool isHOT = text ==
"hot";
932 num2 = CS$<>8__locals1.<TryUseAbility>g__ForeachChara|3(itemAbility, (
Chara c) => base.<TryUseAbility>g__HealFactor|6(c),
true);
933 if (itemAbility.aiPt || (
this.owner.IsPC &&
this.tactics.CastPartyBuff))
935 itemAbility.pt =
true;
949 if (itemAbility2.priority > 0)
951 if (
EClass.debug.logCombat &&
this.owner.IsPC)
953 Debug.Log(itemAbility2.act.Name +
"/" + itemAbility2.priority.ToString());
955 if (itemAbility2.act.source.alias ==
"ActRanged")
957 if (this.TryThrow(dist))
961 if (this.TryUseRanged(dist))
968 Act.Cost cost = itemAbility2.act.GetCost(this.owner);
969 if (!this.owner.IsPCParty || !itemAbility2.pt || itemAbility2.act.TargetType.ForceParty || cost.cost *
EClass.pc.party.members.Count <=
this.owner.mana.value)
971 if (isPCFaction && cost.cost > 0)
973 Act.CostType type = cost.type;
974 if (type !=
Act.CostType.MP)
976 if (type ==
Act.CostType.SP)
978 if (cost.cost >
this.owner.stamina.value)
984 else if (cost.cost >
this.owner.mana.value)
989 if ((cost.cost <= 0 ||
EClass.rnd(100) <=
this.tactics.AbilityChance) && itemAbility2.act.CanPerform(
this.owner, itemAbility2.tg ??
this.tc,
null) &&
this.owner.UseAbility(itemAbility2.act, itemAbility2.tg ??
this.tc,
null, (itemAbility2.act.HaveLongPressAction && itemAbility2.pt) || itemAbility2.aiPt))
991 if (
EClass.debug.logCombat)
993 string[] array =
new string[9];
994 array[0] = this.owner.Name;
996 array[2] = itemAbility2.act.id.ToString();
998 array[4] = itemAbility2.act.CanPerform(this.owner, itemAbility2.tg ??
this.tc,
null).ToString();
1001 Chara tg = itemAbility2.tg;
1002 array[num4] = ((tg !=
null) ? tg.ToString() :
null);
1005 Chara chara = this.tc;
1006 array[num5] = ((chara !=
null) ? chara.ToString() :
null);
1007 Debug.Log(
string.Concat(array));
1015 if (
EClass.debug.logCombat)
1017 Debug.Log(this.owner.Name +
"/" +
this.abilities.Count.ToString());
1020 Debug.Log(itemAbility3.act.Name);
1027 public virtual void BuildAbilityList()
1029 foreach (
ActList.
Item item in
this.owner.ability.list.items)
1031 this.AddAbility(item.act, 0, item.chance, item.pt);
1033 this.AddAbility(
ACT.Ranged, 0, 100,
false);
1034 this.AddAbility(
ACT.Melee, 0, 100,
false);
1035 this.AddAbility(
ACT.Item, 0, 100,
false);
1039 public virtual bool TryAbortCombat()
1046 private void <Run>g__CalmDown|14_0()
1048 this.owner.enemy =
null;
1049 if (this.owner.ride !=
null)
1051 this.owner.ride.enemy =
null;
1053 if (this.owner.parasite !=
null)
1055 this.owner.parasite.enemy =
null;
1057 this.owner.hostility = this.owner.OriginalHostility;
1058 if (this.tc.enemy ==
this.owner)
1060 this.tc.enemy =
null;
1061 if (this.tc.ride !=
null)
1063 this.tc.ride.enemy =
null;
1065 if (this.tc.parasite !=
null)
1067 this.tc.parasite.enemy =
null;
1069 this.tc.hostility = this.tc.OriginalHostility;
1071 this.owner.Say(
"calmDown", this.owner,
null,
null);
1075 public Chara destEnemy;
1081 public int idleCount;
1084 public int moveFail;
1090 public List<Chara> charas =
new List<Chara>();
1099 public int priority;
1102 public int priorityMod;