1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 2010-2019 EDuke32 developers and contributors
4 Copyright (C) 2019 Nuke.YKT
5 
6 This file is part of NBlood.
7 
8 NBlood is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License version 2
10 as published by the Free Software Foundation.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 
16 See the GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 */
22 //-------------------------------------------------------------------------
23 #include "compat.h"
24 #include "build.h"
25 #include "pragmas.h"
26 #include "mmulti.h"
27 #include "common_game.h"
28 
29 #include "actor.h"
30 #include "ai.h"
31 #include "aiburn.h"
32 #include "blood.h"
33 #include "db.h"
34 #include "dude.h"
35 #include "levels.h"
36 #include "player.h"
37 #include "seq.h"
38 #include "sfx.h"
39 #include "trig.h"
40 #ifdef NOONE_EXTENSIONS
41 #include "nnexts.h"
42 #endif
43 
44 static void BurnSeqCallback(int, int);
45 static void thinkSearch(spritetype*, XSPRITE*);
46 static void thinkGoto(spritetype*, XSPRITE*);
47 static void thinkChase(spritetype*, XSPRITE*);
48 
49 static int nBurnClient = seqRegisterClient(BurnSeqCallback);
50 
51 AISTATE cultistBurnIdle = { kAiStateIdle, 3, -1, 0, NULL, NULL, aiThinkTarget, NULL };
52 AISTATE cultistBurnChase = { kAiStateChase, 3, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
53 AISTATE cultistBurnGoto = { kAiStateMove, 3, -1, 3600, NULL, aiMoveForward, thinkGoto, &cultistBurnSearch };
54 AISTATE cultistBurnSearch = { kAiStateSearch, 3, -1, 3600, NULL, aiMoveForward, thinkSearch, &cultistBurnSearch };
55 AISTATE cultistBurnAttack = { kAiStateChase, 3, nBurnClient, 120, NULL, NULL, NULL, &cultistBurnChase };
56 
57 AISTATE zombieABurnChase = { kAiStateChase, 3, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
58 AISTATE zombieABurnGoto = { kAiStateMove, 3, -1, 3600, NULL, aiMoveForward, thinkGoto, &zombieABurnSearch };
59 AISTATE zombieABurnSearch = { kAiStateSearch, 3, -1, 3600, NULL, aiMoveForward, thinkSearch, NULL };
60 AISTATE zombieABurnAttack = { kAiStateChase, 3, nBurnClient, 120, NULL, NULL, NULL, &zombieABurnChase };
61 
62 AISTATE zombieFBurnChase = { kAiStateChase, 3, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
63 AISTATE zombieFBurnGoto = { kAiStateMove, 3, -1, 3600, NULL, aiMoveForward, thinkGoto, &zombieFBurnSearch };
64 AISTATE zombieFBurnSearch = { kAiStateSearch, 3, -1, 3600, NULL, aiMoveForward, thinkSearch, NULL };
65 AISTATE zombieFBurnAttack = { kAiStateChase, 3, nBurnClient, 120, NULL, NULL, NULL, &zombieFBurnChase };
66 
67 AISTATE innocentBurnChase = { kAiStateChase, 3, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
68 AISTATE innocentBurnGoto = { kAiStateMove, 3, -1, 3600, NULL, aiMoveForward, thinkGoto, &zombieFBurnSearch };
69 AISTATE innocentBurnSearch = { kAiStateSearch, 3, -1, 3600, NULL, aiMoveForward, thinkSearch, NULL };
70 AISTATE innocentBurnAttack = { kAiStateChase, 3, nBurnClient, 120, NULL, NULL, NULL, &zombieFBurnChase };
71 
72 AISTATE beastBurnChase = { kAiStateChase, 3, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
73 AISTATE beastBurnGoto = { kAiStateMove, 3, -1, 3600, NULL, aiMoveForward, thinkGoto, &beastBurnSearch };
74 AISTATE beastBurnSearch = { kAiStateSearch, 3, -1, 3600, NULL, aiMoveForward, thinkSearch, &beastBurnSearch };
75 AISTATE beastBurnAttack = { kAiStateChase, 3, nBurnClient, 120, NULL, NULL, NULL, &beastBurnChase };
76 
77 AISTATE tinycalebBurnChase = { kAiStateChase, 3, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
78 AISTATE tinycalebBurnGoto = { kAiStateMove, 3, -1, 3600, NULL, aiMoveForward, thinkGoto, &tinycalebBurnSearch };
79 AISTATE tinycalebBurnSearch = { kAiStateSearch, 3, -1, 3600, NULL, aiMoveForward, thinkSearch, &tinycalebBurnSearch };
80 AISTATE tinycalebBurnAttack = { kAiStateChase, 3, nBurnClient, 120, NULL, NULL, NULL, &tinycalebBurnChase };
81 
82 AISTATE genDudeBurnIdle = { kAiStateIdle, 3, -1, 0, NULL, NULL, aiThinkTarget, NULL };
83 AISTATE genDudeBurnChase = { kAiStateChase, 3, -1, 0, NULL, aiMoveForward, thinkChase, NULL };
84 AISTATE genDudeBurnGoto = { kAiStateMove, 3, -1, 3600, NULL, aiMoveForward, thinkGoto, &genDudeBurnSearch };
85 AISTATE genDudeBurnSearch = { kAiStateSearch, 3, -1, 3600, NULL, aiMoveForward, thinkSearch, &genDudeBurnSearch };
86 AISTATE genDudeBurnAttack = { kAiStateChase, 3, nBurnClient, 120, NULL, NULL, NULL, &genDudeBurnChase };
87 
BurnSeqCallback(int,int)88 static void BurnSeqCallback(int, int)
89 {
90 }
91 
thinkSearch(spritetype * pSprite,XSPRITE * pXSprite)92 static void thinkSearch(spritetype *pSprite, XSPRITE *pXSprite)
93 {
94     aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng);
95     aiThinkTarget(pSprite, pXSprite);
96 }
97 
thinkGoto(spritetype * pSprite,XSPRITE * pXSprite)98 static void thinkGoto(spritetype *pSprite, XSPRITE *pXSprite)
99 {
100     dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
101     DUDEINFO *pDudeInfo = getDudeInfo(pSprite->type);
102     int dx = pXSprite->targetX-pSprite->x;
103     int dy = pXSprite->targetY-pSprite->y;
104     int nAngle = getangle(dx, dy);
105     int nDist = approxDist(dx, dy);
106     aiChooseDirection(pSprite, pXSprite, nAngle);
107     if (nDist < 512 && klabs(pSprite->ang - nAngle) < pDudeInfo->periphery)
108     {
109         switch (pSprite->type)
110         {
111         case kDudeBurningCultist:
112             aiNewState(pSprite, pXSprite, &cultistBurnSearch);
113             break;
114         case kDudeBurningZombieAxe:
115             aiNewState(pSprite, pXSprite, &zombieABurnSearch);
116             break;
117         case kDudeBurningZombieButcher:
118             aiNewState(pSprite, pXSprite, &zombieFBurnSearch);
119             break;
120         case kDudeBurningInnocent:
121             aiNewState(pSprite, pXSprite, &innocentBurnSearch);
122             break;
123         case kDudeBurningBeast:
124             aiNewState(pSprite, pXSprite, &beastBurnSearch);
125             break;
126         case kDudeBurningTinyCaleb:
127             aiNewState(pSprite, pXSprite, &tinycalebBurnSearch);
128             break;
129         #ifdef NOONE_EXTENSIONS
130         case kDudeModernCustomBurning:
131             aiNewState(pSprite, pXSprite, &genDudeBurnSearch);
132             break;
133         #endif
134         }
135     }
136     aiThinkTarget(pSprite, pXSprite);
137 }
138 
thinkChase(spritetype * pSprite,XSPRITE * pXSprite)139 static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite)
140 {
141     if (pXSprite->target == -1)
142     {
143         switch (pSprite->type)
144         {
145         case kDudeBurningCultist:
146             aiNewState(pSprite, pXSprite, &cultistBurnGoto);
147             break;
148         case kDudeBurningZombieAxe:
149             aiNewState(pSprite, pXSprite, &zombieABurnGoto);
150             break;
151         case kDudeBurningZombieButcher:
152             aiNewState(pSprite, pXSprite, &zombieFBurnGoto);
153             break;
154         case kDudeBurningInnocent:
155             aiNewState(pSprite, pXSprite, &innocentBurnGoto);
156             break;
157         case kDudeBurningBeast:
158             aiNewState(pSprite, pXSprite, &beastBurnGoto);
159             break;
160         case kDudeBurningTinyCaleb:
161             aiNewState(pSprite, pXSprite, &tinycalebBurnGoto);
162             break;
163         #ifdef NOONE_EXTENSIONS
164         case kDudeModernCustomBurning:
165             aiNewState(pSprite, pXSprite, &genDudeBurnGoto);
166             break;
167         #endif
168         }
169         return;
170     }
171     dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax);
172     DUDEINFO *pDudeInfo = getDudeInfo(pSprite->type);
173     dassert(pXSprite->target >= 0 && pXSprite->target < kMaxSprites);
174     spritetype *pTarget = &sprite[pXSprite->target];
175     XSPRITE *pXTarget = &xsprite[pTarget->extra];
176     int dx = pTarget->x-pSprite->x;
177     int dy = pTarget->y-pSprite->y;
178     aiChooseDirection(pSprite, pXSprite, getangle(dx, dy));
179     if (pXTarget->health == 0)
180     {
181         switch (pSprite->type)
182         {
183         case kDudeBurningCultist:
184             aiNewState(pSprite, pXSprite, &cultistBurnSearch);
185             break;
186         case kDudeBurningZombieAxe:
187             aiNewState(pSprite, pXSprite, &zombieABurnSearch);
188             break;
189         case kDudeBurningZombieButcher:
190             aiNewState(pSprite, pXSprite, &zombieFBurnSearch);
191             break;
192         case kDudeBurningInnocent:
193             aiNewState(pSprite, pXSprite, &innocentBurnSearch);
194             break;
195         case kDudeBurningBeast:
196             aiNewState(pSprite, pXSprite, &beastBurnSearch);
197             break;
198         case kDudeBurningTinyCaleb:
199             aiNewState(pSprite, pXSprite, &tinycalebBurnSearch);
200             break;
201         #ifdef NOONE_EXTENSIONS
202         case kDudeModernCustomBurning:
203             aiNewState(pSprite, pXSprite, &genDudeBurnSearch);
204             break;
205         #endif
206         }
207         return;
208     }
209     int nDist = approxDist(dx, dy);
210     if (nDist <= pDudeInfo->seeDist)
211     {
212         int nDeltaAngle = ((getangle(dx,dy)+1024-pSprite->ang)&2047)-1024;
213         int height = (pDudeInfo->eyeHeight*pSprite->yrepeat)<<2;
214         if (cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - height, pSprite->sectnum))
215         {
216             if (nDist < pDudeInfo->seeDist && klabs(nDeltaAngle) <= pDudeInfo->periphery)
217             {
218                 aiSetTarget(pXSprite, pXSprite->target);
219                 if (nDist < 0x333 && klabs(nDeltaAngle) < 85)
220                 {
221                     switch (pSprite->type)
222                     {
223                     case kDudeBurningCultist:
224                         aiNewState(pSprite, pXSprite, &cultistBurnAttack);
225                         break;
226                     case kDudeBurningZombieAxe:
227                         aiNewState(pSprite, pXSprite, &zombieABurnAttack);
228                         break;
229                     case kDudeBurningZombieButcher:
230                         aiNewState(pSprite, pXSprite, &zombieFBurnAttack);
231                         break;
232                     case kDudeBurningInnocent:
233                         aiNewState(pSprite, pXSprite, &innocentBurnAttack);
234                         break;
235                     case kDudeBurningBeast:
236                         aiNewState(pSprite, pXSprite, &beastBurnAttack);
237                         break;
238                     case kDudeBurningTinyCaleb:
239                         aiNewState(pSprite, pXSprite, &tinycalebBurnAttack);
240                         break;
241                     #ifdef NOONE_EXTENSIONS
242                     case kDudeModernCustomBurning:
243                         aiNewState(pSprite, pXSprite, &genDudeBurnSearch);
244                         break;
245                     #endif
246                     }
247                 }
248                 return;
249             }
250         }
251     }
252 
253     switch (pSprite->type)
254     {
255     case kDudeBurningCultist:
256         aiNewState(pSprite, pXSprite, &cultistBurnGoto);
257         break;
258     case kDudeBurningZombieAxe:
259         aiNewState(pSprite, pXSprite, &zombieABurnGoto);
260         break;
261     case 242:
262         aiNewState(pSprite, pXSprite, &zombieFBurnGoto);
263         break;
264     case kDudeBurningInnocent:
265         aiNewState(pSprite, pXSprite, &innocentBurnGoto);
266         break;
267     case kDudeBurningBeast:
268         aiNewState(pSprite, pXSprite, &beastBurnGoto);
269         break;
270     case kDudeBurningTinyCaleb:
271         aiNewState(pSprite, pXSprite, &tinycalebBurnGoto);
272         break;
273     #ifdef NOONE_EXTENSIONS
274     case kDudeModernCustomBurning:
275         aiNewState(pSprite, pXSprite, &genDudeBurnSearch);
276         break;
277     #endif
278     }
279     pXSprite->target = -1;
280 }
281