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