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