1 /*
2  * Holotz's Castle
3  * Copyright (C) 2004 Juan Carlos Seijo P�rez
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the Free
7  * Software Foundation; either version 2 of the License, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc., 59
17  * Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  *
19  * Juan Carlos Seijo P�rez
20  * jacob@mainreactor.net
21  */
22 
23 /** Exit gadget for Holtz's castle game.
24  * @file    HCExit.cpp
25  * @author  Juan Carlos Seijo P�rez
26  * @date    17/08/2004
27  * @version 0.0.1 - 17/08/2004 - First version.
28  */
29 
30 #include <HCExit.h>
31 
HCExit()32 HCExit::HCExit() : map(0), state(HCEXITSTATE_LOCKED), x1(0), y1(0),
33                    sparks(0), numSparks(0), character(0), imgCharacter(0)
34 {
35 }
36 
Init(HCMap * _map,s32 nSparks,s32 w)37 bool HCExit::Init(HCMap *_map, s32 nSparks, s32 w)
38 {
39 	if (!_map)
40 		return false;
41 
42 	map = _map;
43 
44 	if (nSparks <= 0)
45 	{
46 		nSparks = 1;
47 	}
48 
49 	Destroy();
50 	numSparks = nSparks;
51 	sparks = new HCExitSpark[numSparks];
52 
53 	// Hangs from the ceiling of the cell
54 	pos.x = map->ToX(map->ExitCol()) - (map->CellWidth()/2);
55 	pos.y = map->ToY(map->ExitRow()) - (map->CellHeight() - 1);
56 
57 	float x0 = pos.x, y0 = pos.y;
58 	x1 = x0 + (w == 0 ? map->CellWidth() : w);
59 
60 	// Computes the height of the exit box
61 	s32 i, j;
62 	bool end = false;
63 	for (j = map->ExitRow() + 1, i = map->ExitCol(); !end && j < map->Rows(); ++j)
64 	{
65 		if (map->Cell(j, i)->Type() != HCCELLTYPE_BLANK)
66 		{
67 			end = true;
68 		}
69 	}
70 
71 	y1 = map->ToY((j > 0 ? j - 2: 1));
72 
73 	// Randomly initializes the sparks into the exit box
74 	srand(time(0));
75 
76 	for (s32 k = 0; k < numSparks; ++k)
77 	{
78 		sparks[k].c.r = 255;//128 + (rand()%127);
79 		sparks[k].c.g = 255;//128 + (rand()%127);
80 		sparks[k].c.b = 255;//128 + (rand()%127);
81 		sparks[k].y = y0;
82 		sparks[k].vy = -(1.7 + (float(rand()%50)/50.0f));
83 		sparks[k].c.g = sparks[k].c.r = 0;
84 		sparks[k].x = x0 + (rand()%s32(x1 - x0));
85 		sparks[k].y = y0 + (rand()%s32(y1 - y0));
86 		sparks[k].vy = -(0.1 + (float(rand()%50)/500.0f));
87 		sparks[k].vx = -sparks[k].vy * (((x1 - x0)/2) - (sparks[k].x - x0))/(y1 - y0);
88 		sparks[k].dc = 255 - (u8)(255.0f * (float(y1 - sparks[k].y)/(y1 - y0)));
89 	}
90 
91 	// Sets the timer to 25 FPS
92 	timer.Start(1000/25);
93 
94 	// By default, the exit is locked
95 	Lock();
96 
97   return true;
98 }
99 
Draw()100 void HCExit::Draw()
101 {
102 	switch (state)
103 	{
104 	default:
105 	case HCEXITSTATE_LOCKED:
106 		{
107 			JImage img(SDL_GetVideoSurface());
108 			if (0 == img.Lock())
109 			{
110 				for (s32 k = 0; k < numSparks; ++k)
111 				{
112 					if (sparks[k].x > 0 && sparks[k].x < JApp::App()->Width() &&
113 							sparks[k].y > 0 && sparks[k].y < JApp::App()->Height())
114 					{
115 						img.PutPixel((s32)sparks[k].x, (s32)sparks[k].y,
116                          SDL_MapRGB(img.Format(),
117 																		sparks[k].c.r,
118 																		sparks[k].c.g,
119 																		sparks[k].c.b));
120 					}
121 				}
122 
123 				img.Unlock();
124 			}
125 		}
126 		break;
127 
128 	case HCEXITSTATE_SWALLOWING:
129 	case HCEXITSTATE_UNLOCKED:
130 		{
131 			JImage img(SDL_GetVideoSurface());
132 
133 			if (0 == img.Lock())
134 			{
135 				for (s32 k = 0; k < numSparks; ++k)
136 				{
137 					if (sparks[k].x > 0 && sparks[k].x < JApp::App()->Width() &&
138 							sparks[k].y > 0 && sparks[k].y < JApp::App()->Height() - 3)
139 					{
140 						for (s32 i = 0; i < 3; ++i)
141 						{
142 							img.PutPixel((s32)sparks[k].x, (s32)sparks[k].y + i,
143                            SDL_MapRGB(img.Format(),
144 																			(sparks[k].c.r/(i+1)),
145 																			(sparks[k].c.g/(i+1)),
146 																			(sparks[k].c.b)));
147 						}
148 					}
149 				}
150 
151 				img.Unlock();
152 			}
153 		}
154 		break;
155 	}
156 }
157 
Update()158 s32 HCExit::Update()
159 {
160 	if (!timer.Changed())
161 		return 0;
162 
163 	float x0 = pos.x, y0 = pos.y;
164 
165 	switch (state)
166 	{
167 	default:
168 	case HCEXITSTATE_LOCKED:
169 		for (s32 k = 0; k < numSparks; ++k)
170 		{
171 			if (sparks[k].y < pos.y)
172 			{
173 				sparks[k].vy = -(1.7 + (float(rand()%50)/50.0f));
174 				sparks[k].c.g = sparks[k].c.r = 0;
175 				sparks[k].x = x0 + (rand()%s32(x1 - x0));
176 				sparks[k].y = y0 + (rand()%s32(y1 - y0));
177 				sparks[k].vy = -(0.1 + (float(rand()%50)/500.0f));
178 				sparks[k].vx = -sparks[k].vy * (((x1 - x0)/2) - (sparks[k].x - x0))/(y1 - y0);
179 				sparks[k].dc = 255 - (u8)(255.0f * (float(y1 - sparks[k].y)/(y1 - y0)));
180 			}
181 			sparks[k].c.r += sparks[k].dc;
182 			sparks[k].c.g += sparks[k].dc;
183 			sparks[k].x += sparks[k].vx;
184 			sparks[k].y += sparks[k].vy;
185 		}
186 		break;
187 
188 	case HCEXITSTATE_UNLOCKED:
189 		for (s32 k = 0; k < numSparks; ++k)
190 		{
191 			if (sparks[k].y <= y0)
192 			{
193 				sparks[k].c.g = sparks[k].c.r = 0;
194 				sparks[k].x = x0 + (rand()%s32(x1 - x0));
195 				sparks[k].y = y0 + (rand()%s32(y1 - y0));
196 				sparks[k].vy = -(4.7 + (float(rand()%10)/5.0f));
197 				sparks[k].vx = -sparks[k].vy * 0.1f * (((x1 - x0)/2) - (sparks[k].x - x0))/(x1 - x0);
198 				sparks[k].vx = -sparks[k].vy * (((x1 - x0)/2) - (sparks[k].x - x0))/(y1 - y0);
199 				sparks[k].dc = 255 - (u8)(255.0f * (float(y1 - sparks[k].y)/(y1 - y0)));
200 			}
201 			sparks[k].c.g += sparks[k].dc;
202 			sparks[k].c.r += sparks[k].dc;
203 			sparks[k].x += sparks[k].vx;
204 			sparks[k].y += sparks[k].vy;
205 		}
206 		break;
207 
208 	case HCEXITSTATE_SWALLOWING:
209 		for (s32 k = 0; k < numSparks; ++k)
210 		{
211 			if (sparks[k].y <= y0)
212 			{
213 				// Faster, from top to the character's feet
214 				sparks[k].c.g = sparks[k].c.r = 0;
215 				sparks[k].x = x0 + (rand()%s32(x1 - x0));
216 				sparks[k].y = character->Y();//y0 + (rand()%s32(character->Y() - y0 + 5));
217 				sparks[k].vy = -(6.7 + (float(rand()%10)/2.0f));
218 				sparks[k].vx = -sparks[k].vy * 0.1f * (((x1 - x0)/2) - (sparks[k].x - x0))/(x1 - x0);
219 				sparks[k].vx = -sparks[k].vy * (((x1 - x0)/2) - (sparks[k].x - x0))/(y1 - y0);
220 				sparks[k].dc = 255 - (u8)(255.0f * (float(y1 - sparks[k].y)/(y1 - y0)));
221 			}
222 			sparks[k].c.g += sparks[k].dc;
223 			sparks[k].c.r += sparks[k].dc;
224 			sparks[k].x += sparks[k].vx;
225 			sparks[k].y += sparks[k].vy;
226 		}
227 
228 		if (character->Y() <= (y0 + map->CellHeight()))
229 		{
230 			// Done swallowing
231 			state = HCEXITSTATE_SWALLOWED;
232 		}
233 		else
234 		{
235 			character->Pos(character->X(), character->Y() + character->Veloccity().y);
236 		}
237 		break;
238 
239 	case HCEXITSTATE_SWALLOWED:
240 		break;
241 	}
242 
243 	return 1;
244 }
245 
Unlock()246 void HCExit::Unlock()
247 {
248 	// Suddenly accelerates the sparks
249 	state = HCEXITSTATE_UNLOCKED;
250 	for (s32 k = 0; k < numSparks; ++k)
251 	{
252 		sparks[k].vy = -(1.7 + (float(rand()%10)/5.0f));
253 	}
254 }
255 
Swallow(HCCharacter * ch)256 void HCExit::Swallow(HCCharacter *ch)
257 {
258 	state = HCEXITSTATE_SWALLOWING;
259 	character = ch;
260 	character->State(HCCS_STOP);
261 	character->Veloccity().y = -5.0f;
262 
263 	// Calculates the veloccity to end in the midpoint of the ceiling
264 	character->Veloccity().x = character->Veloccity().y * (((character->X() - pos.x) - (x1 - pos.x)/2))/(y1 - pos.y);
265 }
266 
Pos(float xPos,float yPos)267 void HCExit::Pos(float xPos, float yPos)
268 {
269 	float dx = xPos - pos.x, dy = yPos - pos.y;
270 	pos.x = xPos;
271 	pos.y = yPos;
272 	x1 += dx;
273 	y1 += dy;
274 
275 	for (s32 k = 0; k < numSparks; ++k)
276 	{
277 		sparks[k].x += dx;
278 		sparks[k].y += dy;
279 	}
280 }
281 
Destroy()282 void HCExit::Destroy()
283 {
284 	JDELETE_ARRAY(sparks);
285 	JDELETE(imgCharacter);
286 }
287 
~HCExit()288 HCExit::~HCExit()
289 {
290 	Destroy();
291 }
292