Elin Decompiled Documentation EA 23.310 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.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 flag10 = owner.HasCondition<StanceTaunt>();
573 bool flag11 = tactics.source.taunt != -1 && 100 * owner.hp / owner.MaxHP >= tactics.source.taunt;
574 num = ((flag10 && !flag11) ? 100 : ((!flag10 && flag11) ? 100 : 0));
575 break;
576 }
577 case "song":
578 {
579 bool flag7 = owner.HasCondition<BaseSong>();
580 bool flag8 = owner.mana.value > owner.mana.max / 3;
581 num = ((flag7 && !flag8) ? 100 : ((!flag7 && flag8) ? 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 flag6 = act is ActBolt;
681 {
682 continue;
683 }
684 GetNumEnemy(flag6 ? 6 : 5);
685 if (numEnemy == 0 || (owner.IsPCFactionOrMinion && GetNumNeutral(flag6 ? 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 6606:
819 if (owner.mana.value <= 0)
820 {
821 continue;
822 }
823 break;
824 case 6603:
825 if (!tc.IsPCParty || tc.Evalue(418) < 0)
826 {
827 break;
828 }
829 foreach (Chara member in EClass.pc.party.members)
830 {
831 if (member.Evalue(418) < 0)
832 {
833 owner.enemy = (tc = member);
834 return false;
835 }
836 }
837 break;
838 case 6602:
839 if (dist <= 1 || tc.HasCondition<ConEntangle>())
840 {
841 continue;
842 }
843 break;
844 case 6450:
845 if (isPCFaction && (tc.HasElement(1221) || tc.HasElement(1223) || tc.id == "hedgehog_ether"))
846 {
847 continue;
848 }
849 break;
850 case 8200:
851 case 8201:
852 if (owner.HasElement(400))
853 {
854 continue;
855 }
856 break;
857 case 6400:
858 if (isPCFaction)
859 {
860 continue;
861 }
862 break;
863 case 8790:
864 case 8791:
865 if (tc.host != null)
866 {
867 continue;
868 }
869 break;
870 case 6900:
871 if (owner.IsPC)
872 {
873 continue;
874 }
875 if (owner.IsPCParty)
876 {
877 foreach (Chara member2 in EClass.pc.party.members)
878 {
879 float num4 = 100f - (float)(member2.mana.value * 100) / MathF.Max(1f, member2.mana.max);
880 if (num4 > (float)num)
881 {
882 num = (int)num4;
883 }
884 }
885 }
886 else
887 {
888 num = 100 - owner.mana.value * 100 / Mathf.Max(1, owner.mana.max);
889 }
890 break;
891 case 6627:
893 {
894 continue;
895 }
896 num = 100 - owner.hp * 100 / Mathf.Max(1, owner.MaxHP);
897 break;
898 case 9200:
899 {
900 int num3 = 0;
901 foreach (Condition condition in tc.conditions)
902 {
903 if (condition.Type == ConditionType.Debuff)
904 {
905 num3++;
906 }
907 }
908 num = num3 * 15;
909 break;
910 }
911 }
912 if (s.target == "Neighbor")
913 {
914 if (dist > 1)
915 {
916 continue;
917 }
918 num += 10;
919 }
920 if (s.proc.Length != 0 && s.proc[0] == "Debuff" && tc.HasCondition(s.proc[1]))
921 {
922 continue;
923 }
924 if (s.abilityType.Length > 1)
925 {
926 num += (owner.IsPC ? s.abilityType[2] : s.abilityType[1]).ToInt();
927 }
928 if (act is Spell)
929 {
930 if (owner.IsPC)
931 {
932 if (act.vPotential <= 0 && !owner.ability.Has(act.id))
933 {
934 continue;
935 }
936 if (flag2 || isConfused || flag4)
937 {
938 num -= 50;
939 }
940 }
941 else
942 {
943 if (flag2)
944 {
945 num -= 30;
946 }
947 if (isConfused || flag4)
948 {
949 num -= 10;
950 }
951 }
952 }
953 if (num > 0)
954 {
955 num += ability.priorityMod + EClass.rnd(tactics.RandomFacotr + ability.priorityMod);
956 }
957 ability.priority = num;
958 int HealFactor(Chara c)
959 {
960 if (isHOT && c.HasCondition(s.proc[1]))
961 {
962 return 0;
963 }
964 float num5 = (float)c.hp / (float)c.MaxHP;
965 if (num5 > (isHOT ? 0.85f : 0.75f))
966 {
967 return 0;
968 }
969 int num6 = tactics.P_Heal - (int)((float)tactics.P_Heal * num5) + (isHOT ? 50 : 25);
970 foreach (Condition condition2 in c.conditions)
971 {
972 if (condition2 is ConFear)
973 {
974 num6 += 10;
975 }
976 else if (condition2 is ConPoison)
977 {
978 num6 += 2;
979 }
980 else if (condition2 is ConConfuse)
981 {
982 num6 += 4;
983 }
984 else if (condition2 is ConDim)
985 {
986 num6 += 6;
987 }
988 else if (condition2 is ConBleed)
989 {
990 num6 += 8;
991 }
992 }
993 return num6;
994 }
995 }
996 abilities.Sort((ItemAbility a, ItemAbility b) => b.priority - a.priority);
997 foreach (ItemAbility ability2 in abilities)
998 {
999 if (ability2.priority <= 0)
1000 {
1001 continue;
1002 }
1004 {
1005 Debug.Log(ability2.act.Name + "/" + ability2.priority + "/" + ability2.act.CanPerform(owner, ability2.tg ?? tc));
1006 }
1007 if (ability2.act.source.alias == "ActRanged")
1008 {
1009 if (TryThrow(dist))
1010 {
1011 return true;
1012 }
1013 if (TryUseRanged(dist))
1014 {
1015 return true;
1016 }
1017 continue;
1018 }
1019 Cost cost = ability2.act.GetCost(owner);
1020 if (owner.IsPCParty && ability2.pt && !ability2.act.IsTargetHostileParty() && !ability2.act.TargetType.ForceParty && cost.cost * EClass.pc.party.members.Count > owner.mana.value)
1021 {
1022 continue;
1023 }
1024 if (isPCFaction && cost.cost > 0)
1025 {
1026 switch (cost.type)
1027 {
1028 case CostType.MP:
1029 if (cost.cost > owner.mana.value)
1030 {
1031 continue;
1032 }
1033 break;
1034 case CostType.SP:
1035 if (cost.cost > owner.stamina.value)
1036 {
1037 continue;
1038 }
1039 break;
1040 }
1041 }
1042 if (cost.cost > 0 && EClass.rnd(100) > tactics.AbilityChance)
1043 {
1044 continue;
1045 }
1046 Chara chara = owner;
1047 if (ability2.act.CanPerform(owner, ability2.tg ?? tc) && owner.UseAbility(ability2.act, ability2.tg ?? tc, null, (ability2.act.HaveLongPressAction && ability2.pt) || ability2.aiPt))
1048 {
1050 {
1051 Debug.Log("Used Ability: " + chara?.ToString() + "/" + ability2.act?.ToString() + "/" + ability2.tg?.ToString() + "/" + tc);
1052 Debug.Log(ability2.act.CanPerform(chara, ability2.tg ?? tc));
1053 }
1054 return true;
1055 }
1056 }
1058 {
1059 Debug.Log(owner.Name + "/" + abilities.Count);
1060 foreach (ItemAbility ability3 in abilities)
1061 {
1062 Debug.Log(ability3.act.Name + "/" + ability3.priority + "/" + ability3.act.CanPerform(owner, ability3.tg ?? tc));
1063 }
1064 }
1065 return false;
1066 void BuildCharaList()
1067 {
1068 if (charaBuilt)
1069 {
1070 return;
1071 }
1072 charas.Clear();
1073 charaBuilt = true;
1074 int sightRadius = owner.GetSightRadius();
1075 foreach (Chara chara2 in EClass._map.charas)
1076 {
1077 if (chara2 != owner)
1078 {
1079 int num11 = owner.Dist(chara2);
1080 if (num11 > sightRadius || !owner.CanSeeLos(chara2, num11))
1081 {
1082 continue;
1083 }
1084 }
1085 charas.Add(chara2);
1086 }
1087 }
1088 int ForeachChara(ItemAbility a, Func<Chara, int> func, bool isFriendlyAbility)
1089 {
1090 if (a.act.TargetType.Range == TargetRange.Self)
1091 {
1092 a.tg = owner;
1093 return func(owner);
1094 }
1095 BuildCharaList();
1096 int num7 = 0;
1097 foreach (Chara chara3 in charas)
1098 {
1099 int num8 = func(chara3);
1100 if (num8 > 0)
1101 {
1102 if (isFriendlyAbility)
1103 {
1104 if (owner.IsPCParty)
1105 {
1106 if (!chara3.IsPCParty)
1107 {
1108 continue;
1109 }
1110 }
1111 else if (!owner.IsFriendOrAbove(chara3))
1112 {
1113 continue;
1114 }
1115 if (chara3 != owner)
1116 {
1117 num8 += tactics.P_Party;
1118 }
1119 }
1120 else if (!owner.IsHostile(chara3))
1121 {
1122 continue;
1123 }
1124 if (num8 >= num7)
1125 {
1126 a.tg = chara3;
1127 num7 = num8;
1128 }
1129 }
1130 }
1131 return num7;
1132 }
1133 int GetAttackMod(Act a)
1134 {
1135 if (!owner.IsPCParty || a.source.aliasRef.IsEmpty())
1136 {
1137 return 0;
1138 }
1139 int num9 = ((a.source.aliasRef == "mold") ? owner.MainElement.id : EClass.sources.elements.alias[a.source.aliasRef].id);
1140 int num10 = -15 * tc.ResistLvFrom(num9);
1141 if (a is ActSword)
1142 {
1143 num10 = 0;
1144 }
1145 if (owner.HasElement(1238) && num10 < -15)
1146 {
1147 num10 = -15;
1148 }
1149 switch (num9)
1150 {
1151 case 910:
1152 if (tc.isWet)
1153 {
1154 num10 -= 30;
1155 }
1156 break;
1157 case 911:
1158 if (tc.HasCondition<ConBurning>())
1159 {
1160 num10 -= 30;
1161 }
1162 break;
1163 case 912:
1164 if (tc.isWet)
1165 {
1166 num10 += 30;
1167 }
1168 break;
1169 }
1170 return num10;
1171 }
1172 void GetNumEnemy(int radius)
1173 {
1174 if (numEnemy != -1)
1175 {
1176 return;
1177 }
1178 BuildCharaList();
1179 numEnemy = 0;
1180 foreach (Chara chara4 in charas)
1181 {
1182 if (chara4.host == null && owner.IsHostile(chara4) && owner.Dist(chara4) < radius && owner.CanSeeLos(chara4))
1183 {
1184 numEnemy++;
1185 }
1186 }
1187 }
1188 int GetNumNeutral(int radius)
1189 {
1190 if (numNeutral != -1)
1191 {
1192 return numNeutral;
1193 }
1194 BuildCharaList();
1195 numNeutral = 0;
1196 foreach (Chara chara5 in charas)
1197 {
1198 if (!chara5.IsPCFactionOrMinion && chara5.IsNeutralOrAbove() && owner.Dist(chara5) <= radius && owner.CanSeeLos(chara5))
1199 {
1200 numNeutral++;
1201 }
1202 }
1203 return numNeutral;
1204 }
1205 }
1206
1207 public virtual void BuildAbilityList()
1208 {
1209 abilities.Clear();
1210 foreach (ActList.Item item in owner.ability.list.items)
1211 {
1212 AddAbility(item.act, 0, item.chance, item.pt);
1213 }
1214 if (owner.mimicry != null && owner.mimicry.IsChara)
1215 {
1216 foreach (ActList.Item item2 in owner.mimicry.Card.Chara.ability.list.items)
1217 {
1218 AddAbility(item2.act, 0, item2.chance, item2.pt);
1219 }
1220 }
1225 {
1226 TryAddAbility(6410);
1227 }
1228 }
1229
1230 public virtual bool TryAbortCombat()
1231 {
1232 return false;
1233 }
1234}
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:321
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
virtual ConditionType Type
Definition: BaseStats.cs:19
Definition: Card.cs:11
bool IsPCFactionOrMinion
Definition: Card.cs:2326
void Teleport(Point point, bool silent=false, bool force=false)
Definition: Card.cs:6041
virtual Chara Chara
Definition: Card.cs:2122
Thing Split(int a)
Definition: Card.cs:3580
string id
Definition: Card.cs:36
int GetSightRadius()
Definition: Card.cs:6735
bool IsRestrainedResident
Definition: Card.cs:2312
bool isRestrained
Definition: Card.cs:569
SoundSource PlaySound(string id, float v=1f, bool spatial=true)
Definition: Card.cs:6481
void Talk(string idTopic, string ref1=null, string ref2=null, bool forceSync=false)
Definition: Card.cs:7041
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:2649
Point pos
Definition: Card.cs:60
int DEX
Definition: Card.cs:2389
MoveResult TryMoveFrom(Point p)
Definition: Card.cs:6092
Effect PlayEffect(string id, bool useRenderPos=true, float range=0f, Vector3 fix=default(Vector3))
Definition: Card.cs:6515
void ShowEmo(Emo _emo=Emo.none, float duration=0f, bool skipSame=true)
Definition: Card.cs:6449
Trait trait
Definition: Card.cs:54
bool IsPowerful
Definition: Card.cs:2146
MoveResult
Definition: Card.cs:13
bool HasEditorTag(EditorTag tag)
Definition: Card.cs:2654
BossType c_bossType
Definition: Card.cs:1261
int turn
Definition: Card.cs:68
int Evalue(int ele)
Definition: Card.cs:2625
int Dist(Card c)
Definition: Card.cs:8034
bool isHidden
Definition: Card.cs:533
void ModExp(string alias, int a)
Definition: Card.cs:2702
bool HasElement(int ele, bool includeNagative=false)
Definition: Card.cs:6223
int LV
Definition: Card.cs:389
int ResistLvFrom(int ele)
Definition: Card.cs:6213
void Say(string lang, string ref1=null, string ref2=null)
Definition: Card.cs:7159
ActList list
Definition: CharaAbility.cs:12
bool Has(int id)
int GetMeleeDistance()
Definition: CharaBody.cs:466
Definition: Chara.cs:10
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:9721
bool isWet
Definition: Chara.cs:144
override bool IsPC
Definition: Chara.cs:630
Chara host
Definition: Chara.cs:33
bool IsPlant
Definition: Chara.cs:998
Point GetFirstStep(Point newPoint, PathManager.MoveType moveType=PathManager.MoveType.Default)
Definition: Chara.cs:2668
Chara GetNearbyCatToSniff()
Definition: Chara.cs:8336
bool CanSeeLos(Card c, int dist=-1)
Definition: Chara.cs:1285
override bool IsPCParty
Definition: Chara.cs:633
override string ToString()
Definition: Chara.cs:1207
Party party
Definition: Chara.cs:43
bool IsInCombat
Definition: Chara.cs:887
List< Condition > conditions
Definition: Chara.cs:215
bool HasCondition(string alias)
Definition: Chara.cs:9709
bool IsNeutralOrAbove()
Definition: Chara.cs:6764
override bool IsMinion
Definition: Chara.cs:645
bool MoveRandom()
Definition: Chara.cs:2673
int CountDebuff()
Definition: Chara.cs:9738
override bool IsPCFaction
Definition: Chara.cs:689
int MaxSummon
Definition: Chara.cs:732
Thing TryGetThrowable()
Definition: Chara.cs:8007
int calmCheckTurn
Definition: Chara.cs:118
void MakeMinion(Chara _master, MinionType type=MinionType.Default)
Definition: Chara.cs:2420
bool CanSee(Card c)
Definition: Chara.cs:1253
override bool IsPCFactionMinion
Definition: Chara.cs:673
bool IsFriendOrAbove()
Definition: Chara.cs:6808
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:1189
bool FindNewEnemy()
Definition: Chara.cs:6624
Stats stamina
Definition: Chara.cs:1181
bool UseAbility(int idAct, Card tc=null, Point pos=null, bool pt=false)
Definition: Chara.cs:5944
void GoHostile(Card _tg)
Definition: Chara.cs:6507
Chara parasite
Definition: Chara.cs:30
Chara ride
Definition: Chara.cs:27
bool CanBeTempAlly(Chara c)
Definition: Chara.cs:2398
MoveResult TryMoveTowards(Point p)
Definition: Chara.cs:2713
bool isBerserk
Definition: Chara.cs:124
bool FindNearestNewEnemy()
Definition: Chara.cs:6697
Chara enemy
Definition: Chara.cs:86
CharaAbility ability
Definition: Chara.cs:428
Chara SetEnemy(Chara c=null)
Definition: Chara.cs:6482
bool isBlind
Definition: Chara.cs:132
bool IsMachine
Definition: Chara.cs:926
Tactics tactics
Definition: Chara.cs:857
bool IsHostile()
Definition: Chara.cs:6712
bool isDead
Definition: Chara.cs:393
bool isConfused
Definition: Chara.cs:128
ConBaseTransmuteMimic mimicry
Definition: Chara.cs:106
bool TryEquipRanged()
Definition: Chara.cs:8083
void TrySetEnemy(Chara c)
Definition: Chara.cs:6499
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: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:1119
virtual Act.Cost GetCost(Chara c)
Definition: ELEMENT.cs:1049
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:482
override IEnumerable< Status > Run()
Definition: GoalCombat.cs:55
virtual bool TryThrow(int dist)
Definition: GoalCombat.cs:491
virtual void BuildAbilityList()
Definition: GoalCombat.cs:1207
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:1230
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
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
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:990
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:630
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:3801
virtual bool SetAlarmOnBreakLaw
Definition: Zone.cs:233
bool HasField(int idEle)
Definition: Zone.cs:2965
void SetBGM(List< int > ids, bool refresh=true, float fadeDuration=0f)
Definition: Zone.cs:3045
virtual bool IsTown
Definition: Zone.cs:225
bool IsPCFaction
Definition: Zone.cs:475
virtual void SetAlarm(bool enable)
Definition: Zone.cs:3656
Definition: ACT.cs:71
CostType type
Definition: ACT.cs:74
int cost
Definition: ACT.cs:72