Elin Decompiled Documentation EA 23.327 Nightly
Loading...
Searching...
No Matches
GoalCombat.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using UnityEngine;
4
5public class GoalCombat : Goal
6{
7 public class ItemAbility
8 {
9 public Act act;
10
11 public int priority;
12
13 public int priorityMod;
14
15 public int chance;
16
17 public Chara tg;
18
19 public bool pt;
20
21 public bool aiPt;
22
23 public bool aiSelf;
24 }
25
27
28 public Chara tc;
29
30 public int idleCount;
31
32 public int moveFail;
33
34 public List<ItemAbility> abilities;
35
36 public List<Chara> charas = new List<Chara>();
37
39
40 public override bool CancelWhenDamaged => false;
41
42 public override bool CancelOnAggro => false;
43
45
46 public override bool CanManualCancel()
47 {
48 if (owner != null)
49 {
50 return !owner.isBerserk;
51 }
52 return false;
53 }
54
55 public override IEnumerable<Status> Run()
56 {
57 if (destEnemy != null)
58 {
59 owner.enemy = destEnemy;
60 destEnemy = null;
61 }
62 int count = 0;
63 int lostCount = 0;
64 bool dontWander = owner.IsPCParty && !owner.IsPC && EClass.game.config.tactics.dontWander;
65 while (true)
66 {
68 {
69 EClass._zone.SetAlarm(enable: true);
70 }
71 bool canSeeLos = false;
73 {
74 Debug.Log("■" + owner.Name + "/" + count + "/" + lostCount);
75 }
77 {
78 owner.enemy = null;
79 owner.ShowEmo(Emo.happy);
80 yield return Success();
81 }
82 count++;
83 if (dontWander && owner.enemy != null && !EClass.pc.isBlind && !EClass.pc.CanSeeLos(owner.enemy) && (owner.Dist(EClass.pc) > 4 || owner.Dist(owner.enemy) > 1))
84 {
86 if (firstStep.IsValid && !firstStep.HasChara)
87 {
88 owner.enemy = null;
89 }
90 }
91 tc = owner.enemy;
92 if (tc != null && owner.IsPCFactionOrMinion)
93 {
95 {
96 owner.enemy = null;
97 yield return Success();
98 }
100 {
101 tc = (owner.enemy = null);
102 }
103 }
104 if (tc == null || tc.isDead || !tc.ExistsOnMap || !tc.pos.IsInBounds || lostCount >= (owner.IsPowerful ? 50 : 5) || !owner.CanSee(tc))
105 {
106 tc = (owner.enemy = null);
108 {
109 yield return Success();
110 }
112 lostCount = 0;
113 if (owner.enemy == null)
114 {
115 yield return Success();
116 }
117 tc = owner.enemy;
118 }
119 else
120 {
121 canSeeLos = owner.CanSeeLos(tc);
122 lostCount = ((!canSeeLos) ? (lostCount + 1) : 0);
123 }
124 if (owner.IsPC && tc.HasEditorTag(EditorTag.Invulnerable))
125 {
126 Msg.Say("abort_idle");
127 yield return Success();
128 }
129 if (tc.IsPCFaction && owner.id == "melilith_boss" && EClass._map.plDay.list.Count > 1 && EClass._map.plDay.list[0].data.id != 107)
130 {
131 EClass._zone.SetBGM(107);
132 }
133 if (abilities == null)
134 {
135 abilities = new List<ItemAbility>();
137 }
138 if (owner.IsPCFaction && tc.IsPCFaction && EClass.rnd(5) == 0 && count > 2)
139 {
140 CalmDown();
141 yield return Success();
142 }
144 {
145 if (owner.calmCheckTurn < 0 || (!owner.enemy.IsPCParty && EClass.rnd(10) == 0))
146 {
147 CalmDown();
148 yield return Success();
149 }
151 }
153 {
154 foreach (Chara chara in EClass._map.charas)
155 {
156 if (!chara.IsPCFactionOrMinion && !chara.IsInCombat && chara != owner && chara.trait is TraitBigDaddy)
157 {
158 chara.GoHostile(tc);
159 }
160 }
161 }
162 if (owner.IsPC)
163 {
164 CursorSystem.ignoreCount = 1;
165 }
166 if (tc.host != null && (tc.hp == 0 || EClass.rnd(5) == 0 || tc.host.isRestrained))
167 {
169 }
170 if (tc.parasite != null && !tc.isRestrained && tc.parasite.hp > 0 && EClass.rnd(5) == 0)
171 {
173 }
174 if (tc.ride != null && !tc.isRestrained && tc.ride.hp > 0 && EClass.rnd(5) == 0)
175 {
177 }
178 if (tc.enemy != null)
179 {
181 }
182 if (!tc.IsMinion && EClass.rnd(10) == 0 && EClass.rnd(tc.DEX + 10) > owner.LV && tc.HasElement(1315) && !owner.HasElement(1315) && owner.IsMachine && owner.CanBeTempAlly(tc) && owner.id != "mech_scarab")
183 {
184 owner.Say("dominate_machine", tc, owner);
185 owner.PlayEffect("boost");
186 owner.PlaySound("boost");
187 owner.ShowEmo(Emo.love);
188 owner.lastEmo = Emo.angry;
190 yield return Success();
191 }
192 if (EClass.rnd(5) == 0 && tc.HasElement(1325) && owner.IsPlant && owner.CanBeTempAlly(tc))
193 {
194 owner.Say("dominate_plant", tc, owner);
195 owner.ShowEmo(Emo.love);
196 owner.lastEmo = Emo.angry;
198 yield return Success();
199 }
200 if (EClass.rnd(20) == 0 && owner.isRestrained)
201 {
202 owner.Talk("restrained");
203 }
204 if (this is GoalAutoCombat)
205 {
207 EClass.pc.ModExp(135, 20);
208 }
209 int dist = owner.Dist(tc);
210 bool move = owner.host == null && (tactics.ChanceMove > EClass.rnd(100) || (owner.IsPC && tc.HasCondition<ConFear>() && dist >= EClass.pc.GetSightRadius() - 1));
211 bool haltSecondMove = false;
212 if (!owner.IsPC && owner.IsNeutralOrAbove() && !owner.isBlind && !owner.isSummon && !owner.IsMinion)
213 {
214 int num = -1;
215 if (tc.HasElement(1221))
216 {
217 num = 1;
218 }
219 if (tc.source.HasTag(CTAG.suicide) && !tc.HasCondition<ConWet>())
220 {
221 num = 3;
222 }
223 if (num > 0)
224 {
225 if (dist <= num)
226 {
227 if (EClass.rnd(15) == 0)
228 {
229 owner.Talk("run_suicide");
230 }
231 if (owner.host == null && owner.TryMoveFrom(tc.pos) != 0)
232 {
233 yield return Status.Running;
234 idleCount = 0;
235 continue;
236 }
238 {
239 Debug.Log("Failed to Run: " + owner.Name);
240 }
241 }
242 if (dist == num + 1)
243 {
244 haltSecondMove = true;
245 move = false;
246 idleCount = 0;
247 }
248 }
249 }
250 if (dontWander)
251 {
252 int num2 = owner.Dist(EClass.pc);
253 if (num2 > 3)
254 {
255 int x = tc.pos.x;
256 int z = tc.pos.z;
257 if (EClass.pc.pos.Distance(owner.pos.x + ((x > owner.pos.x) ? 1 : ((x < owner.pos.x) ? (-1) : 0)), owner.pos.z + ((z > owner.pos.z) ? 1 : ((z < owner.pos.z) ? (-1) : 0))) >= num2)
258 {
259 move = false;
260 haltSecondMove = true;
261 }
262 }
263 }
264 if ((owner.IsPC && EClass.game.config.autoCombat.bDontChase) || (!canSeeLos && tc.isHidden))
265 {
266 move = false;
267 haltSecondMove = true;
268 }
270 {
271 Debug.Log(owner.Name + "/" + move + "/" + haltSecondMove + "/" + dist);
272 }
273 if (move)
274 {
275 if (owner.IsPC && dist <= owner.GetSightRadius() && TryUseAbility(dist, beforeMove: true))
276 {
277 yield return Status.Running;
278 idleCount = 0;
279 continue;
280 }
281 if (TryMove(dist))
282 {
284 {
285 Debug.Log("moved:" + owner.Name);
286 }
287 yield return Status.Running;
288 idleCount = 0;
289 continue;
290 }
291 }
292 if (owner == null)
293 {
294 yield return Cancel();
295 }
296 if (dist <= owner.GetSightRadius() && TryUseAbility(dist))
297 {
298 yield return Status.Running;
299 idleCount = 0;
300 continue;
301 }
303 {
304 Debug.Log(owner.Name + "/" + move + "/" + haltSecondMove + "/" + tactics.ChanceSecondMove);
305 }
306 if (!move && !haltSecondMove && tactics.ChanceSecondMove > EClass.rnd(100) && TryMove(dist))
307 {
308 yield return Status.Running;
309 idleCount = 0;
310 continue;
311 }
312 if (owner == null)
313 {
314 yield return Cancel();
315 }
316 idleCount++;
317 if (TryAbortCombat())
318 {
319 yield return Success();
320 }
321 if (idleCount > 1 && owner.id == "keeper_garden" && owner.enemy != null)
322 {
323 owner.Teleport(owner.enemy.pos.GetNearestPoint(allowBlock: false, allowChara: false, allowInstalled: true, ignoreCenter: true, 3) ?? EClass._map.GetRandomSurface(), silent: false, force: true);
324 yield return Success();
325 }
326 if (idleCount > 2)
327 {
328 if (dontWander)
329 {
330 yield return Success();
331 }
332 idleCount = 0;
333 string aiIdle = owner.source.aiIdle;
334 if (aiIdle == "stand" || aiIdle == "root")
335 {
336 yield return Success();
337 }
338 if (owner.tactics.DestDist > 4)
339 {
340 yield return Success();
341 }
342 yield return DoGoto(tc.pos);
343 }
344 else if (owner.FindNearestNewEnemy())
345 {
346 yield return Status.Running;
347 continue;
348 }
349 yield return Status.Running;
350 }
351 void CalmDown()
352 {
353 owner.enemy = null;
354 if (owner.ride != null)
355 {
356 owner.ride.enemy = null;
357 }
358 if (owner.parasite != null)
359 {
360 owner.parasite.enemy = null;
361 }
362 owner.hostility = owner.OriginalHostility;
363 if (tc.enemy == owner)
364 {
365 tc.enemy = null;
366 if (tc.ride != null)
367 {
368 tc.ride.enemy = null;
369 }
370 if (tc.parasite != null)
371 {
372 tc.parasite.enemy = null;
373 }
374 tc.hostility = tc.OriginalHostility;
375 }
376 owner.Say("calmDown", owner);
377 }
378 }
379
380 public bool TryMove(int dist)
381 {
383 {
384 Debug.Log("TryMove: " + owner.Name + "/" + dist);
385 }
386 if (owner.host != null)
387 {
388 return false;
389 }
390 if (owner.isBlind)
391 {
392 return owner.MoveRandom();
393 }
394 int num = (tc.HasCondition<ConFear>() ? 1 : tactics.DestDist);
395 if (!owner.IsPC && (tactics.source.id == "archer" || tactics.source.id == "gunner") && !owner.TryEquipRanged())
396 {
397 num = 1;
398 }
399 if (!owner.IsPC && num > 1)
400 {
401 if (tactics.DestDist == 2)
402 {
403 if (EClass.rnd(5) == 0)
404 {
405 num = 1;
406 }
407 }
408 else if (owner.turn / 3 % 5 > 2)
409 {
410 num--;
411 }
412 }
413 bool flag = false;
414 if (dist > num)
415 {
416 flag = owner.TryMoveTowards(tc.pos) != Card.MoveResult.Fail;
417 if (!flag)
418 {
419 moveFail++;
420 }
421 }
422 else if (dist < num)
423 {
424 flag = owner.TryMoveFrom(tc.pos) != Card.MoveResult.Fail;
425 }
426 if (flag)
427 {
428 moveFail = 0;
429 }
431 {
432 Debug.Log("TryMove:" + owner.Name + "/" + flag + "/" + dist + "/" + num);
433 }
434 return flag;
435 }
436
437 public void AddAbility(Act a, int mod = 0, int chance = 100, bool aiPt = false)
438 {
439 abilities.Add(new ItemAbility
440 {
441 act = a,
442 priorityMod = mod,
443 chance = chance,
444 aiPt = aiPt
445 });
446 }
447
448 public void TryAddAbility(int ele)
449 {
450 if (abilities == null)
451 {
453 }
454 foreach (ItemAbility ability in abilities)
455 {
456 Act obj = ability.act;
457 if (obj != null && obj.id == ele)
458 {
459 return;
460 }
461 }
462 AddAbility(Element.Create(ele) as Act);
463 }
464
465 public void TryRemoveAbility(int ele)
466 {
467 if (abilities == null)
468 {
469 return;
470 }
471 foreach (ItemAbility ability in abilities)
472 {
473 Act obj = ability.act;
474 if (obj != null && obj.id == ele)
475 {
476 abilities.Remove(ability);
477 break;
478 }
479 }
480 }
481
482 public virtual bool TryUseRanged(int dist)
483 {
484 if (owner.TryEquipRanged())
485 {
486 return ACT.Ranged.Perform(owner, tc);
487 }
488 return false;
489 }
490
491 public virtual bool TryThrow(int dist)
492 {
493 if (dist > owner.GetSightRadius())
494 {
495 return false;
496 }
497 Thing thing = owner.TryGetThrowable();
498 if (thing == null)
499 {
500 return false;
501 }
502 if (!ACT.Throw.CanPerform(owner, tc, tc.pos))
503 {
504 return false;
505 }
506 ActThrow.Throw(owner, tc.pos, tc, thing.HasElement(410) ? thing : thing.Split(1));
507 return true;
508 }
509
510 public virtual bool TryUseAbility(int dist, bool beforeMove = false)
511 {
512 if (abilities.Count == 0)
513 {
514 Debug.Log("no ability:" + owner);
515 return false;
516 }
517 int numEnemy = -1;
518 int numFriend = -1;
519 int numNeutral = -1;
520 bool charaBuilt = false;
521 bool flag = owner.CanSeeLos(tc, dist);
522 bool isPCFaction = owner.IsPCFaction;
523 bool flag2 = owner.HasCondition<ConSilence>();
524 bool isBlind = owner.isBlind;
525 bool flag3 = owner.HasCondition<ConFear>();
526 bool isConfused = owner.isConfused;
527 bool flag4 = owner.HasCondition<ConDim>();
528 bool flag5 = owner.HasCondition<ConSupress>();
529 foreach (ItemAbility ability in abilities)
530 {
531 Act act = ability.act;
532 if (act.id == 8801 && owner.race.id == "spider" && EClass._zone.HasField(10000) && !owner.IsPCFactionOrMinion)
533 {
534 ability.act = ACT.Create(50413);
535 }
536 ability.priority = 0;
537 ability.tg = null;
538 ability.pt = false;
539 if (EClass.rnd(100) >= ability.chance || (isBlind && act.HasTag("reqSight")) || (owner.isBerserk && !(act is ActMelee) && !(act is ActRanged) && !(act is ActBreathe) && !(act is ActThrow)))
540 {
541 continue;
542 }
543 int num = 0;
545 if (s.abilityType.Length == 0 || (owner.IsPC && flag2 && act is Spell) || (beforeMove && !act.HasTag("before_move")))
546 {
547 continue;
548 }
549 string text = s.abilityType[0];
550 if (flag5 && !(text == "melee") && !(text == "range") && EClass.rnd(2) == 0)
551 {
552 continue;
553 }
554 bool isHOT;
555 switch (text)
556 {
557 case "any":
558 num = 50;
559 break;
560 case "item":
561 num = (act as ActItem).BuildAct(owner);
562 break;
563 case "wait":
564 if (owner.IsPCParty)
565 {
566 continue;
567 }
568 num = 50;
569 break;
570 case "taunt":
571 {
572 bool flag6 = owner.HasCondition<StanceTaunt>();
573 bool flag7 = tactics.source.taunt != -1 && 100 * owner.hp / owner.MaxHP >= tactics.source.taunt;
574 num = ((flag6 && !flag7) ? 100 : ((!flag6 && flag7) ? 100 : 0));
575 break;
576 }
577 case "song":
578 {
579 bool flag10 = owner.HasCondition<BaseSong>();
580 bool flag11 = owner.mana.value > owner.mana.max / 3;
581 num = ((flag10 && !flag11) ? 100 : ((!flag10 && flag11) ? 100 : 0));
582 break;
583 }
584 case "melee":
585 if (tactics.source.melee == 0 || dist > owner.body.GetMeleeDistance())
586 {
587 continue;
588 }
589 num = ((!flag3) ? tactics.P_Melee : ((!owner.IsPC) ? (tactics.P_Melee / 2) : 0));
590 if (isConfused)
591 {
592 num -= (owner.IsPC ? 30 : 10);
593 }
594 if (isBlind)
595 {
596 num -= (owner.IsPC ? 50 : 10);
597 }
598 if (dist <= 1)
599 {
600 if (tc.HasElement(1221))
601 {
602 num -= 40;
603 }
604 if (tc.HasElement(1223))
605 {
606 num -= 40;
607 }
608 if (!owner.IsPC && owner.IsPCFaction && tc.id == "hedgehog_ether")
609 {
610 continue;
611 }
612 if (!owner.IsPCFaction && num < 10)
613 {
614 num = 10;
615 }
616 }
617 break;
618 case "range":
619 if (!flag || EClass.rnd(100) > tactics.RangedChance)
620 {
621 continue;
622 }
623 num = ((!flag3) ? tactics.P_Range : ((!owner.IsPC) ? (tactics.P_Range / 2) : 0));
624 if (isConfused)
625 {
626 num -= (owner.IsPC ? 30 : 10);
627 }
628 if (isBlind)
629 {
630 num -= (owner.IsPC ? 50 : 10);
631 }
632 if (owner.ranged != null && owner.ranged.trait is TraitToolRangeCane && owner.mana.value <= 0)
633 {
634 continue;
635 }
636 break;
637 case "teleport":
638 num = 40;
639 break;
640 case "hot":
641 case "heal":
642 isHOT = text == "hot";
643 num = ForeachChara(ability, (Chara c) => HealFactor(c), isFriendlyAbility: true);
644 if (ability.aiPt || (owner.IsPC && tactics.CastPartyBuff))
645 {
646 ability.pt = true;
647 }
648 break;
649 case "dot":
650 case "attack":
651 case "attackMelee":
652 {
653 if (!flag)
654 {
655 continue;
656 }
657 bool flag9 = text == "dot";
658 if (flag9 && (owner.isRestrained || (tc != null && tc.IsRestrainedResident)))
659 {
660 continue;
661 }
662 num = ((text == "attackMelee") ? tactics.P_Melee : tactics.P_Spell) + GetAttackMod(act);
663 if (num > 0 && flag9)
664 {
665 num += 10;
666 }
667 if (ability.aiPt)
668 {
669 ability.pt = true;
670 }
671 break;
672 }
673 case "attackArea":
674 {
675 if (owner.isRestrained || (tc != null && tc.IsRestrainedResident))
676 {
677 continue;
678 }
679 bool flag8 = act is ActBolt;
680 if ((owner.pos.IsBlocked && (flag8 || act is ActBall || act is ActBreathe)) || !flag || (owner.IsPCParty && (EClass._zone.IsTown || EClass._zone.IsPCFaction)) || (act.id == 9150 && EClass._zone.IsPCFaction && owner.IsNeutralOrAbove()))
681 {
682 continue;
683 }
684 GetNumEnemy(flag8 ? 6 : 5);
685 if (numEnemy == 0 || (owner.IsPCFactionOrMinion && GetNumNeutral(flag8 ? 6 : 5) > 0))
686 {
687 continue;
688 }
689 num = tactics.P_Spell - 20 + numEnemy * 10 + GetAttackMod(act);
690 break;
691 }
692 case "buff":
693 num = ForeachChara(ability, (Chara c) => (!c.HasCondition(s.proc[1])) ? tactics.P_Buff : 0, isFriendlyAbility: true);
694 if (ability.aiPt || (owner.IsPC && tactics.CastPartyBuff))
695 {
696 ability.pt = true;
697 }
698 break;
699 case "buffStats":
700 num = ForeachChara(ability, delegate(Chara c)
701 {
702 Element buffStats2 = c.GetBuffStats(s.proc[1]);
703 return (buffStats2 == null || buffStats2.Value < 0) ? tactics.P_Buff : 0;
704 }, isFriendlyAbility: true);
705 if (ability.aiPt || (owner.IsPC && tactics.CastPartyBuff))
706 {
707 ability.pt = true;
708 }
709 break;
710 case "cure":
711 num = ForeachChara(ability, (Chara c) => c.CountDebuff() * 30, isFriendlyAbility: true);
712 if (ability.aiPt || (owner.IsPC && tactics.CastPartyBuff))
713 {
714 ability.pt = true;
715 }
716 break;
717 case "debuff":
718 if (!flag)
719 {
720 continue;
721 }
722 num = tactics.P_Debuff;
723 if (ability.aiPt)
724 {
725 ability.pt = true;
726 }
727 break;
728 case "debuffStats":
729 if (!flag)
730 {
731 continue;
732 }
733 num = ForeachChara(ability, delegate(Chara c)
734 {
735 Element buffStats = c.GetBuffStats(s.proc[1]);
736 return (buffStats == null || buffStats.Value > 0) ? tactics.P_Debuff : 0;
737 }, isFriendlyAbility: false);
738 if (ability.aiPt)
739 {
740 ability.pt = true;
741 }
742 break;
743 case "ground":
744 if (!flag || owner.isRestrained || (tc != null && tc.IsRestrainedResident))
745 {
746 continue;
747 }
748 num = 50;
749 if (isPCFaction)
750 {
751 num -= 10;
752 }
753 break;
754 case "summon":
755 {
756 if (owner.isRestrained || (tc != null && tc.IsRestrainedResident))
757 {
758 continue;
759 }
760 int num2 = EClass._zone.CountMinions(owner);
761 if (num2 >= owner.MaxSummon)
762 {
763 continue;
764 }
765 num = tactics.P_Summon - 20 * num2 / owner.MaxSummon;
766 break;
767 }
768 case "summonAlly":
769 if (owner.isRestrained || (tc != null && tc.IsRestrainedResident))
770 {
771 continue;
772 }
773 if (owner.IsPC)
774 {
775 if (EClass.player.lastEmptyAlly <= 0)
776 {
777 continue;
778 }
779 }
780 else if (EClass._zone.CountMinions(owner) > 0)
781 {
782 continue;
783 }
784 num = tactics.P_Summon;
785 break;
786 case "summonSpecial":
787 if (owner.GetInt(70) > EClass.world.date.GetRaw())
788 {
789 continue;
790 }
791 num = 1000;
792 break;
793 case "summonSpecial2":
794 num = 1000;
795 break;
796 case "suicide":
798 {
799 continue;
800 }
801 if (owner.HasTag(CTAG.kamikaze))
802 {
803 num = ((dist <= 1) ? 1000 : 0);
804 break;
805 }
806 num = 100 - 125 * owner.hp / owner.MaxHP;
807 if (EClass.rnd(200) <= num && (!owner.IsPowerful || owner.hp < owner.MaxHP / 2))
808 {
809 break;
810 }
811 continue;
812 default:
813 num = 0;
814 break;
815 }
816 switch (act.id)
817 {
818 case 6802:
820 {
821 continue;
822 }
823 break;
824 case 6606:
825 if (owner.mana.value <= 0)
826 {
827 continue;
828 }
829 break;
830 case 6603:
831 if (!tc.IsPCParty || tc.Evalue(418) < 0)
832 {
833 break;
834 }
835 foreach (Chara member in EClass.pc.party.members)
836 {
837 if (member.Evalue(418) < 0)
838 {
839 owner.enemy = (tc = member);
840 return false;
841 }
842 }
843 break;
844 case 6602:
845 if (dist <= 1 || tc.HasCondition<ConEntangle>())
846 {
847 continue;
848 }
849 break;
850 case 6450:
851 if (isPCFaction && (tc.HasElement(1221) || tc.HasElement(1223) || tc.id == "hedgehog_ether"))
852 {
853 continue;
854 }
855 break;
856 case 8200:
857 case 8201:
858 if (owner.HasElement(400))
859 {
860 continue;
861 }
862 break;
863 case 6400:
864 if (isPCFaction)
865 {
866 continue;
867 }
868 break;
869 case 8790:
870 case 8791:
871 if (tc.host != null)
872 {
873 continue;
874 }
875 break;
876 case 6900:
877 if (owner.IsPC)
878 {
879 continue;
880 }
881 if (owner.IsPCParty)
882 {
883 foreach (Chara member2 in EClass.pc.party.members)
884 {
885 float num4 = 100f - (float)(member2.mana.value * 100) / MathF.Max(1f, member2.mana.max);
886 if (num4 > (float)num)
887 {
888 num = (int)num4;
889 }
890 }
891 }
892 else
893 {
894 num = 100 - owner.mana.value * 100 / Mathf.Max(1, owner.mana.max);
895 }
896 break;
897 case 6627:
899 {
900 continue;
901 }
902 num = 100 - owner.hp * 100 / Mathf.Max(1, owner.MaxHP);
903 break;
904 case 9200:
905 {
906 int num3 = 0;
907 foreach (Condition condition in tc.conditions)
908 {
909 if (condition.Type == ConditionType.Debuff)
910 {
911 num3++;
912 }
913 }
914 num = num3 * 15;
915 break;
916 }
917 }
918 if (s.target == "Neighbor")
919 {
920 if (dist > 1)
921 {
922 continue;
923 }
924 num += 10;
925 }
926 if (s.proc.Length != 0 && s.proc[0] == "Debuff" && tc.HasCondition(s.proc[1]))
927 {
928 continue;
929 }
930 if (s.abilityType.Length > 1)
931 {
932 num += (owner.IsPC ? s.abilityType[2] : s.abilityType[1]).ToInt();
933 }
934 if (act is Spell)
935 {
936 if (owner.IsPC)
937 {
938 if (act.vPotential <= 0 && !owner.ability.Has(act.id))
939 {
940 continue;
941 }
942 if (flag2 || isConfused || flag4)
943 {
944 num -= 50;
945 }
946 }
947 else
948 {
949 if (flag2)
950 {
951 num -= 30;
952 }
953 if (isConfused || flag4)
954 {
955 num -= 10;
956 }
957 }
958 }
959 if (num > 0)
960 {
961 num += ability.priorityMod + EClass.rnd(tactics.RandomFacotr + ability.priorityMod);
962 }
963 ability.priority = num;
964 int HealFactor(Chara c)
965 {
966 if (isHOT && c.HasCondition(s.proc[1]))
967 {
968 return 0;
969 }
970 float num7 = (float)c.hp / (float)c.MaxHP;
971 if (num7 > (isHOT ? 0.85f : 0.75f))
972 {
973 return 0;
974 }
975 int num8 = tactics.P_Heal - (int)((float)tactics.P_Heal * num7) + (isHOT ? 50 : 25);
976 foreach (Condition condition2 in c.conditions)
977 {
978 if (condition2 is ConFear)
979 {
980 num8 += 10;
981 }
982 else if (condition2 is ConPoison)
983 {
984 num8 += 2;
985 }
986 else if (condition2 is ConConfuse)
987 {
988 num8 += 4;
989 }
990 else if (condition2 is ConDim)
991 {
992 num8 += 6;
993 }
994 else if (condition2 is ConBleed)
995 {
996 num8 += 8;
997 }
998 }
999 return num8;
1000 }
1001 }
1002 abilities.Sort((ItemAbility a, ItemAbility b) => b.priority - a.priority);
1003 foreach (ItemAbility ability2 in abilities)
1004 {
1005 if (ability2.priority <= 0)
1006 {
1007 continue;
1008 }
1010 {
1011 Debug.Log(ability2.act.Name + "/" + ability2.priority + "/" + ability2.act.CanPerform(owner, ability2.tg ?? tc));
1012 }
1013 if (ability2.act.source.alias == "ActRanged")
1014 {
1015 if (TryThrow(dist))
1016 {
1017 return true;
1018 }
1019 if (TryUseRanged(dist))
1020 {
1021 return true;
1022 }
1023 continue;
1024 }
1025 Cost cost = ability2.act.GetCost(owner);
1026 if (owner.IsPCParty && ability2.pt && !ability2.act.IsTargetHostileParty() && !ability2.act.TargetType.ForceParty && cost.cost * EClass.pc.party.members.Count > owner.mana.value)
1027 {
1028 continue;
1029 }
1030 if (isPCFaction && cost.cost > 0)
1031 {
1032 switch (cost.type)
1033 {
1034 case CostType.MP:
1035 if (cost.cost > owner.mana.value)
1036 {
1037 continue;
1038 }
1039 break;
1040 case CostType.SP:
1041 if (cost.cost > owner.stamina.value)
1042 {
1043 continue;
1044 }
1045 break;
1046 }
1047 }
1048 if (cost.cost > 0 && EClass.rnd(100) > tactics.AbilityChance)
1049 {
1050 continue;
1051 }
1052 Chara chara = owner;
1053 if (ability2.act.CanPerform(owner, ability2.tg ?? tc) && owner.UseAbility(ability2.act, ability2.tg ?? tc, null, (ability2.act.HaveLongPressAction && ability2.pt) || ability2.aiPt))
1054 {
1056 {
1057 Debug.Log("Used Ability: " + chara?.ToString() + "/" + ability2.act?.ToString() + "/" + ability2.tg?.ToString() + "/" + tc);
1058 Debug.Log(ability2.act.CanPerform(chara, ability2.tg ?? tc));
1059 }
1060 return true;
1061 }
1062 }
1064 {
1065 if (tc.pos.HasBridge)
1066 {
1067 EClass._map.SetBridge(tc.pos.x, tc.pos.z, 0, 0, 0, 0, 0);
1068 }
1069 else
1070 {
1071 EClass._map.SetBridge(owner.pos.x, owner.pos.z, 0, 0, 0, 0, 0);
1072 }
1073 }
1075 {
1076 Debug.Log(owner.Name + "/" + abilities.Count);
1077 foreach (ItemAbility ability3 in abilities)
1078 {
1079 Debug.Log(ability3.act.Name + "/" + ability3.priority + "/" + ability3.act.CanPerform(owner, ability3.tg ?? tc));
1080 }
1081 }
1082 return false;
1083 void BuildCharaList()
1084 {
1085 if (charaBuilt)
1086 {
1087 return;
1088 }
1089 charas.Clear();
1090 charaBuilt = true;
1091 int sightRadius = owner.GetSightRadius();
1092 foreach (Chara chara2 in EClass._map.charas)
1093 {
1094 if (chara2 != owner)
1095 {
1096 int num11 = owner.Dist(chara2);
1097 if (num11 > sightRadius || !owner.CanSeeLos(chara2, num11))
1098 {
1099 continue;
1100 }
1101 }
1102 charas.Add(chara2);
1103 }
1104 }
1105 int ForeachChara(ItemAbility a, Func<Chara, int> func, bool isFriendlyAbility)
1106 {
1107 if (a.act.TargetType.Range == TargetRange.Self)
1108 {
1109 a.tg = owner;
1110 return func(owner);
1111 }
1112 BuildCharaList();
1113 int num5 = 0;
1114 foreach (Chara chara3 in charas)
1115 {
1116 int num6 = func(chara3);
1117 if (num6 > 0)
1118 {
1119 if (isFriendlyAbility)
1120 {
1121 if (owner.IsPCParty)
1122 {
1123 if (!chara3.IsPCParty)
1124 {
1125 continue;
1126 }
1127 }
1128 else if (!owner.IsFriendOrAbove(chara3))
1129 {
1130 continue;
1131 }
1132 if (chara3 != owner)
1133 {
1134 num6 += tactics.P_Party;
1135 }
1136 }
1137 else if (!owner.IsHostile(chara3))
1138 {
1139 continue;
1140 }
1141 if (num6 >= num5)
1142 {
1143 a.tg = chara3;
1144 num5 = num6;
1145 }
1146 }
1147 }
1148 return num5;
1149 }
1150 int GetAttackMod(Act a)
1151 {
1152 if (!owner.IsPCParty || a.source.aliasRef.IsEmpty())
1153 {
1154 return 0;
1155 }
1156 int num9 = ((a.source.aliasRef == "mold") ? owner.MainElement.id : EClass.sources.elements.alias[a.source.aliasRef].id);
1157 int num10 = -15 * tc.ResistLvFrom(num9);
1158 if (a is ActSword)
1159 {
1160 num10 = 0;
1161 }
1162 if (owner.HasElement(1238) && num10 < -15)
1163 {
1164 num10 = -15;
1165 }
1166 switch (num9)
1167 {
1168 case 910:
1169 if (tc.isWet)
1170 {
1171 num10 -= 30;
1172 }
1173 break;
1174 case 911:
1175 if (tc.HasCondition<ConBurning>())
1176 {
1177 num10 -= 30;
1178 }
1179 break;
1180 case 912:
1181 if (tc.isWet)
1182 {
1183 num10 += 30;
1184 }
1185 break;
1186 }
1187 return num10;
1188 }
1189 void GetNumEnemy(int radius)
1190 {
1191 if (numEnemy != -1)
1192 {
1193 return;
1194 }
1195 BuildCharaList();
1196 numEnemy = 0;
1197 foreach (Chara chara4 in charas)
1198 {
1199 if (chara4.host == null && owner.IsHostile(chara4) && owner.Dist(chara4) < radius && owner.CanSeeLos(chara4))
1200 {
1201 numEnemy++;
1202 }
1203 }
1204 }
1205 int GetNumNeutral(int radius)
1206 {
1207 if (numNeutral != -1)
1208 {
1209 return numNeutral;
1210 }
1211 BuildCharaList();
1212 numNeutral = 0;
1213 foreach (Chara chara5 in charas)
1214 {
1215 if (!chara5.IsPCFactionOrMinion && chara5.IsNeutralOrAbove() && owner.Dist(chara5) <= radius && owner.CanSeeLos(chara5))
1216 {
1217 numNeutral++;
1218 }
1219 }
1220 return numNeutral;
1221 }
1222 }
1223
1224 public virtual void BuildAbilityList()
1225 {
1226 abilities.Clear();
1227 foreach (ActList.Item item in owner.ability.list.items)
1228 {
1229 AddAbility(item.act, 0, item.chance, item.pt);
1230 }
1231 if (owner.mimicry != null && owner.mimicry.IsChara)
1232 {
1233 foreach (ActList.Item item2 in owner.mimicry.Card.Chara.ability.list.items)
1234 {
1235 AddAbility(item2.act, 0, item2.chance, item2.pt);
1236 }
1237 }
1242 {
1243 TryAddAbility(6410);
1244 }
1245 }
1246
1247 public virtual bool TryAbortCombat()
1248 {
1249 return false;
1250 }
1251}
BossType
Definition: BossType.cs:2
CTAG
Definition: CTAG.cs:2
ConditionType
Definition: ConditionType.cs:2
EditorTag
Definition: EditorTag.cs:2
Emo
Definition: Emo.cs:2
Hostility
Definition: Hostility.cs:2
MinionType
Definition: MinionType.cs:2
TargetRange
Definition: TargetRange.cs:2
Definition: ACT.cs:6
static ActRanged Ranged
Definition: ACT.cs:17
static ActThrow Throw
Definition: ACT.cs:19
static Act Create(int id)
Definition: ACT.cs:36
static ActMelee Melee
Definition: ACT.cs:15
static ActItem Item
Definition: ACT.cs:21
virtual Status Cancel()
Definition: AIAct.cs:305
virtual bool ShouldAllyAttack(Chara tg)
Definition: AIAct.cs:134
new Chara owner
Definition: AIAct.cs:14
Status
Definition: AIAct.cs:8
override string ToString()
Definition: AIAct.cs:124
Status DoGoto(Point pos, int dist=0, bool ignoreConnection=false, Func< Status > _onChildFail=null)
Definition: AIAct.cs:446
void SetTurbo(int mtp=-1)
Definition: AM_Adv.cs:1086
List< Item > items
Definition: ActList.cs:14
override bool Perform()
Definition: ActRanged.cs:65
static EffectIRenderer Throw(Card c, Point p, Thing t, ThrowMethod method=ThrowMethod.Default, float failChance=0f)
Definition: ActThrow.cs:97
override bool CanPerform()
Definition: ActThrow.cs:29
Definition: ACT.cs:62
CostType
Definition: ACT.cs:64
virtual TargetType TargetType
Definition: ACT.cs:144
virtual bool HaveLongPressAction
Definition: ACT.cs:135
virtual bool CanPerform()
Definition: ACT.cs:326
bool IsTargetHostileParty()
Definition: ACT.cs:241
static AM_Adv Adv
Definition: ActionMode.cs:15
virtual ConditionType Type
Definition: BaseStats.cs:33
Definition: Card.cs:11
bool IsPCFactionOrMinion
Definition: Card.cs:2342
void Teleport(Point point, bool silent=false, bool force=false)
Definition: Card.cs:6162
virtual Chara Chara
Definition: Card.cs:2122
Thing Split(int a)
Definition: Card.cs:3658
string id
Definition: Card.cs:36
int GetSightRadius()
Definition: Card.cs:6860
bool IsRestrainedResident
Definition: Card.cs:2328
bool isRestrained
Definition: Card.cs:569
SoundSource PlaySound(string id, float v=1f, bool spatial=true)
Definition: Card.cs:6606
void Talk(string idTopic, string ref1=null, string ref2=null, bool forceSync=false)
Definition: Card.cs:7166
int hp
Definition: Card.cs:245
string Name
Definition: Card.cs:2191
bool ExistsOnMap
Definition: Card.cs:2137
bool HasTag(CTAG tag)
Definition: Card.cs:2728
Point pos
Definition: Card.cs:60
int DEX
Definition: Card.cs:2405
MoveResult TryMoveFrom(Point p)
Definition: Card.cs:6213
Effect PlayEffect(string id, bool useRenderPos=true, float range=0f, Vector3 fix=default(Vector3))
Definition: Card.cs:6640
void ShowEmo(Emo _emo=Emo.none, float duration=0f, bool skipSame=true)
Definition: Card.cs:6574
Trait trait
Definition: Card.cs:54
bool IsPowerful
Definition: Card.cs:2146
MoveResult
Definition: Card.cs:13
bool HasEditorTag(EditorTag tag)
Definition: Card.cs:2733
BossType c_bossType
Definition: Card.cs:1261
int turn
Definition: Card.cs:68
int Evalue(int ele)
Definition: Card.cs:2704
int Dist(Card c)
Definition: Card.cs:8165
bool isHidden
Definition: Card.cs:533
void ModExp(string alias, int a)
Definition: Card.cs:2781
int GetInt(string id, int? defaultInt=null)
Definition: Card.cs:2567
bool HasElement(int ele, bool includeNagative=false)
Definition: Card.cs:6344
int LV
Definition: Card.cs:389
int ResistLvFrom(int ele)
Definition: Card.cs:6334
void Say(string lang, string ref1=null, string ref2=null)
Definition: Card.cs:7284
ActList list
Definition: CharaAbility.cs:13
bool Has(int id)
int GetMeleeDistance()
Definition: CharaBody.cs:466
Definition: Chara.cs:10
override bool IsAliveInCurrentZone
Definition: Chara.cs:567
Element MainElement
Definition: Chara.cs:735
new TraitChara trait
Definition: Chara.cs:509
Hostility OriginalHostility
Definition: Chara.cs:475
CharaBody body
Definition: Chara.cs:94
AIAct ai
Definition: Chara.cs:206
Element GetBuffStats(string alias)
Definition: Chara.cs:9946
bool isWet
Definition: Chara.cs:144
override bool IsPC
Definition: Chara.cs:630
Chara host
Definition: Chara.cs:33
bool IsPlant
Definition: Chara.cs:1022
Point GetFirstStep(Point newPoint, PathManager.MoveType moveType=PathManager.MoveType.Default)
Definition: Chara.cs:2789
Chara GetNearbyCatToSniff()
Definition: Chara.cs:8533
bool CanSeeLos(Card c, int dist=-1)
Definition: Chara.cs:1309
override bool IsPCParty
Definition: Chara.cs:633
override string ToString()
Definition: Chara.cs:1231
Party party
Definition: Chara.cs:43
bool CanDestroyPath()
Definition: Chara.cs:2628
bool IsInCombat
Definition: Chara.cs:911
List< Condition > conditions
Definition: Chara.cs:215
bool HasCondition(string alias)
Definition: Chara.cs:9934
bool IsNeutralOrAbove()
Definition: Chara.cs:6901
override bool IsMinion
Definition: Chara.cs:645
bool MoveRandom()
Definition: Chara.cs:2794
int CountDebuff()
Definition: Chara.cs:9963
override bool IsPCFaction
Definition: Chara.cs:689
int MaxSummon
Definition: Chara.cs:732
Thing TryGetThrowable()
Definition: Chara.cs:8169
int calmCheckTurn
Definition: Chara.cs:118
void MakeMinion(Chara _master, MinionType type=MinionType.Default)
Definition: Chara.cs:2541
bool CanSee(Card c)
Definition: Chara.cs:1277
override bool IsPCFactionMinion
Definition: Chara.cs:673
bool IsFriendOrAbove()
Definition: Chara.cs:6945
override int MaxHP
Definition: Chara.cs:726
Thing ranged
Definition: Chara.cs:98
SourceChara.Row source
Definition: Chara.cs:162
Stats mana
Definition: Chara.cs:1213
bool FindNewEnemy()
Definition: Chara.cs:6761
Stats stamina
Definition: Chara.cs:1205
bool UseAbility(int idAct, Card tc=null, Point pos=null, bool pt=false)
Definition: Chara.cs:6081
void GoHostile(Card _tg)
Definition: Chara.cs:6644
Chara parasite
Definition: Chara.cs:30
Chara ride
Definition: Chara.cs:27
bool CanBeTempAlly(Chara c)
Definition: Chara.cs:2519
bool CanInteractTo(Card c)
Definition: Chara.cs:2735
MoveResult TryMoveTowards(Point p)
Definition: Chara.cs:2834
bool isBerserk
Definition: Chara.cs:124
bool FindNearestNewEnemy()
Definition: Chara.cs:6834
Chara enemy
Definition: Chara.cs:86
CharaAbility ability
Definition: Chara.cs:428
Chara SetEnemy(Chara c=null)
Definition: Chara.cs:6619
bool isBlind
Definition: Chara.cs:132
bool IsMachine
Definition: Chara.cs:950
Tactics tactics
Definition: Chara.cs:857
bool IsHostile()
Definition: Chara.cs:6849
bool isDead
Definition: Chara.cs:393
bool isConfused
Definition: Chara.cs:128
ConBaseTransmuteMimic mimicry
Definition: Chara.cs:106
bool TryEquipRanged()
Definition: Chara.cs:8250
void TrySetEnemy(Chara c)
Definition: Chara.cs:6636
SourceRace.Row race
Definition: Chara.cs:468
Definition: ConDim.cs:2
Definition: ConHOT.cs:4
Definition: ConWet.cs:2
bool logCombat
Definition: CoreDebug.cs:260
static CursorInfo IconMelee
int GetRaw(int offsetHours=0)
Definition: Date.cs:328
Definition: EClass.cs:6
static Game game
Definition: EClass.cs:9
static Zone _zone
Definition: EClass.cs:21
static World world
Definition: EClass.cs:41
static Map _map
Definition: EClass.cs:19
static int rnd(long a)
Definition: EClass.cs:59
static SourceManager sources
Definition: EClass.cs:43
static Player player
Definition: EClass.cs:13
static Chara pc
Definition: EClass.cs:15
static CoreDebug debug
Definition: EClass.cs:49
int id
Definition: ELEMENT.cs:259
SourceElement.Row source
Definition: ELEMENT.cs:282
int vPotential
Definition: ELEMENT.cs:265
bool HasTag(string tag)
Definition: ELEMENT.cs:482
int Value
Definition: ELEMENT.cs:301
virtual string Name
Definition: ELEMENT.cs:313
static Element Create(int id, int v=0)
Definition: ELEMENT.cs:1123
virtual Act.Cost GetCost(Chara c)
Definition: ELEMENT.cs:1053
Act act
Definition: ELEMENT.cs:403
ConfigTactics tactics
Definition: Game.cs:91
ConfigAutoCombat autoCombat
Definition: Game.cs:94
Config config
Definition: Game.cs:219
virtual bool TryUseRanged(int dist)
Definition: GoalCombat.cs:482
override IEnumerable< Status > Run()
Definition: GoalCombat.cs:55
virtual bool TryThrow(int dist)
Definition: GoalCombat.cs:491
virtual void BuildAbilityList()
Definition: GoalCombat.cs:1224
Chara tc
Definition: GoalCombat.cs:28
void TryRemoveAbility(int ele)
Definition: GoalCombat.cs:465
Tactics tactics
Definition: GoalCombat.cs:44
int idleCount
Definition: GoalCombat.cs:30
virtual bool TryAbortCombat()
Definition: GoalCombat.cs:1247
override bool CancelOnAggro
Definition: GoalCombat.cs:42
bool TryMove(int dist)
Definition: GoalCombat.cs:380
Chara destEnemy
Definition: GoalCombat.cs:26
List< ItemAbility > abilities
Definition: GoalCombat.cs:34
List< Chara > charas
Definition: GoalCombat.cs:36
virtual bool TryUseAbility(int dist, bool beforeMove=false)
Definition: GoalCombat.cs:510
override CursorInfo CursorIcon
Definition: GoalCombat.cs:38
override bool CancelWhenDamaged
Definition: GoalCombat.cs:40
int moveFail
Definition: GoalCombat.cs:32
void TryAddAbility(int ele)
Definition: GoalCombat.cs:448
override bool CanManualCancel()
Definition: GoalCombat.cs:46
void AddAbility(Act a, int mod=0, int chance=100, bool aiPt=false)
Definition: GoalCombat.cs:437
Definition: Goal.cs:4
Point GetRandomSurface(int x, int z, int radius, bool walkable=true, bool allowWater=false)
Definition: MapBounds.cs:182
void SetBridge(int x, int z, int height=0, int idMat=0, int idBridge=0, int dir=0, byte idPillar=0)
Definition: Map.cs:994
Playlist plDay
Definition: Map.cs:77
List< Chara > charas
Definition: Map.cs:81
Definition: Msg.cs:5
static string Say(string idLang, string ref1, string ref2=null, string ref3=null, string ref4=null)
Definition: Msg.cs:58
List< Chara > members
Definition: Party.cs:19
bool IsCriminal
Definition: Player.cs:1409
int lastEmptyAlly
Definition: Player.cs:1263
Definition: Point.cs:9
bool HasBridge
Definition: Point.cs:221
bool IsBlocked
Definition: Point.cs:363
int x
Definition: Point.cs:36
Point GetNearestPoint(bool allowBlock=false, bool allowChara=true, bool allowInstalled=true, bool ignoreCenter=false, int minRadius=0)
Definition: Point.cs:624
int z
Definition: Point.cs:39
bool IsValid
Definition: Point.cs:88
int Distance(Point p)
Definition: Point.cs:995
bool IsInBounds
Definition: Point.cs:104
bool HasChara
Definition: Point.cs:238
string[] abilityType
SourceElement elements
bool isAlarmSet
Definition: Spatial.cs:430
bool isPeace
Definition: Spatial.cs:406
Definition: SPELL.cs:632
virtual int value
Definition: Stats.cs:56
virtual int max
Definition: Stats.cs:68
int ChanceSecondMove
Definition: Tactics.cs:56
int RandomFacotr
Definition: Tactics.cs:12
int P_Party
Definition: Tactics.cs:71
int P_Spell
Definition: Tactics.cs:79
bool CastPartyBuff
Definition: Tactics.cs:88
int P_Debuff
Definition: Tactics.cs:83
int P_Buff
Definition: Tactics.cs:81
int P_Melee
Definition: Tactics.cs:73
int DestDist
Definition: Tactics.cs:24
int RangedChance
Definition: Tactics.cs:116
SourceTactics.Row source
Definition: Tactics.cs:3
int AbilityChance
Definition: Tactics.cs:100
int P_Range
Definition: Tactics.cs:75
int P_Summon
Definition: Tactics.cs:85
virtual TargetRange Range
Definition: TargetType.cs:25
virtual bool ForceParty
Definition: TargetType.cs:41
Definition: Thing.cs:8
GameDate date
Definition: World.cs:6
int CountMinions(Chara c)
Definition: Zone.cs:3915
virtual bool SetAlarmOnBreakLaw
Definition: Zone.cs:235
bool HasField(int idEle)
Definition: Zone.cs:3069
void SetBGM(List< int > ids, bool refresh=true, float fadeDuration=0f)
Definition: Zone.cs:3154
virtual bool IsTown
Definition: Zone.cs:227
bool IsPCFaction
Definition: Zone.cs:477
virtual void SetAlarm(bool enable)
Definition: Zone.cs:3770
Definition: ACT.cs:71
CostType type
Definition: ACT.cs:74
int cost
Definition: ACT.cs:72