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