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