1 /*
2 Copyright (C) 2009-2021 Parallel Realities
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 */
19
20 #include "../headers.h"
21
22 #include "../enemy/enemies.h"
23 #include "../entity.h"
24 #include "../graphics/animation.h"
25 #include "../graphics/decoration.h"
26 #include "../item/item.h"
27 #include "../item/key_items.h"
28 #include "../player.h"
29 #include "../projectile.h"
30 #include "../system/error.h"
31 #include "../system/properties.h"
32 #include "../system/random.h"
33
34 extern Entity *self;
35
36 static void spawn(void);
37 static void init(void);
38
addSpawner(int x,int y,char * entityToSpawn)39 Entity *addSpawner(int x, int y, char *entityToSpawn)
40 {
41 Entity *e = getFreeEntity();
42
43 if (e == NULL)
44 {
45 showErrorAndExit("No free slots to add a Spawner");
46 }
47
48 loadProperties(entityToSpawn, e);
49
50 e->x = x;
51 e->y = y;
52
53 e->draw = &drawLoopingAnimationToMap;
54 e->touch = NULL;
55 e->action = &init;
56
57 e->type = SPAWNER;
58
59 setEntityAnimation(e, "STAND");
60
61 return e;
62 }
63
init()64 static void init()
65 {
66 Entity *e;
67 char spawnList[MAX_VALUE_LENGTH], name[MAX_VALUE_LENGTH];
68 char *token;
69
70 #if DEV == 1
71 if (strlen(self->objectiveName) == 0)
72 {
73 showErrorAndExit("Spawner at %f %f is not set correctly", self->x, self->y);
74 }
75 #endif
76
77 /* Precache the Entities to spawn */
78
79 e = getFreeEntity();
80
81 if (e == NULL)
82 {
83 showErrorAndExit("No free slots to add spawner entity");
84 }
85
86 STRNCPY(spawnList, self->objectiveName, MAX_VALUE_LENGTH);
87
88 token = strtok(spawnList, "|");
89
90 while (token != NULL)
91 {
92 if (strcmpignorecase(self->name, "common/spawner") == 0 && strstr(token, "/") == NULL)
93 {
94 SNPRINTF(name, sizeof(name), "enemy/%s", token);
95 }
96
97 else
98 {
99 SNPRINTF(name, sizeof(name), "%s", token);
100 }
101
102 loadProperties(name, e);
103
104 token = strtok(NULL, "|");
105 }
106
107 e->inUse = FALSE;
108
109 self->action = &spawn;
110
111 self->action();
112 }
113
spawn()114 static void spawn()
115 {
116 int distance;
117 char spawnList[MAX_VALUE_LENGTH], name[MAX_VALUE_LENGTH];
118 char *token;
119 int spawnIndex = 0, spawnCount = 0;
120 Entity *e;
121
122 if (self->active == TRUE)
123 {
124 self->thinkTime--;
125
126 if (self->thinkTime <= 0)
127 {
128 self->thinkTime = 0;
129
130 if (self->health < 0)
131 {
132 /* Don't spawn if the player is too close or too far away */
133
134 distance = self->health == -2 ? getDistanceFromPlayer(self) : 0;
135
136 if (self->health == -1 || self->health == -3 || (self->health == -2 && distance > SCREEN_WIDTH && distance < SCREEN_WIDTH + TILE_SIZE))
137 {
138 if (strcmpignorecase(self->name, "common/decoration_spawner") == 0)
139 {
140 e = addDecoration(self->objectiveName, self->x, self->y);
141
142 e->x += (self->w - e->w) / 2;
143 e->y += (self->h - e->h) / 2;
144 }
145
146 else if (strcmpignorecase(self->name, "common/projectile_spawner") == 0)
147 {
148 e = addProjectile(self->objectiveName, self, self->x, self->y, 0, 0);
149
150 e->x += (self->w - e->w) / 2;
151
152 if (e->flags & FLY)
153 {
154 e->dirX = (self->face == LEFT ? -e->speed : e->speed);
155
156 e->face = self->face;
157
158 e->y += (self->h - e->h) / 2;
159 }
160 }
161
162 else if (strcmpignorecase(self->name, "common/item_spawner") == 0)
163 {
164 e = addPermanentItem(self->objectiveName, self->x, self->y);
165
166 e->x += (self->w - e->w) / 2;
167
168 e->face = self->face;
169 }
170
171 else if (strcmpignorecase(self->name, "common/key_item_spawner") == 0)
172 {
173 e = addKeyItem(self->objectiveName, self->x, self->y);
174
175 e->x += (self->w - e->w) / 2;
176
177 e->face = self->face;
178 }
179
180 else
181 {
182 STRNCPY(spawnList, self->objectiveName, MAX_VALUE_LENGTH);
183
184 token = strtok(spawnList, "|");
185
186 while (token != NULL)
187 {
188 token = strtok(NULL, "|");
189
190 spawnCount++;
191 }
192
193 if (spawnCount == 0)
194 {
195 showErrorAndExit("Spawner at %f %f has no spawn list", self->x, self->y);
196 }
197
198 spawnIndex = prand() % spawnCount;
199
200 STRNCPY(spawnList, self->objectiveName, MAX_VALUE_LENGTH);
201
202 spawnCount = 0;
203
204 token = strtok(spawnList, "|");
205
206 while (token != NULL)
207 {
208 if (spawnCount == spawnIndex)
209 {
210 break;
211 }
212
213 token = strtok(NULL, "|");
214
215 spawnCount++;
216 }
217
218 if (strstr(token, "/") == NULL)
219 {
220 SNPRINTF(name, sizeof(name), "enemy/%s", token);
221 }
222
223 else
224 {
225 SNPRINTF(name, sizeof(name), "%s", token);
226 }
227
228 e = addEnemy(name, self->x, self->y);
229
230 e->x += (self->w - e->w) / 2;
231 e->y += (self->h - e->h) / 2;
232
233 e->startX = self->startX;
234 e->startY = self->startY;
235
236 e->endX = self->endX;
237 e->endY = self->endY;
238
239 e->face = self->face;
240
241 if (self->health == -2)
242 {
243 e->flags |= SPAWNED_IN;
244
245 e->spawnTime = SPAWNED_IN_TIME;
246 }
247 }
248
249 if (self->speed != 0)
250 {
251 e->speed = self->speed;
252 }
253
254 self->thinkTime = self->maxThinkTime;
255
256 if (self->health == -3)
257 {
258 self->active = FALSE;
259 }
260 }
261 }
262
263 else
264 {
265 STRNCPY(spawnList, self->objectiveName, MAX_VALUE_LENGTH);
266
267 token = strtok(spawnList, "|");
268
269 while (token != NULL)
270 {
271 token = strtok(NULL, "|");
272
273 spawnCount++;
274 }
275
276 if (spawnCount == 0)
277 {
278 showErrorAndExit("Spawner at %f %f has no spawn list", self->x, self->y);
279 }
280
281 spawnIndex = prand() % spawnCount;
282
283 STRNCPY(spawnList, self->objectiveName, MAX_VALUE_LENGTH);
284
285 spawnCount = 0;
286
287 token = strtok(spawnList, "|");
288
289 while (token != NULL)
290 {
291 if (spawnCount == spawnIndex)
292 {
293 break;
294 }
295
296 token = strtok(NULL, "|");
297
298 spawnCount++;
299 }
300
301 if (strstr(token, "/") == NULL)
302 {
303 SNPRINTF(name, sizeof(name), "enemy/%s", token);
304 }
305
306 else
307 {
308 SNPRINTF(name, sizeof(name), "%s", token);
309 }
310
311 e = addEnemy(name, self->x, self->y);
312
313 e->x += (self->w - e->w) / 2;
314 e->y += (self->h - e->h) / 2;
315
316 e->startX = self->startX;
317 e->startY = self->startY;
318
319 e->endX = self->endX;
320 e->endY = self->endY;
321
322 e->face = self->face;
323
324 if (self->speed != 0)
325 {
326 e->speed = self->speed;
327 }
328
329 self->health--;
330
331 if (self->health == 0)
332 {
333 self->inUse = FALSE;
334 }
335
336 self->thinkTime = self->maxThinkTime;
337 }
338 }
339 }
340 }
341