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