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 "../audio/audio.h"
23 #include "../collisions.h"
24 #include "../entity.h"
25 #include "../graphics/animation.h"
26 #include "../hud.h"
27 #include "../player.h"
28 #include "../system/error.h"
29 #include "../system/properties.h"
30
31 extern Entity *self, player;
32
33 static void entityWait(void);
34 static void touch(Entity *);
35 static void activate(int);
36 static void init(void);
37 static void addDoor(void);
38 static void doorWait(void);
39 static void doorClose(void);
40 static void doorOpen(void);
41
addSoulMerger(int x,int y,char * name)42 Entity *addSoulMerger(int x, int y, char *name)
43 {
44 Entity *e = getFreeEntity();
45
46 if (e == NULL)
47 {
48 showErrorAndExit("No free slots to add a Soul Merger");
49 }
50
51 loadProperties(name, e);
52
53 e->x = x;
54 e->y = y;
55
56 e->type = KEY_ITEM;
57
58 e->action = &init;
59 e->touch = &touch;
60 e->activate = &activate;
61
62 e->draw = &drawLoopingAnimationToMap;
63
64 setEntityAnimation(e, "STAND");
65
66 return e;
67 }
68
init()69 static void init()
70 {
71 addDoor();
72
73 setEntityAnimation(self, self->mental == 0 ? "STAND" : "WALK");
74
75 self->action = &entityWait;
76 }
77
entityWait()78 static void entityWait()
79 {
80 if (self->health == 3)
81 {
82 self->thinkTime--;
83
84 if (self->thinkTime <= 0)
85 {
86 self->thinkTime = 120;
87
88 setEntityAnimation(self, self->mental == 0 ? "STAND" : "WALK");
89
90 self->health = 4;
91 }
92 }
93
94 else if (self->health == 4)
95 {
96 self->thinkTime--;
97
98 if (self->thinkTime <= 0)
99 {
100 self->health = 5;
101 }
102 }
103
104 if (self->target != NULL)
105 {
106 self->target->flags |= INVULNERABLE;
107 }
108
109 checkToMap(self);
110 }
111
touch(Entity * other)112 static void touch(Entity *other)
113 {
114 if (self->health == 0 && self->active == TRUE)
115 {
116 setInfoBoxMessage(0, 255, 255, 255, _("Press Action to enter the Soul Merger"));
117 }
118 }
119
activate(int val)120 static void activate(int val)
121 {
122 Entity *other;
123
124 if (self->health == 0)
125 {
126 if (val == 0)
127 {
128 if (self->active == TRUE)
129 {
130 other = getEntityByObjectiveName(self->requires);
131
132 if (other == NULL)
133 {
134 showErrorAndExit("Soul Merger could not find target chamber %s", self->requires);
135 }
136
137 if (other->mental == self->mental)
138 {
139 setInfoBoxMessage(120, 255, 255, 255, _("An IN Chamber and an OUT Chamber are required"));
140 }
141
142 else
143 {
144 self->target = &player;
145
146 setPlayerLocked(TRUE);
147 }
148 }
149 }
150
151 else if (val == -1)
152 {
153 setEntityAnimation(self, self->mental == 0 ? "STAND" : "WALK");
154 }
155
156 else
157 {
158 self->target = getEntityByObjectiveName("EVIL_EDGAR_2");
159 }
160
161 if (self->target != NULL)
162 {
163 self->target->x = self->x + self->w / 2 - self->target->w / 2;
164
165 self->health = 1;
166 }
167 }
168 }
169
addDoor()170 static void addDoor()
171 {
172 Entity *e = getFreeEntity();
173
174 if (e == NULL)
175 {
176 showErrorAndExit("No free slots to add a Soul Merger Door");
177 }
178
179 loadProperties("item/soul_merger_door", e);
180
181 setEntityAnimation(e, "STAND");
182
183 e->x = self->x + self->w / 2 - e->w / 2 - e->w;
184 e->y = self->y + self->h - e->h;
185
186 e->startX = e->x;
187
188 e->endX = self->x + self->w / 2 - e->w / 2;
189
190 e->type = KEY_ITEM;
191
192 e->action = &doorWait;
193
194 e->draw = &drawLoopingAnimationToMap;
195
196 e->head = self;
197 }
198
doorWait()199 static void doorWait()
200 {
201 if (self->head->health == 1)
202 {
203 self->layer = FOREGROUND_LAYER;
204
205 self->action = &doorClose;
206 }
207
208 else if (self->head->health == 5)
209 {
210 self->layer = FOREGROUND_LAYER;
211
212 self->action = &doorOpen;
213 }
214
215 checkToMap(self);
216 }
217
doorClose()218 static void doorClose()
219 {
220 if (fabs(self->endX - self->x) <= fabs(self->dirX))
221 {
222 self->layer = BACKGROUND_LAYER;
223
224 self->x = self->endX;
225
226 self->dirX = 0;
227
228 self->head->health = 2;
229
230 self->action = &doorWait;
231
232 self->head->target->flags |= NO_DRAW;
233
234 playSoundToMap("sound/common/door", -1, self->x, self->y, 0);
235 }
236
237 else
238 {
239 self->dirX = self->endX < self->x ? -2 : 2;
240 }
241
242 checkToMap(self);
243 }
244
doorOpen()245 static void doorOpen()
246 {
247 if (fabs(self->startX - self->x) <= fabs(self->dirX))
248 {
249 self->x = self->startX;
250
251 self->dirX = 0;
252
253 self->head->health = 6;
254
255 if (self->target == &player)
256 {
257 setPlayerLocked(FALSE);
258 }
259
260 self->head->target = NULL;
261
262 self->action = &doorWait;
263
264 self->layer = BACKGROUND_LAYER;
265
266 playSoundToMap("sound/common/door", -1, self->x, self->y, 0);
267 }
268
269 else
270 {
271 self->dirX = self->startX < self->x ? -2 : 2;
272 }
273
274 checkToMap(self);
275 }
276